/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * The contents of this file are subject to the Netscape Public License * Version 1.0 (the "NPL"); you may not use this file except in * compliance with the NPL. You may obtain a copy of the NPL at * http://www.mozilla.org/NPL/ * * Software distributed under the NPL is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL * for the specific language governing rights and limitations under the * NPL. * * The Initial Developer of this code under the NPL is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All Rights * Reserved. */ #include "stdafx.h" #include "cxdc.h" #include "cntritem.h" #include "intlwin.h" #include "mainfrm.h" #include "npapi.h" #include "np.h" #include "feembed.h" #include "fmabstra.h" #include "custom.h" #include "prefapi.h" #include "feimage.h" #include "il_icons.h" #include "prefinfo.h" // Make an array of RGB colors that match the current palette. // This array is used for contexts that don't employ DibPalColors. // Returns TRUE on success, FALSE otherwise. static const RGBQUAD rgbqWhite = {0xFF, 0xFF, 0xFF, 0}; static const RGBQUAD rgbqBlack = {0, 0, 0, 0}; //#define USE_IDENTITY_PALETTE #ifdef XP_WIN32 //#define USE_DIB_SECTION #endif #ifdef USE_IDENTITY_PALETTE # define PALETTEENTRY_FLAGS PC_NOCOLLAPSE #else # define PALETTEENTRY_FLAGS 0 #endif extern "C"{ extern int gifAbort; } #define ROP_PSDPxax 0x00B8074AL // Alters the transparent part of the source image (already selected into // pSrcDC) with the specified brush // // Make sure that the WHOLE image is changed and not just the part that // needs to be displayed; otherwise things will get out of sync static BOOL CopyPaletteToRGBArray(HPALETTE pPal, RGBQUAD *pRGBArray) { PALETTEENTRY *paletteEntries; XP_ASSERT(pRGBArray); paletteEntries = (PALETTEENTRY *)XP_ALLOC(sizeof(PALETTEENTRY) * 256); if (!paletteEntries) return FALSE; // Copy existing palette VERIFY(::GetPaletteEntries(pPal, 0, 256, paletteEntries) > 0); for(int i = 0; i < 256; i++) { pRGBArray[i].rgbRed = paletteEntries[i].peRed; pRGBArray[i].rgbGreen = paletteEntries[i].peGreen; pRGBArray[i].rgbBlue = paletteEntries[i].peBlue; pRGBArray[i].rgbReserved = NULL; } XP_FREE(paletteEntries); return TRUE; } void CDCCX::ImageComplete(NI_Pixmap* image) { FEBitmapInfo *imageInfo; HDC hdc = GetContextDC(); if (!image || !hdc || IsPrintContext()) return; imageInfo = (FEBitmapInfo*) image->client_data; if(!imageInfo) return; #ifndef USE_DIB_SECTION if(!imageInfo->hBitmap) { // Attempt to create a bitmap if (!imageInfo->IsMask ) { imageInfo->hBitmap = ::CreateDIBitmap(hdc, &(imageInfo->bmpInfo->bmiHeader), CBM_INIT, image->bits, imageInfo->bmpInfo, m_bUseDibPalColors ? DIB_PAL_COLORS : DIB_RGB_COLORS); if (imageInfo->hBitmap) { // Free the image bits since we no longer need them CDCCX::HugeFree(image->bits); image->bits = NULL; } } else { // If there is a mask then create another bitmap // Build a BITMAPINFO struct for mask char cMask[sizeof(BITMAPINFOHEADER) + (2 * sizeof(RGBQUAD))]; LPBITMAPINFO pBmInfoMask = (LPBITMAPINFO)cMask; memcpy(pBmInfoMask, imageInfo->bmpInfo, sizeof(BITMAPINFOHEADER)); pBmInfoMask->bmiHeader.biBitCount = 1; pBmInfoMask->bmiHeader.biCompression = BI_RGB; // must NOT be BI_BITFIELDS // Build a color table for monochrome mask. Image lib sets the foreground // pixels to 1 and the background pixels to 0. We want the monochrome // mask to be the same way pBmInfoMask->bmiColors[1] = rgbqBlack; // background pixels pBmInfoMask->bmiColors[0] = rgbqWhite; // foreground pixels // Create the mask. It's important that we use the memory DC, because we // want a momochrome bitmap imageInfo->hBitmap = ::CreateDIBitmap(m_pImageDC, (LPBITMAPINFOHEADER)pBmInfoMask, CBM_INIT, image->bits, pBmInfoMask, DIB_RGB_COLORS); if (imageInfo->hBitmap) { // Free the mask bits since we no longer need them CDCCX::HugeFree(image->bits); image->bits = NULL; } } } #else HBITMAP oldBmp; oldBmp = imageInfo->hBitmap; if (!imageInfo->IsMask ) { imageInfo->hBitmap = ::CreateDIBitmap(hdc, &(imageInfo->bmpInfo->bmiHeader), CBM_INIT, image->bits, imageInfo->bmpInfo, m_bUseDibPalColors ? DIB_PAL_COLORS : DIB_RGB_COLORS); } else { // If there is a mask then create another bitmap // Build a BITMAPINFO struct for mask char cMask[sizeof(BITMAPINFOHEADER) + (2 * sizeof(RGBQUAD))]; LPBITMAPINFO pBmInfoMask = (LPBITMAPINFO)cMask; memcpy(pBmInfoMask, imageInfo->bmpInfo, sizeof(BITMAPINFOHEADER)); pBmInfoMask->bmiHeader.biBitCount = 1; pBmInfoMask->bmiHeader.biCompression = BI_RGB; // must NOT be BI_BITFIELDS // Build a color table for monochrome mask. Image lib sets the foreground // pixels to 1 and the background pixels to 0. We want the monochrome // mask to be the same way pBmInfoMask->bmiColors[1] = rgbqBlack; // background pixels pBmInfoMask->bmiColors[0] = rgbqWhite; // foreground pixels // Create the mask. It's important that we use the memory DC, because we // want a momochrome bitmap imageInfo->hBitmap = ::CreateDIBitmap(m_pImageDC, (LPBITMAPINFOHEADER)pBmInfoMask, CBM_INIT, image->bits, pBmInfoMask, DIB_RGB_COLORS); } ::DeleteObject(oldBmp); image->bits = NULL; #endif ReleaseContextDC(hdc); } static WORD GetBitCount(BITMAP &bmp) { WORD nBits = (WORD)(bmp.bmPlanes * bmp.bmBitsPixel); #ifdef XP_WIN32 if (nBits == 1) nBits = 1; else if (nBits <= 4) nBits = 4; else if (nBits <= 8) nBits = 8; else if (nBits <= 16) nBits = 16; else if (nBits <= 24) nBits = 24; else nBits = 32; #else if (nBits == 1) nBits = 1; else if (nBits <= 4) nBits = 4; else if (nBits <= 8) nBits = 8; else nBits = 24; #endif return nBits; } #ifndef XP_WIN32 /* Quaternary raster codes */ #define MAKEROP4(fore,back) (DWORD)((((back) << 8) & 0xFF000000) | (fore)) #endif BOOL CDCCX::CanWriteBitmapFile(LO_ImageStruct* pLOImage) { ASSERT(pLOImage); if(!pLOImage) { return(FALSE); } IL_Pixmap *pImage = IL_GetImagePixmap(pLOImage->image_req); // Internal icons have no platform data. FEBitmapInfo* imageinfo = (FEBitmapInfo*) pImage->client_data; // We can't do anything if we don't have all the image bits return imageinfo && imageinfo->hBitmap; } HANDLE CDCCX::WriteBitmapToMemory( IL_ImageReq *image_req, LO_Color* bg) { IL_Pixmap *pImage = IL_GetImagePixmap(image_req); IL_Pixmap *pMask = IL_GetMaskPixmap(image_req); // Windows bitmap file format looks like this: // // +------------------+ // | BITMAPFILEHEADER | // |------------------| // | BITMAPINFOHEADER | // |------------------| // | color table | // |------------------| // | image bits | // +------------------+ FEBitmapInfo* imageinfo = (FEBitmapInfo*) pImage->client_data; FEBitmapInfo* maskinfo = 0; if (pMask) maskinfo = (FEBitmapInfo*) pMask->client_data; // We can't do anything if we don't have all the image bits HGLOBAL hDib; if (imageinfo && imageinfo->hBitmap) { BITMAP bmp; LPBITMAPINFOHEADER lpBmi; WORD nBitCount; LPBYTE lpBits; int nColorTable; // Determine the bits per pixel if (!::GetObject(imageinfo->hBitmap, sizeof(bmp), &bmp)) return FALSE; nBitCount = GetBitCount(bmp); // We need to know how big the color table is. For 16-bit mode and 32-bit mode, we need to // allocate room for 3 double-word color masks if (nBitCount == 16 || nBitCount == 32) nColorTable = 3; else if (nBitCount < 16) nColorTable = 1 << nBitCount; else { ASSERT(nBitCount == 24); nColorTable = 0; } // Allocate space for a BITMAPINFO structure (BITMAPINFOHEADER structure // plus space for the color table) WORD dwSize = sizeof(BITMAPINFOHEADER) + nColorTable * sizeof(RGBQUAD); hDib = GlobalAlloc(GMEM_SHARE, dwSize); lpBmi = (LPBITMAPINFOHEADER)GlobalLock(hDib); if (!lpBmi) return FALSE; // Initialize the BITMAPINFOHEADER structure lpBmi->biSize = sizeof(BITMAPINFOHEADER); lpBmi->biWidth = bmp.bmWidth; lpBmi->biHeight = bmp.bmHeight; lpBmi->biPlanes = 1; lpBmi->biBitCount = nBitCount; HDC hdc = GetContextDC(); // Note: NT 16-bit video mode won't work unless you use BI_BITFIELDS, and // Win 95 probably won't work if you use BI_BITFIELDS. Win 3.x doesn't even // support 16-bit DIBs, so it isn't an issue there #ifdef XP_WIN32 if (sysInfo.m_bWinNT && (nBitCount == 16 || nBitCount == 32)) lpBmi->biCompression = BI_BITFIELDS; else lpBmi->biCompression = BI_RGB; #else lpBmi->biCompression = BI_RGB; #endif // Ask the driver to tell us the number of bits we need to allocate ::GetDIBits(hdc, imageinfo->hBitmap, 0, (int)lpBmi->biHeight, NULL, (LPBITMAPINFO)lpBmi, DIB_RGB_COLORS); if (lpBmi->biSizeImage == 0) { // The driver didn't tell us so we need to compute it ourselves lpBmi->biSizeImage = ((((lpBmi->biWidth * nBitCount) + 31) & ~31) >> 3) * lpBmi->biHeight; } GlobalUnlock(hDib); hDib = GlobalReAlloc(hDib, lpBmi->biSizeImage + dwSize,0); // Allocate space for the bits lpBits = (LPBYTE)GlobalLock(hDib); if (!lpBits) { free(lpBmi); ReleaseContextDC(hdc); return FALSE; } // Windows bitmap files don't allow for a mask. Therefore we have to set the transparent // parts of the image to be the appropriate color. This ensures that the bitmap file matches // what the user sees on the screen // // ZZZ: This code should be shared with the code in _StretchBlt() COLORREF bgColor = bg ? RGB(bg->red, bg->green, bg->blue) : m_rgbBackgroundColor; if (maskinfo && maskinfo->hBitmap) { HBRUSH hBrush; HDC tempDC = ::CreateCompatibleDC(hdc); HBITMAP tempBmp = ::CreateCompatibleBitmap(hdc, lpBmi->biWidth, lpBmi->biHeight); HBITMAP hOldBmp = (HBITMAP)::SelectObject(tempDC, tempBmp); HBITMAP hOldBmp1 = (HBITMAP)::SelectObject(m_pImageDC, imageinfo->hBitmap); if (m_iBitsPerPixel == 16) // We don't want a dithered brush hBrush = ::CreateSolidBrush(::GetNearestColor(hdc, bgColor)); else hBrush = ::CreateSolidBrush(0x02000000L | bgColor); ::BitBlt(tempDC, 0, 0,lpBmi->biWidth, lpBmi->biHeight, m_pImageDC, 0, 0, SRCCOPY); // Select the mask into the memory DC ::SelectObject(m_pImageDC, maskinfo->hBitmap); // Change the transparent bits of the source bitmap to the desired background // color by doing an AND raster op // // The mask is monochrome and will be converted to color to match the depth of // the destination. The foreground pixels in the mask are set to 1, and the // background pixels to 0. When converting to a color bitmap, white pixels (1) // are set to the background color of the DC, and black pixels (0) are set to // the text color of the DC // // Select the brush HBRUSH hOldBrush = (HBRUSH)::SelectObject(tempDC, hBrush); // Draw the brush where the mask is 0 ::BitBlt(tempDC, 0, 0, lpBmi->biWidth, lpBmi->biHeight, m_pImageDC, 0, 0, MAKEROP4(SRCPAINT, R2_COPYPEN)); ::SelectObject(tempDC, hOldBrush); ::DeleteObject(hBrush); ::GetDIBits(tempDC, tempBmp, 0, (int)lpBmi->biHeight, lpBits + dwSize, (LPBITMAPINFO)lpBmi, DIB_RGB_COLORS); ::SelectObject(m_pImageDC, hOldBmp1); ::SelectObject(tempDC, hOldBmp); ::DeleteObject(tempBmp); ::DeleteDC(tempDC); } else // This time have the driver give us the color table and the bits ::GetDIBits(hdc, imageinfo->hBitmap, 0, (int)lpBmi->biHeight, lpBits + dwSize, (LPBITMAPINFO)lpBmi, DIB_RGB_COLORS); ReleaseContextDC(hdc); GlobalUnlock(hDib); return (hDib); } return (0); } BOOL CDCCX::WriteBitmapFile(LPCSTR lpszFileName, LO_ImageStruct* pLOImage) { ASSERT(pLOImage); if(!pLOImage) { return(FALSE); } IL_Pixmap *pImage = IL_GetImagePixmap(pLOImage->image_req); IL_Pixmap *pMask = IL_GetMaskPixmap(pLOImage->image_req); // Windows bitmap file format looks like this: // // +------------------+ // | BITMAPFILEHEADER | // |------------------| // | BITMAPINFOHEADER | // |------------------| // | color table | // |------------------| // | image bits | // +------------------+ FEBitmapInfo* imageinfo = (FEBitmapInfo*) pImage->client_data; FEBitmapInfo* maskinfo = 0; if (pMask) maskinfo = (FEBitmapInfo*) pMask->client_data; // We can't do anything if we don't have all the image bits if (imageinfo && imageinfo->hBitmap) { BITMAP bmp; LPBITMAPINFOHEADER lpBmi; WORD nBitCount; LPBYTE lpBits; int nColorTable; // Determine the bits per pixel if (!::GetObject(imageinfo->hBitmap, sizeof(bmp), &bmp)) return FALSE; nBitCount = GetBitCount(bmp); // We need to know how big the color table is. For 16-bit mode and 32-bit mode, we need to // allocate room for 3 double-word color masks if (nBitCount == 16 || nBitCount == 32) nColorTable = 3; else if (nBitCount < 16) nColorTable = 1 << nBitCount; else { ASSERT(nBitCount == 24); nColorTable = 0; } // Allocate space for a BITMAPINFO structure (BITMAPINFOHEADER structure // plus space for the color table) lpBmi = (LPBITMAPINFOHEADER)calloc(sizeof(BITMAPINFOHEADER) + nColorTable * sizeof(RGBQUAD), 1); if (!lpBmi) return FALSE; // Initialize the BITMAPINFOHEADER structure lpBmi->biSize = sizeof(BITMAPINFOHEADER); lpBmi->biWidth = bmp.bmWidth; lpBmi->biHeight = bmp.bmHeight; lpBmi->biPlanes = 1; lpBmi->biBitCount = nBitCount; HDC hdc = GetContextDC(); // Note: NT 16-bit video mode won't work unless you use BI_BITFIELDS, and // Win 95 probably won't work if you use BI_BITFIELDS. Win 3.x doesn't even // support 16-bit DIBs, so it isn't an issue there #ifdef XP_WIN32 if (sysInfo.m_bWinNT && (nBitCount == 16 || nBitCount == 32)) lpBmi->biCompression = BI_BITFIELDS; else lpBmi->biCompression = BI_RGB; #else lpBmi->biCompression = BI_RGB; #endif // Ask the driver to tell us the number of bits we need to allocate ::GetDIBits(hdc, imageinfo->hBitmap, 0, (int)lpBmi->biHeight, NULL, (LPBITMAPINFO)lpBmi, DIB_RGB_COLORS); if (lpBmi->biSizeImage == 0) { // The driver didn't tell us so we need to compute it ourselves lpBmi->biSizeImage = ((((lpBmi->biWidth * nBitCount) + 31) & ~31) >> 3) * lpBmi->biHeight; } // Allocate space for the bits lpBits = (LPBYTE)HugeAlloc(lpBmi->biSizeImage, 1); if (!lpBits) { free(lpBmi); ReleaseContextDC(hdc); return FALSE; } // Windows bitmap files don't allow for a mask. Therefore we have to set the transparent // parts of the image to be the appropriate color. This ensures that the bitmap file matches // what the user sees on the screen // // ZZZ: This code should be shared with the code in _StretchBlt() LO_Color* bg = (pLOImage->text_attr && !pLOImage->text_attr->no_background) ? &pLOImage->text_attr->bg : NULL; COLORREF bgColor = bg ? RGB(bg->red, bg->green, bg->blue) : m_rgbBackgroundColor; if (maskinfo && maskinfo->hBitmap) { HBRUSH hBrush; HDC tempDC = ::CreateCompatibleDC(hdc); HBITMAP tempBmp = ::CreateCompatibleBitmap(hdc, lpBmi->biWidth, lpBmi->biHeight); HBITMAP hOldBmp = (HBITMAP)::SelectObject(tempDC, tempBmp); HBITMAP hOldBmp1 = (HBITMAP)::SelectObject(m_pImageDC, imageinfo->hBitmap); if (m_iBitsPerPixel == 16) // We don't want a dithered brush hBrush = ::CreateSolidBrush(::GetNearestColor(hdc, bgColor)); else hBrush = ::CreateSolidBrush(0x02000000L | bgColor); ::BitBlt(tempDC, 0, 0,lpBmi->biWidth, lpBmi->biHeight, m_pImageDC, 0, 0, SRCCOPY); // Select the mask into the memory DC ::SelectObject(m_pImageDC, maskinfo->hBitmap); // Change the transparent bits of the source bitmap to the desired background // color by doing an AND raster op // // The mask is monochrome and will be converted to color to match the depth of // the destination. The foreground pixels in the mask are set to 1, and the // background pixels to 0. When converting to a color bitmap, white pixels (1) // are set to the background color of the DC, and black pixels (0) are set to // the text color of the DC // // Select the brush HBRUSH hOldBrush = (HBRUSH)::SelectObject(tempDC, hBrush); // Draw the brush where the mask is 0 ::BitBlt(tempDC, 0, 0, lpBmi->biWidth, lpBmi->biHeight, m_pImageDC, 0, 0, MAKEROP4(SRCPAINT, R2_COPYPEN)); ::SelectObject(tempDC, hOldBrush); ::DeleteObject(hBrush); ::GetDIBits(tempDC, tempBmp, 0, (int)lpBmi->biHeight, lpBits, (LPBITMAPINFO)lpBmi, DIB_RGB_COLORS); ::SelectObject(m_pImageDC, hOldBmp1); ::SelectObject(tempDC, hOldBmp); ::DeleteObject(tempBmp); ::DeleteDC(tempDC); } else // This time have the driver give us the color table and the bits ::GetDIBits(hdc, imageinfo->hBitmap, 0, (int)lpBmi->biHeight, lpBits, (LPBITMAPINFO)lpBmi, DIB_RGB_COLORS); ReleaseContextDC(hdc); BITMAPFILEHEADER bf; // Initialize the BITMAPFILEHEADER struct bf.bfType = 0x4D42; // 'BM' bf.bfReserved1 = 0; bf.bfReserved2 = 0; // Compute the offset to the bits. The bits are after the color table bf.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + nColorTable * sizeof(RGBQUAD); // Compute the size of the file bf.bfSize = bf.bfOffBits + lpBmi->biSizeImage; // Open the file and start writing CStdioFile file; TRY { #ifndef XP_WIN32 file.Open(lpszFileName, CFile::modeWrite | CFile::modeCreate | CFile::typeBinary); #else file.Open(lpszFileName, CFile::modeWrite | CFile::modeCreate | CFile::typeBinary | CFile::shareExclusive); #endif // Write the BITMAPFILEHEADER structure file.Write(&bf, sizeof(bf)); // Write the BITMAPINFOHEADER and color table file.Write(lpBmi, sizeof(BITMAPINFOHEADER) + nColorTable * sizeof(RGBQUAD)); // Write the bits #ifdef XP_WIN32 file.Write(lpBits, lpBmi->biSizeImage); #else file.WriteHuge(lpBits, lpBmi->biSizeImage); #endif file.Close(); } CATCH(CFileException, e) { CDCCX::HugeFree(lpBits); free(lpBmi); return FALSE; } END_CATCH // Free up everything and return success CDCCX::HugeFree(lpBits); free(lpBmi); return TRUE; } return FALSE; } void CDCCX::LayoutNewDocument(MWContext *pContext, URL_Struct *pURL, int32 *pWidth, int32 *pHeight, int32 *pmWidth, int32 *pmHeight) { // Set up the width, height, and margins as defualt values here. // These should have been set up in the Initialize() member of a derived // class. if (pContext->grid_children) { XP_ListDestroy (pContext->grid_children); pContext->grid_children = 0; } *pWidth = m_lWidth; *pHeight = m_lHeight; // No known margins, up to dervied classes to correctly set. // Don't set the margins if non-zero, Layout has it's own ideas about this. // Set ourselves to be at the top of the document. m_lOrgX = 0; m_lOrgY = 0; // Document has no substance. m_lDocWidth = 0; m_lDocHeight = 0; // Flush the background color. COLORREF rgbColor = prefInfo.m_rgbBackgroundColor; FE_SetBackgroundColor(pContext, GetRValue(rgbColor), GetGValue(rgbColor), GetBValue(rgbColor)); // We're loading a new page, so flush the previous page's // fonts so that we don't keep building a huge font cache. ClearFontCache(); } #define LIGHT_GRAY RGB(192, 192, 192) #define DARK_GRAY RGB(128, 128, 128) #define WHITE RGB(255, 255, 255) #define BLACK RGB(0, 0, 0) static void GetSystem3DColors(COLORREF rgbBackground, COLORREF& rgbLightColor, COLORREF& rgbDarkColor) { #ifdef XP_WIN32 if (sysInfo.IsWin4_32()) { // These are Windows 95 only rgbLightColor = ::GetSysColor(COLOR_3DLIGHT); rgbDarkColor = ::GetSysColor(COLOR_3DSHADOW); } else { rgbLightColor = LIGHT_GRAY; rgbDarkColor = ::GetSysColor(COLOR_BTNSHADOW); } #else rgbLightColor = LIGHT_GRAY; rgbDarkColor = ::GetSysColor(COLOR_BTNSHADOW); #endif // We need to make sure that both colors are visible against // the background if (rgbLightColor == rgbBackground) rgbLightColor = rgbBackground == LIGHT_GRAY ? WHITE : LIGHT_GRAY; if (rgbDarkColor == rgbBackground) rgbDarkColor = rgbBackground == DARK_GRAY ? BLACK : DARK_GRAY; } // Constants for calculating Highlight (TS = "TopShadow") and // shadow (BS = "BottomShadow") values relative to background // Taken from UNIX version -- Eric Bina's Visual.c // // Bias brightness calculation by standard color-sensitivity values // (Percents -- UNIX used floats, but we don't need to) // #define RED_LUMINOSITY 30 #define GREEN_LUMINOSITY 59 #define BLUE_LUMINOSITY 11 // Percent effect of intensity, light, and luminosity & on brightness, #define INTENSITY_FACTOR 25 #define LIGHT_FACTOR 0 #define LUMINOSITY_FACTOR 75 // LITE color model percent to interpolate RGB towards black for BS, TS #define COLOR_LITE_BS_FACTOR 45 #define COLOR_LITE_TS_FACTOR 70 // DARK color model - percent to interpolate RGB towards white for BS, TS #define COLOR_DARK_BS_FACTOR 30 #define COLOR_DARK_TS_FACTOR 50 #define MAX_COLOR 255 #define COLOR_DARK_THRESHOLD 51 #define COLOR_LIGHT_THRESHOLD 204 void CDCCX::Compute3DColors(COLORREF rgbColor, COLORREF &rgbLight, COLORREF &rgbDark) { unsigned uRed, uGreen, uBlue; unsigned uRedBack = GetRValue(rgbColor); unsigned uGreenBack = GetGValue(rgbColor); unsigned uBlueBack = GetBValue(rgbColor); unsigned intensity = (uRedBack + uGreenBack + uBlueBack) / 3; unsigned luminosity = ((RED_LUMINOSITY * uRedBack)/ 100) + ((GREEN_LUMINOSITY * uGreenBack)/ 100) + ((BLUE_LUMINOSITY * uBlueBack)/ 100); unsigned backgroundBrightness = ((intensity * INTENSITY_FACTOR) + (luminosity * LUMINOSITY_FACTOR)) / 100; unsigned f; if (backgroundBrightness < COLOR_DARK_THRESHOLD) { // Dark Background - interpolate 30% toward black uRed = uRedBack - (COLOR_DARK_BS_FACTOR * uRedBack / 100); uGreen = uGreenBack - (COLOR_DARK_BS_FACTOR * uGreenBack / 100); uBlue = uBlueBack - (COLOR_DARK_BS_FACTOR * uBlueBack / 100); rgbDark = RGB(uRed, uGreen, uBlue); // This interpolotes to 50% toward white uRed = uRedBack + (COLOR_DARK_TS_FACTOR * (MAX_COLOR - uRedBack) / 100); uGreen = uGreenBack + (COLOR_DARK_TS_FACTOR * (MAX_COLOR - uGreenBack) / 100); uBlue = uBlueBack + (COLOR_DARK_TS_FACTOR * (MAX_COLOR - uBlueBack) / 100); } else if (backgroundBrightness > COLOR_LIGHT_THRESHOLD) { // Interpolate 45% toward black uRed = uRedBack - (COLOR_LITE_BS_FACTOR * uRedBack / 100); uGreen = uGreenBack - (COLOR_LITE_BS_FACTOR * uGreenBack / 100); uBlue = uBlueBack - (COLOR_LITE_BS_FACTOR * uBlueBack / 100); rgbDark = RGB(uRed, uGreen, uBlue); // Original algorithm (from X source: visual.c) used: // uRed = uRedBack - (COLOR_LITE_TS_FACTOR * uRedBack / 100), // where FACTOR is 20%, but that makes no sense! // I think the intention was large interpolation toward white, // so use max of "medium" range (70%) for smooth continuity across threshhold uRed = uRedBack + (COLOR_LITE_TS_FACTOR * (MAX_COLOR - uRedBack) / 100); uGreen = uGreenBack + (COLOR_LITE_TS_FACTOR * (MAX_COLOR - uGreenBack) / 100); uBlue = uBlueBack + (COLOR_LITE_TS_FACTOR * (MAX_COLOR - uBlueBack) / 100); } else { // Medium Background f = COLOR_DARK_BS_FACTOR + (backgroundBrightness * ( COLOR_LITE_BS_FACTOR - COLOR_DARK_BS_FACTOR ) / MAX_COLOR); uRed = uRedBack - (f * uRedBack / 100); uGreen = uGreenBack - (f * uGreenBack / 100); uBlue = uBlueBack - (f * uBlueBack / 100); rgbDark = RGB(uRed, uGreen, uBlue); f = COLOR_DARK_TS_FACTOR + (backgroundBrightness * ( COLOR_LITE_TS_FACTOR - COLOR_DARK_TS_FACTOR ) / MAX_COLOR); uRed = uRedBack + (f * (MAX_COLOR - uRedBack) / 100); uGreen = uGreenBack + (f * (MAX_COLOR - uGreenBack) / 100); uBlue = uBlueBack + (f * (MAX_COLOR - uBlueBack) / 100); } // Safety check for upper limit uRed = min(MAX_COLOR, uRed); uGreen = min(MAX_COLOR, uGreen); uBlue = min(MAX_COLOR, uBlue); rgbLight = RGB(uRed, uGreen, uBlue); // If either of these colors is the same as the background color // then use the system 3D element colors instead if (rgbLight == m_rgbBackgroundColor || rgbDark == m_rgbBackgroundColor) { GetSystem3DColors(m_rgbBackgroundColor, rgbLight, rgbDark); } } void CDCCX::Set3DColors(COLORREF crBackground) { Compute3DColors(crBackground, m_rgbLightColor, m_rgbDarkColor); } void CDCCX::SetBackgroundColor(MWContext *pContext, uint8 uRed, uint8 uGreen, uint8 uBlue) { // Generate the color reference COLORREF crBackground = ResolveBGColor(uRed, uGreen, uBlue); if( crBackground != m_rgbBackgroundColor ){ // Recalculate the color only if it has changed m_rgbBackgroundColor = crBackground; Set3DColors(m_rgbBackgroundColor); } // Determine transparency. ResolveTransparentColor(uRed, uGreen, uBlue); // Set the background color in the DC. HDC hdc = GetContextDC(); if (hdc) { ::SetBkColor(hdc, m_rgbBackgroundColor); } #ifdef DDRAW if (GetPrimarySurface()) { hdc = GetDispDC(); // set the background color for offscreen surface. if (hdc) { ::SetBkColor(hdc, m_rgbBackgroundColor); } } #endif ReleaseContextDC(hdc); // Have any views (ledges) clear. // Only do the FE_VIEW, since there aren't any other ledges right now. FE_ClearView(pContext, FE_VIEW); } void CDCCX::SetTransparentColor(BYTE red, BYTE green, BYTE blue) { rgbTransparentColor.red = red; rgbTransparentColor.green = green; rgbTransparentColor.blue = blue; } // Create the initial identity palette that contains just the system colors // and the colors. HPALETTE CDCCX::InitPalette(HDC hdc) { int i; HPALETTE hPal; // Create an identity palette LPLOGPALETTE pLogPal = (LPLOGPALETTE)XP_ALLOC(sizeof(LOGPALETTE) + 256 * sizeof(PALETTEENTRY)); if(pLogPal != NULL) { pLogPal->palVersion = 0x300; pLogPal->palNumEntries = 256; // Get entries 0-9 and 246-255, which are the standard system colors GetSystemPaletteEntries(hdc, 0, pLogPal->palNumEntries, pLogPal->palPalEntry); // Initialize palette entry flags for (i = 10; i < 246; i++) { pLogPal->palPalEntry[i].peFlags = PALETTEENTRY_FLAGS; #ifndef USE_IDENTITY_PALETTE // Collapse all unspecified entries to black so that we are // friendlier to other applications sharing the palette. if(i >= (iLowerColors + MAX_IMAGE_PALETTE_ENTRIES)) { pLogPal->palPalEntry[i].peRed = 0; pLogPal->palPalEntry[i].peGreen = 0; pLogPal->palPalEntry[i].peBlue = 0; } #endif } // Now add in the animation colors for(int iLowCnt = iLowerSystemColors, j = 0; iLowCnt < iLowerColors; iLowCnt++, j++) { pLogPal->palPalEntry[iLowCnt].peRed = animationPalette[j].red; pLogPal->palPalEntry[iLowCnt].peGreen = animationPalette[j].green; pLogPal->palPalEntry[iLowCnt].peBlue = animationPalette[j].blue; pLogPal->palPalEntry[iLowCnt].peFlags = PC_NOCOLLAPSE; } if(!(hPal = ::CreatePalette(pLogPal))) { hPal = NULL; } // Done with this. XP_FREE(pLogPal); } return hPal; } HPALETTE CDCCX::CreateColorPalette(HDC hdc, IL_IRGB& transparentColor, int bitsPerPixel) { HPALETTE hPal; // Set up the per-context palette. // This is per-window since not everything goes to the screen, and therefore // won't always have the screen's attributes. (printing, metafiles DCs, etc). IL_ColorMap * defaultColorMap = IL_NewCubeColorMap(NULL, 0, MAX_IMAGE_PALETTE_ENTRIES+1); hPal = CDCCX::InitPalette(hdc); CDCCX::SetColormap(hdc, defaultColorMap, transparentColor, hPal); IL_DestroyColorMap (defaultColorMap); return hPal; } void CDCCX::SetColormap(HDC hdc, NI_ColorMap *pMap, IL_IRGB& transparentColor, HPALETTE hPal) { PALETTEENTRY paletteEntries[256]; int iExactMatches = 0; // # of color requests we were able to match int iFirstImageColor = iLowerColors; int iLastImageColor = iLowerColors + MAX_IMAGE_PALETTE_ENTRIES - 1; // Copy existing palette to get system colors and animation colors GetPaletteEntries(hPal, 0, 256, paletteEntries); if (!pMap->index) { // setup the index array. pMap->index = (unsigned char*)XP_ALLOC(MAX_IMAGE_PALETTE_ENTRIES+1); for (int i = 0; i < MAX_IMAGE_PALETTE_ENTRIES; i++) { pMap->index[i] = iLowerColors + i; paletteEntries[iLowerColors + i].peRed = pMap->map[i].red; paletteEntries[iLowerColors + i].peGreen = pMap->map[i].green; paletteEntries[iLowerColors + i].peBlue = pMap->map[i].blue; paletteEntries[iLowerColors + i].peFlags = PALETTEENTRY_FLAGS; } } paletteEntries[iLowerColors + MAX_IMAGE_PALETTE_ENTRIES].peRed = transparentColor.red; paletteEntries[iLowerColors + MAX_IMAGE_PALETTE_ENTRIES].peGreen = transparentColor.green; paletteEntries[iLowerColors + MAX_IMAGE_PALETTE_ENTRIES].peBlue = transparentColor.blue; paletteEntries[iLowerColors + MAX_IMAGE_PALETTE_ENTRIES].peFlags = PC_NOCOLLAPSE; paletteEntries[255].peRed = 0xFF; paletteEntries[255].peGreen = 0xFF; paletteEntries[255].peBlue = 0xFF; paletteEntries[255].peFlags = PALETTEENTRY_FLAGS; ::SetPaletteEntries(hPal, iFirstImageColor, MAX_IMAGE_PALETTE_ENTRIES, &paletteEntries[iFirstImageColor]); } void CDCCX::SetDocDimension(MWContext *pContext, int iLocation, int32 lWidth, int32 lLength) { // Set the document height and width. m_lDocWidth = lWidth; m_lDocHeight = lLength; } void CDCCX::GetDocPosition(MWContext *pContext, int iLocation, int32 *lX_p, int32 *lY_p) { *lX_p = m_lOrgX; *lY_p = m_lOrgY; } BOOL CDCCX::OnOpenDocumentCX(const char *pPathName) { // Should only happen with window contexts. if(IsWindowContext() == FALSE) { return(FALSE); } // Make sure there's something specified, otherwise just // return sucess. // Take passing in NULL as a request to initialize, which we do // nothing with. if(pPathName != NULL) { // convert the path name to a URL. CString csUrl; WFE_ConvertFile2Url(csUrl, pPathName); // Load it. GetUrl(NET_CreateURLStruct(csUrl, NET_DONT_RELOAD), FO_CACHE_AND_PRESENT); } return(TRUE); } void CDCCX::ViewImages() { #ifdef MOZ_NGLAYOUT XP_ASSERT(0); #else if(IsDestroyed() == FALSE) { // Tell layout that all images are to be force loaded. LO_SetForceLoadImage(NULL, TRUE); ExplicitlyLoadAllImages(); } #endif /* MOZ_NGLAYOUT */ } BOOL CDCCX::CanViewImages() { BOOL bRetval; if(prefInfo.m_bAutoLoadImages || IsDestroyed()) { bRetval = FALSE; } else { bRetval = TRUE; } return(bRetval); } // Set up the things that need to be in order to handle an OLE server // metafile correctly. void CDCCX::EnableOleServer() { TRACE("Enabling context as an OLE server\n"); // Mark a generic switch that can be checked elsewhere. m_bOleServer = TRUE; } // Create a url struct from the history, with appropriate checking // for NULL and such, so that we don't have this code scattered // throughout the client. // bClearStateData is a flag set to erase any data that can't be // tossed around without upsetting the client (form data). // It's off by default, so be careful out there. URL_Struct *CDCCX::CreateUrlFromHist(BOOL bClearStateData, SHIST_SavedData *pSavedData, BOOL bWysiwyg) { // Make sure that we're not destroyed. if(IsDestroyed()) { return(NULL); } // Before we create the URL, we must save any state data of the current page // that is needed to perform the next load (such as position).... // Other's not dealing with history, save their data in the GetUrl call. SHIST_SetPositionOfCurrentDoc(&(GetContext()->hist), 0); #ifdef MOZ_NGLAYOUT XP_ASSERT(0); #else if(GetOriginX() || GetOriginY()) { #ifdef LAYERS LO_Any *pAny = (LO_Any *)LO_XYToNearestElement(GetDocumentContext(), GetOriginX(), GetOriginY(), NULL); #else LO_Any *pAny = (LO_Any *)LO_XYToNearestElement(GetDocumentContext(), GetOriginX(), GetOriginY()); #endif /* LAYERS */ if(pAny != NULL) { TRACE("Remembering document position at element id %ld\n", pAny->ele_id); SHIST_SetPositionOfCurrentDoc(&(GetContext()->hist), pAny->ele_id); } } #endif /* MOZ_NGLAYOUT */ // Call/return the base. URL_Struct *pUrl = CStubsCX::CreateUrlFromHist(bClearStateData, pSavedData, bWysiwyg); return(pUrl); } #ifndef MOZ_NGLAYOUT // // Make the given form element visible on the screen // void CDCCX::DisplayFormElement(MWContext *pContext, int iLocation, LO_FormElementStruct *pFormElement) { // Call the base. CStubsCX::DisplayFormElement(pContext, iLocation, pFormElement); // Figure the coordinates. LTRB Rect; // Note that we call this version of ResolveElement since we do // something special for form elements. Note also that we don't // check the return value since this function may be called before // the form element is actually visible, but we have to correctly // "display". In other words, this function is only called when the // visibility or position of the form element changes and we need // make the corresponding changes to the actual widget irrespective // of whether it's visible or not. ResolveElement(Rect, pFormElement); SafeSixteen(Rect); // Get our front end form element, and have it display itself at the given rectangle. CFormElement *pFormClass = CFormElement::GetFormElement(ABSTRACTCX(GetContext()), pFormElement); if(pFormClass != NULL) { pFormClass->DisplayFormElement(Rect); } } void CDCCX::FormTextIsSubmit(MWContext *pContext, LO_FormElementStruct *pFormElement) { // Call the base. CStubsCX::FormTextIsSubmit(pContext, pFormElement); // Get our front end form element, and have it do it's thang. CFormElement *pFormClass = CFormElement::GetFormElement(ABSTRACTCX(GetContext()), pFormElement); if(pFormClass != NULL) { pFormClass->FormTextIsSubmit(); } } void CDCCX::GetFormElementInfo(MWContext *pContext, LO_FormElementStruct *pFormElement) { // Call the base. CStubsCX::GetFormElementInfo(pContext, pFormElement); // Get our front end form element, and have it do it's thang. CFormElement *pFormClass = CFormElement::GetFormElement(ABSTRACTCX(GetContext()), pFormElement); if(pFormClass != NULL) { pFormClass->GetFormElementInfo(); } } void CDCCX::GetFormElementValue(MWContext *pContext, LO_FormElementStruct *pFormElement, XP_Bool bTurnOff) { // Call the base. CStubsCX::GetFormElementValue(pContext, pFormElement, bTurnOff); // Get our front end form element, and have it do it's thang. CFormElement *pFormClass = CFormElement::GetFormElement(ABSTRACTCX(GetContext()), pFormElement); if(pFormClass != NULL) { pFormClass->GetFormElementValue(bTurnOff); } } void CDCCX::ResetFormElement(MWContext *pContext, LO_FormElementStruct *pFormElement) { // Call the base. CStubsCX::ResetFormElement(pContext, pFormElement); // Get our front end form element, and have it do it's thang. CFormElement *pFormClass = CFormElement::GetFormElement(ABSTRACTCX(GetContext()), pFormElement); if(pFormClass != NULL) { pFormClass->ResetFormElement(); } } void CDCCX::SetFormElementToggle(MWContext *pContext, LO_FormElementStruct *pFormElement, XP_Bool iState) { // Call the base. CStubsCX::SetFormElementToggle(pContext, pFormElement, iState); // Get our front end form element, and have it do it's thang. CFormElement *pFormClass = CFormElement::GetFormElement(ABSTRACTCX(GetContext()), pFormElement); if(pFormClass != NULL) { pFormClass->SetFormElementToggle(iState); } } #endif // Do a fill rect type operation. void CDCCX::FloodRect(LTRB& Rect, HBRUSH hColor) { if(hColor) { HDC hdc = GetContextDC(); if(hdc) { RECT cr; ::SetRect(&cr, CASTINT(Rect.left), CASTINT(Rect.top), CASTINT(Rect.right), CASTINT(Rect.bottom)); ::FillRect(hdc, &cr, hColor); ReleaseContextDC(hdc); } } } BITMAPINFO* CDCCX::FillBitmapInfoHeader(NI_Pixmap* pImage) { BITMAPINFO *pBMInfo; NI_PixmapHeader* imageHeader = &pImage->header; int pixmap_depth = imageHeader->color_space->pixmap_depth; if (pixmap_depth == 24 || pixmap_depth == 32) pBMInfo = (BITMAPINFO *)XP_ALLOC(sizeof(BITMAPINFOHEADER)+ (1 * sizeof(RGBQUAD))); // space for header only else if (pixmap_depth == 16) pBMInfo = (BITMAPINFO *)XP_ALLOC(sizeof(BITMAPINFOHEADER)+ (3 * sizeof(RGBQUAD)) ); // space for header and color masks else if (pixmap_depth == 8) pBMInfo = (BITMAPINFO *)XP_ALLOC(sizeof(BITMAPINFOHEADER)+ (256 * sizeof(RGBQUAD)) ); // space for header and pallette else if (pixmap_depth == 1) pBMInfo = (BITMAPINFO *)XP_ALLOC(sizeof(BITMAPINFOHEADER)+ (2 * sizeof(RGBQUAD)) ); // space for header and pallette ASSERT(pixmap_depth < 32); if (!pBMInfo) return NULL; // error occor. pBMInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); pBMInfo->bmiHeader.biWidth = pImage->header.width; pBMInfo->bmiHeader.biHeight = pImage->header.height; pBMInfo->bmiHeader.biPlanes = 1; pBMInfo->bmiHeader.biBitCount = (short)pixmap_depth; #ifdef XP_WIN32 // Don't allow this to happen on OLE servers, as the metafiles can't // handle it. if ((pixmap_depth > 1 ) && m_bRGB565) { pBMInfo->bmiHeader.biCompression = BI_BITFIELDS; // Define the color masks for a RGB565 DIB LPDWORD lpMasks = (LPDWORD)pBMInfo->bmiColors; lpMasks[0] = 0xF800; // red color mask lpMasks[1] = 0x07E0; // green color mask lpMasks[2] = 0x001F; // blue color mask } else { if (pixmap_depth == 24 || pixmap_depth == 32) { LPDWORD lpMasks = (LPDWORD)pBMInfo->bmiColors; *lpMasks = NULL; } pBMInfo->bmiHeader.biCompression = BI_RGB; } #else pBMInfo->bmiHeader.biCompression = BI_RGB; #endif //pBMInfo->bmiHeader.biSizeImage = NULL; pBMInfo->bmiHeader.biSizeImage = pImage->header.widthBytes * pImage->header.height; pBMInfo->bmiHeader.biXPelsPerMeter = 0; pBMInfo->bmiHeader.biYPelsPerMeter = 0; pBMInfo->bmiHeader.biClrUsed = 0; // default value pBMInfo->bmiHeader.biClrImportant = 0; // all important if(m_bUseDibPalColors) { if (pixmap_depth == 1) { // Build an index table for monochrome images. Only XBMs are // monochome WORD* pPalIndex = (WORD*)(pBMInfo->bmiColors); pPalIndex[0] = 255; // palette index for WHITE pPalIndex[1] = 0; // palette index for BLACK } else { // pImage->depth != 1 unsigned short nClrUsed = (unsigned short)(1 << pBMInfo->bmiHeader.biBitCount); // DIB_PAL_COLORS expects an array of 16-bit unsigned integers that specify // an index into the currently realized logical palette WORD* pPalIndx = (WORD*)(((unsigned char*)pBMInfo) + pBMInfo->bmiHeader.biSize); for (unsigned short index = 0; index < nClrUsed; index++, pPalIndx++) *pPalIndx = index; } } else { // Not using DIB_PAL_COLORS if (pixmap_depth == 8) { RGBQUAD RGBArray[256]; CopyPaletteToRGBArray(GetPalette(), RGBArray); memcpy(&(pBMInfo->bmiColors[0]), RGBArray, (256 * sizeof(RGBQUAD))); } else if (pixmap_depth == 1) { // Build the color table for monochrome images. Only XBMs are monochrome pBMInfo->bmiColors[0].rgbRed = 255; pBMInfo->bmiColors[0].rgbGreen = 255; pBMInfo->bmiColors[0].rgbBlue = 255; pBMInfo->bmiColors[0].rgbReserved = 0; pBMInfo->bmiColors[1].rgbRed = 0; pBMInfo->bmiColors[1].rgbGreen = 0; pBMInfo->bmiColors[1].rgbBlue = 0; pBMInfo->bmiColors[1].rgbReserved = 0; } } return pBMInfo; } static void replaceColorSpace(NI_Pixmap* pImage, NI_ColorSpace* curColorSpace, int devicePixmap) { NI_PixmapHeader* imageHeader = &pImage->header; NI_ColorSpace* color_space = imageHeader->color_space; ASSERT(color_space->pixmap_depth < 32); if (color_space->pixmap_depth == 1) return; if ((color_space->pixmap_depth <= 8) || (devicePixmap < color_space->pixmap_depth)) { IL_ReleaseColorSpace(color_space); IL_AddRefToColorSpace(curColorSpace); imageHeader->color_space = curColorSpace; } } static BOOL CanCreateBrush(HBITMAP hBitmap, int nBitsPerPixel) { BITMAP bitmap; // Get the size of the bitmap ::GetObject(hBitmap, sizeof(bitmap), &bitmap); // We can create a brush if the bitmap is exacly 8x8 or we're on NT if (sysInfo.m_bWinNT) { if (nBitsPerPixel == 24) { // There's a reported problem with 24bpp mode on NT, but I haven't // seen it on NT 4.0 // if (sysInfo.m_dwMajor < 4) return FALSE; } // Large brushes on NT are a performance hog, so place an upper // limit on the brush size. return bitmap.bmWidth <= 64 && bitmap.bmHeight <= 64; } return bitmap.bmWidth == 8 && bitmap.bmHeight == 8; } HBITMAP CDCCX::CreateBitmap(HDC hTargetDC, NI_Pixmap *image) { ASSERT(hTargetDC); FEBitmapInfo *imageInfo = (FEBitmapInfo*)image->client_data; BITMAPINFO *pBmInfo = imageInfo->bmpInfo; ASSERT(pBmInfo); return ::CreateDIBitmap(hTargetDC, &pBmInfo->bmiHeader, CBM_INIT, image->bits, pBmInfo, m_bUseDibPalColors ? DIB_PAL_COLORS : DIB_RGB_COLORS); } int CDCCX::DisplayPixmap(NI_Pixmap* image, NI_Pixmap* mask, int32 x, int32 y, int32 x_offset, int32 y_offset, int32 width, int32 height, int32 lScaleWidth, int32 lScaleHeight, LTRB& Rect) { // If width and height are 0, then we assume the entire width and height. // x and y are relative coords to the top left of the image. HDC hdc; #ifdef DDRAW LPDIRECTDRAWSURFACE drawSurface = GetBackSurface(); #endif hdc = GetDispDC(); FEBitmapInfo *imageInfo = (FEBitmapInfo*) image->client_data; if (!imageInfo) return FALSE; // there is no image to display. // set this flag, so the display boarder will not try to display the icon. imageInfo->imageDisplayed = TRUE; int xRepeat, yRepeat; xRepeat = (CASTINT(width) + CASTINT(x_offset) + CASTINT(imageInfo->targetWidth) -1) / CASTINT(imageInfo->targetWidth); yRepeat = (CASTINT(height) + CASTINT(y_offset) + CASTINT(imageInfo->targetHeight) -1) / CASTINT(imageInfo->targetHeight); if (!ResolveElement(Rect, image, x_offset * m_lConvertX, y_offset *m_lConvertY, x * m_lConvertX, y* m_lConvertY, width* m_lConvertX, height* m_lConvertY, lScaleWidth * m_lConvertX, lScaleHeight * m_lConvertY)) return FALSE; SafeSixteen(Rect); FEBitmapInfo *maskInfo = (FEBitmapInfo *)NULL; if (mask) maskInfo = (FEBitmapInfo *)mask->client_data; x_offset = (x_offset > 0) ? x_offset : 0; y_offset = (y_offset > 0) ? y_offset : 0; if ((xRepeat > 1) || (yRepeat > 1)) { // tiled TileImage(hdc, Rect, image, mask, x * GetXConvertUnit(), y * GetYConvertUnit()); } else { if (maskInfo) { if ((imageInfo->hBitmap) && (maskInfo->hBitmap)) { #ifdef XP_WIN32 if (sysInfo.m_bWinNT && (GetContextType() != MetaFile) && !IsPrintContext()) { HBITMAP hOldBitmap = (HBITMAP)::SelectObject(m_pImageDC, imageInfo->hBitmap); // MaskBlt has two raster ops: one for the foreground pixels (value of 1) // and one for the background pixels (value of 0). The raster op is // specified using MAKEROP4(fore,back) #ifdef USE_DIB_SECTION if (image->bits) ::MaskBlt(hdc, CASTINT(Rect.left), CASTINT(Rect.top), CASTINT(Rect.right - Rect.left), CASTINT(Rect.bottom - Rect.top), m_pImageDC, x_offset, y_offset, maskInfo->hBitmap, x_offset, y_offset, MAKEROP4(SRCCOPY, 0x00AA0029)); // 0x00AA0029 is destination... else #endif ::MaskBlt(hdc, CASTINT(Rect.left), CASTINT(Rect.top), CASTINT(Rect.right - Rect.left), CASTINT(Rect.bottom - Rect.top), m_pImageDC, x_offset, y_offset, maskInfo->hBitmap, x_offset, y_offset, MAKEROP4(0x00AA0029, SRCCOPY)); // 0x00AA0029 is destination... // Cleanup ::SelectObject(m_pImageDC, hOldBitmap); } else #endif StretchMaskBlt(hdc, imageInfo->hBitmap, maskInfo->hBitmap, CASTINT(Rect.left), CASTINT(Rect.top), CASTINT(Rect.right - Rect.left), CASTINT(Rect.bottom - Rect.top), x_offset, y_offset, width, height); } else { _StretchDIBitsWithMask(hdc, CASTINT(Rect.left), CASTINT(Rect.top), CASTINT(Rect.right - Rect.left), CASTINT(Rect.bottom - Rect.top), CASTINT(x_offset), // the reason for this calculation is that Window's bitmap // is reverse. The first scan line will be at the buttom of // the bitmap buffer. CASTINT(imageInfo->height - ((height ) + y_offset)), CASTINT(width ), CASTINT(height), image, mask); } } else { StretchPixmap(hdc, image, CASTINT(Rect.left), CASTINT(Rect.top), CASTINT(Rect.right - Rect.left), CASTINT(Rect.bottom - Rect.top), x_offset, y_offset, width, height); } } ReleaseContextDC(hdc); return 1; } /////////////////// // Destination coordinates are in the logical units of pDC, and // the source coordinates are in device units void CDCCX::StretchPixmap(HDC hTargetDC, NI_Pixmap* pImage, int32 dx, int32 dy, int32 dw, int32 dh, int32 sx, int32 sy, int32 sw, int32 sh) { // Clamp the width and height if necessary if (sx < 0 || sy < 0) return; FEBitmapInfo *imageInfo = (FEBitmapInfo*)pImage->client_data; BITMAPINFO *pBmInfo = imageInfo->bmpInfo; if (imageInfo->hBitmap) { HBITMAP hOldBitmap; // If we are using this image as a tile, the bitmap will already be selected // into the memory DC for us. if (!imageInfo->IsTile) hOldBitmap = (HBITMAP)::SelectObject(m_pImageDC, imageInfo->hBitmap); ::StretchBlt(hTargetDC, CASTINT(dx), CASTINT(dy), CASTINT(dw), CASTINT(dh), m_pImageDC, CASTINT(sx), CASTINT(sy), CASTINT(sw), CASTINT(sh), pBmInfo->bmiHeader.biBitCount == 1 ? SRCAND : SRCCOPY); // If we are using this image as a tile, the bitmap will be deselected for us. if (!imageInfo->IsTile) ::SelectObject(m_pImageDC, hOldBitmap); } else { // the reason for this calculation is because window's bmp is an // upsidedown image. the bit in the pImage->bits does reflect // this. So we need to sepcify the offset from the bottom up. ::StretchDIBits( hTargetDC, CASTINT(dx), CASTINT(dy), CASTINT(dw), CASTINT(dh), CASTINT(sx), CASTINT(imageInfo->height - (sh + sy)), CASTINT(sw), CASTINT(sh), pImage->bits, // address of bitmap bits imageInfo->bmpInfo, // address of bitmap data CASTUINT(m_bUseDibPalColors ? DIB_PAL_COLORS : DIB_RGB_COLORS), pBmInfo->bmiHeader.biBitCount == 1 ? SRCAND : SRCCOPY); } } HBITMAP CDCCX::CreateMask(HDC hTargetDC, NI_Pixmap* mask) { ASSERT(hTargetDC); FEBitmapInfo *maskInfo = (FEBitmapInfo*)mask->client_data; // Build a BITMAPINFO struct for mask char cMask[sizeof(BITMAPINFOHEADER) + (2 * sizeof(RGBQUAD))]; LPBITMAPINFO pBmInfoMask = (LPBITMAPINFO)cMask; memcpy(pBmInfoMask, maskInfo->bmpInfo, sizeof(BITMAPINFOHEADER)); pBmInfoMask->bmiHeader.biBitCount = 1; pBmInfoMask->bmiHeader.biCompression = BI_RGB; // must NOT be BI_BITFIELDS pBmInfoMask->bmiColors[1] = rgbqBlack; // background pixels pBmInfoMask->bmiColors[0] = rgbqWhite; // foreground pixels // Create the mask. It's important that we use the memory DC, because we // want a momochrome bitmap return ::CreateDIBitmap(hTargetDC, (LPBITMAPINFOHEADER)pBmInfoMask, CBM_INIT, mask->bits, pBmInfoMask, // m_bUseDibPalColors ? DIB_PAL_COLORS : DIB_RGB_COLORS); DIB_RGB_COLORS); } // StretchBlt a DIB with a mask // Destination coordinates are in the logical units of pDC, and // the source coordinates are in device units void WFE_StretchDIBitsWithMask(HDC hTargetDC, BOOL isDeviceDC, HDC hOffscreenDC, int dx, int dy, int dw, int dh, int sx, int sy, int sw, int sh, void XP_HUGE *imageBit, BITMAPINFO* lpImageInfo, void XP_HUGE *maskBit, BOOL bUseDibPalColors, COLORREF fillWithBackground ) { // Tile the shadow bitmap with the backdrop HBITMAP pSaveBmp; HBITMAP bmpShadow; HDC hTempDC; int32 targetX, targetY; HDC memDC; if (isDeviceDC) { if (hOffscreenDC) memDC = hOffscreenDC; else { memDC = ::CreateCompatibleDC(hTargetDC); } if (!(bmpShadow = (HBITMAP)CreateCompatibleBitmap(hTargetDC, dw, dh))) { TRACE("_StretchBltWithMask() can't create bitmap!\n"); return; } pSaveBmp = (HBITMAP) ::SelectObject(memDC, bmpShadow); if (!fillWithBackground) { ::StretchBlt(memDC, // get the screen bit. CASTINT(0), CASTINT(0), CASTINT(dw), CASTINT(dh), hTargetDC, CASTINT(dx), CASTINT(dy), CASTINT(dw), CASTINT(dh), SRCCOPY); } else { // the background is solid color. HBRUSH hbr = ::CreateSolidBrush(fillWithBackground); RECT tempRect; tempRect.left = tempRect.top = 0; tempRect.right = dw; tempRect.bottom = dh; ::FillRect(memDC, &tempRect, hbr); ::DeleteObject(hbr); } hTempDC = memDC; targetX = targetY = 0; } else { hTempDC = hTargetDC; targetX = dx; targetY = dy; } char cMask[sizeof(BITMAPINFOHEADER) + (2 * sizeof(RGBQUAD))]; LPBITMAPINFO pBmInfoMask = (LPBITMAPINFO)cMask; memcpy(pBmInfoMask, lpImageInfo, sizeof(BITMAPINFOHEADER)); pBmInfoMask->bmiHeader.biBitCount = 1; pBmInfoMask->bmiHeader.biCompression = BI_RGB; // must NOT be BI_BITFIELDS // Build a color table for monochrome mask. The image library sets foreground // pixels to 1 and background pixels to 0. We want it the other way around // when doing the AND operation pBmInfoMask->bmiColors[0] = rgbqWhite; // background pixels pBmInfoMask->bmiColors[1] = rgbqBlack; // foreground pixels pBmInfoMask->bmiHeader.biSizeImage = 0; int err = ::StretchDIBits(hTempDC, CASTINT(targetX), CASTINT(targetY), CASTINT(dw), CASTINT(dh), CASTINT(sx), CASTINT(sy), CASTINT(sw), CASTINT(sh), maskBit, pBmInfoMask, DIB_RGB_COLORS, SRCAND); err = ::StretchDIBits(hTempDC, CASTINT(targetX), CASTINT(targetY), CASTINT(dw), CASTINT(dh), CASTINT(sx), CASTINT(sy), CASTINT(sw), CASTINT(sh), imageBit, lpImageInfo, bUseDibPalColors ? DIB_PAL_COLORS : DIB_RGB_COLORS, SRCPAINT); if (isDeviceDC) { ::StretchBlt(hTargetDC, CASTINT(dx), CASTINT(dy), CASTINT(dw), CASTINT(dh), memDC, CASTINT(0), CASTINT(0), CASTINT(dw),CASTINT(dh), SRCCOPY); ::SelectObject(memDC, pSaveBmp); VERIFY(::DeleteObject( bmpShadow)); if (!hOffscreenDC) { // Delete the temporary DC that we created. ::DeleteDC(memDC); } } } // StretchBlt a DIB with a mask // Destination coordinates are in the logical units of pDC, and // the source coordinates are in device units void CDCCX::_StretchDIBitsWithMask(HDC hTargetDC, int dx, int dy, int dw, int dh, int sx, int sy, int sw, int sh, NI_Pixmap *image, NI_Pixmap *mask) { // Tile the shadow bitmap with the backdrop FEBitmapInfo *imageInfo = (FEBitmapInfo*)image->client_data; FEBitmapInfo *maskInfo = (FEBitmapInfo*)mask->client_data; WFE_StretchDIBitsWithMask(hTargetDC, IsDeviceDC(), m_pImageDC, dx, dy, dw, dh, sx, sy, sw, sh, image->bits, imageInfo->bmpInfo, mask->bits, m_bUseDibPalColors); } void CDCCX::StretchMaskBlt(HDC hTargetDC, HBITMAP theBitmap, HBITMAP theMask, int32 dx, int32 dy, int32 dw, int32 dh, int32 sx, int32 sy, int32 sw, int32 sh) { // Tile the shadow bitmap with the backdrop HDC memDC = NULL; HBITMAP pSaveBmp; HBITMAP bmpShadow; HPALETTE hOldPal1 = NULL; int32 targetX, targetY; if (IsDeviceDC()) { if (!(bmpShadow = (HBITMAP)CreateCompatibleBitmap(hTargetDC, CASTINT(dw), CASTINT(dh)))) { TRACE("_StretchBltWithMask() can't create bitmap!\n"); return; } // Create memory DC if (!(memDC=CreateCompatibleDC(hTargetDC))) { TRACE("_StretchBltWithMask() can't create compatible memory DC!\n"); return; } if (m_bUseDibPalColors && m_pPal) { hOldPal1 = (HPALETTE)::SelectPalette(memDC, m_pPal, FALSE); } pSaveBmp = (HBITMAP) ::SelectObject(memDC, bmpShadow); ::StretchBlt(memDC, CASTINT(0), CASTINT(0), CASTINT(dw), CASTINT(dh), hTargetDC, CASTINT(dx), CASTINT(dy), CASTINT(dw), CASTINT(dh), SRCCOPY); targetX = targetY = 0; } else { memDC = hTargetDC; targetX = dx; targetY = dy; } HBITMAP old = (HBITMAP)::SelectObject(m_pImageDC, theMask); ::StretchBlt(memDC, CASTINT(targetX), CASTINT(targetY), CASTINT(dw), CASTINT(dh), m_pImageDC, CASTINT(sx), CASTINT(sy), CASTINT(sw), CASTINT(sh), SRCAND); // load the bitmap into the cached image CDC ::SelectObject(m_pImageDC, theBitmap); ::StretchBlt(memDC, CASTINT(targetX), CASTINT(targetY), CASTINT(dw), CASTINT(dh), m_pImageDC, CASTINT(sx), CASTINT(sy), CASTINT(sw), CASTINT(sh), SRCPAINT); if (IsDeviceDC()) { ::StretchBlt(hTargetDC, CASTINT(dx), CASTINT(dy), CASTINT(dw), CASTINT(dh), memDC, CASTINT(0), CASTINT(0), CASTINT(dw),CASTINT(dh), SRCCOPY); ::SelectObject(memDC, pSaveBmp); if (m_bUseDibPalColors && hOldPal1) { ::SelectPalette(memDC, hOldPal1, FALSE); } VERIFY(::DeleteDC(memDC)); VERIFY(::DeleteObject( bmpShadow)); } ::SelectObject(m_pImageDC, old); } // We need to allocate the space for the image decoding ourselves because it // depends on what size machine we are on how we want to do it BITMAPINFO *CDCCX::NewPixmap(NI_Pixmap *pImage, BOOL mask) { if(mask == FALSE) { replaceColorSpace( pImage, /*this->*/curColorSpace, /*this->*/m_iBitsPerPixel); } NI_PixmapHeader& header = pImage->header; NI_ColorSpace *& color_space = header.color_space; uint8& pixmap_depth = color_space->pixmap_depth; if(pImage->bits == NULL) { header.widthBytes = header.width; header.widthBytes *= pixmap_depth; if(pixmap_depth < 8) { header.widthBytes += 7; } header.widthBytes /= 8; // Make sure image width is 4byte aligned int iAlign = CASTINT(header.widthBytes % 4); if(iAlign) { header.widthBytes += 4; header.widthBytes -= iAlign; } //#ifndef XP_WIN32 #ifndef USE_DIB_SECTION // The image buffer might need to be really big (i.e. over 32K) // We need to use a huge memory allocation on the 16-bit version pImage->bits = HugeAlloc(header.widthBytes * header.height, 1); // Note: It's possible that the image is so huge that we can't allocate enough // memory for it, especially under Win16 (e.g. 18 Mb images) if(pImage->bits == NULL) { return(NULL); } return(FillBitmapInfoHeader(pImage)); #else // for use with createDibSection. BITMAPINFO* pbmInfo = FillBitmapInfoHeader(pImage); FEBitmapInfo *imageInfo; imageInfo = (FEBitmapInfo*) pImage->client_data; HDC hdc = GetContextDC(); imageInfo->hBitmap = CreateDIBSection(hdc, pbmInfo, // pointer to structure containing bitmap size, format, and color data m_bUseDibPalColors ? DIB_PAL_COLORS : DIB_RGB_COLORS, &pImage->bits, // pointer to variable to receive a pointer to the bitmap's bit values NULL, // optional handle to a file mapping object NULL // offset to the bitmap bit values within the file mapping object ); ReleaseContextDC(hdc); #ifdef DEBUG // If this assert fires, please be sure to report the following // information: pixmap_depth, header.widthBytes, header.height // and the current display setting - kevina. XP_ASSERT(pImage->bits); if (pImage->bits) { // Check whether the pointer is currently valid. XP_ASSERT(!IsBadWritePtr((void *)pImage->bits, (uint)(header.widthBytes*header.height))); XP_ASSERT(!IsBadReadPtr((void *)pImage->bits, (uint)(header.widthBytes*header.height))); // For testing. Purify sometimes gets confused and complains that // the shared memory pointer returned by CreateDIBSection is // invalid, even though the previous assertions don't fire. If // this happens, expect Purify to complain whenever the ImageLib // accesses the bits pointer. // memset(pImage->bits, ~0, (header.widthBytes * header.height)); memset(pImage->bits, ~0, 1); } #endif // DEBUG if (!imageInfo->hBitmap) { return FALSE; } else return pbmInfo; #endif } return NULL; } // Create a larger tile from a smaller one. The dimensions of the larger // tile must be a multiple of the dimensions of the smaller tile. static HBITMAP CreateLargerTile(HDC pDC, HDC pMemDCNew, HDC pMemDCOld, NI_Pixmap *pImage, BOOL bUseDibPalColors, int iOldWidth, int iOldHeight, int iNewWidth, int iNewHeight) { int x, y; HBITMAP pNewTile; HGDIOBJ pSavedObj1, pSavedObj2; FEBitmapInfo *imageInfo = (FEBitmapInfo *)pImage->client_data; pNewTile = CreateCompatibleBitmap(pDC, iNewWidth, iNewHeight); if (!pNewTile) return NULL; pSavedObj1 = (HGDIOBJ)::SelectObject(pMemDCNew, pNewTile); if (imageInfo->hBitmap) { pSavedObj2 = (HGDIOBJ)::SelectObject(pMemDCOld, imageInfo->hBitmap); ::BitBlt(pMemDCNew, 0, 0, iOldWidth, iOldHeight, pMemDCOld, 0, 0, SRCCOPY); } else { uint iUsage = bUseDibPalColors ? DIB_PAL_COLORS : DIB_RGB_COLORS; ::StretchDIBits(pMemDCNew, 0, 0, iOldWidth, iOldHeight, 0, 0, iOldWidth, iOldHeight, pImage->bits, imageInfo->bmpInfo, iUsage, SRCCOPY); } // Fill up the new tile exponentially for speed. for (x = iOldWidth; x < iNewWidth; x *= 2) { ::BitBlt(pMemDCNew, x, 0, MIN(x,iNewWidth-x), iOldHeight, pMemDCNew, 0, 0, SRCCOPY); } for (y = iOldHeight; y < iNewHeight; y *= 2) { ::BitBlt(pMemDCNew, 0, y, iNewWidth, MIN(y,iNewHeight-y), pMemDCNew, 0, 0, SRCCOPY); } ::SelectObject(pMemDCNew, pSavedObj1); if (imageInfo->hBitmap) ::SelectObject(pMemDCOld, pSavedObj2); return pNewTile; } #ifdef DDRAW /* * DDColorMatch * * convert a RGB color to a pysical color. * * we do this by leting GDI SetPixel() do the color matching * then we lock the memory and see what it got mapped to. */ static DWORD DDColorMatch(IDirectDrawSurface *pdds, COLORREF rgb) { COLORREF rgbT; HDC hdc; DWORD dw = CLR_INVALID; DDSURFACEDESC ddsd; HRESULT hres; // // use GDI SetPixel to color match for us // if (rgb != CLR_INVALID && pdds->GetDC(&hdc) == DD_OK) { rgbT = GetPixel(hdc, 0, 0); // save current pixel value SetPixel(hdc, 0, 0, rgb); // set our value pdds->ReleaseDC(hdc); } // // now lock the surface so we can read back the converted color // ddsd.dwSize = sizeof(ddsd); while ((hres = pdds->Lock(NULL, &ddsd, 0, NULL)) == DDERR_WASSTILLDRAWING) ; if (hres == DD_OK) { dw = *(DWORD *)ddsd.lpSurface; // get DWORD dw &= (1 << ddsd.ddpfPixelFormat.dwRGBBitCount)-1; // mask it to bpp pdds->Unlock(NULL); } // // now put the color that was there back. // if (rgb != CLR_INVALID && pdds->GetDC(&hdc) == DD_OK) { SetPixel(hdc, 0, 0, rgbT); pdds->ReleaseDC(hdc); } return dw; } // MWH this funtion only work when there is directDraw support. It use the transColor for // transparent blt. if releaseTempSurf == FALSE. It is caller's responsibility to release // the surf. BOOL CDCCX::TransparentBlt(int dx, int dy, int dw, int dh, int sx, int sy, int sw, int sh, NI_Pixmap *image, COLORREF transColor, LPDIRECTDRAWSURFACE surf) { if (!GetPrimarySurface()) return FALSE; LPDDSURFACEDESC ddesc = GetSurfDesc(); RECT rect; HRESULT err = 1; rect.left = rect.top = 0; rect.bottom = dy + dh; rect.right = dx + dw; BOOL needRelease = TRUE; LPDIRECTDRAWSURFACE tempsurf; if (!surf) { tempsurf = CreateOffscreenSurface(rect); } else { tempsurf = surf; needRelease = FALSE; } HDC tempDC; FEBitmapInfo *imageInfo; imageInfo = (FEBitmapInfo*) image->client_data; if (tempsurf) { tempsurf->GetDC(&tempDC); ::StretchDIBits(tempDC, CASTINT(dx), CASTINT(dy), CASTINT(dw), CASTINT(dh), CASTINT(sx), CASTINT(sy), CASTINT(sw), CASTINT(sh), image->bits, imageInfo->bmpInfo, DIB_RGB_COLORS, SRCCOPY); ReleaseOffscreenSurfDC(); rect.left = dx; rect.top = dy; tempsurf->ReleaseDC(tempDC); DDCOLORKEY colorKey; if (ddesc->ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) { //palette device colorKey.dwColorSpaceLowValue = ::GetNearestPaletteIndex(GetPalette(), transColor); colorKey.dwColorSpaceHighValue = ::GetNearestPaletteIndex(GetPalette(), transColor); } else { colorKey.dwColorSpaceLowValue = DDColorMatch(tempsurf, transColor); colorKey.dwColorSpaceHighValue = DDColorMatch(tempsurf, transColor); } tempsurf->SetColorKey(DDCKEY_SRCBLT, &colorKey); err = GetBackSurface()->Blt(&rect, tempsurf, &rect, DDBLT_KEYSRC , NULL); if (err == DDERR_SURFACELOST) { RestoreAllDrawSurface(); err = GetBackSurface()->Blt(&rect, tempsurf, &rect, DDBLT_KEYSRC , NULL); } if (needRelease) { tempsurf->Release(); } LockOffscreenSurfDC(); } if (err != 0) return FALSE; else return TRUE; } #endif #define ROUNDUP(_x,_toMultipleOf) (((_x)+(_toMultipleOf)-1)/(_toMultipleOf)*(_toMultipleOf)) void CDCCX::TileImage(HDC hdc, LTRB& Rect, NI_Pixmap* image, NI_Pixmap* mask, int32 x, int32 y) { int iMinTileWidth, iMinTileHeight, iTileWidth, iTileHeight; int iRectWidth, iRectHeight, iOrigWidth, iOrigHeight; HBITMAP pTmpImageBitmap = NULL, pTmpMaskBitmap = NULL, pSavedImageBitmap, pSavedMaskBitmap; HGDIOBJ pOldObj; FEBitmapInfo *imageInfo; FEBitmapInfo *maskInfo; imageInfo = (FEBitmapInfo*) image->client_data; int32 lDrawingOrgX, lDrawingOrgY; GetDrawingOrigin(&lDrawingOrgX, &lDrawingOrgY); // If we a backdrop image has been explicitly specified and // it is transparent, then don't use the NT brush feature, // since it doesn't support masks. if ((!mask) && (imageInfo->hBitmap) && (CanCreateBrush(imageInfo->hBitmap, m_iBitsPerPixel))) { CPoint brushOrg(CASTINT(lDrawingOrgX - m_lOrgX), CASTINT(lDrawingOrgY - m_lOrgY)); HBRUSH hBrush = CreatePatternBrush(imageInfo->hBitmap); ASSERT(hBrush); // We need to align the brush properly. The values to SetBrushOrg() specifiy // where the brush origin (i.e. the point (0, 0) of the brush) will be mapped. // The coordinates must be in device units ::LPtoDP(hdc, &brushOrg, 1); brushOrg.x %= (imageInfo->width * GetXConvertUnit()); brushOrg.y %= (imageInfo->height * GetYConvertUnit()); POINT tempPoint; #ifdef _WIN32 ::SetBrushOrgEx(hdc,brushOrg.x, brushOrg.y, &tempPoint); #else ::SetBrushOrg( hdc, brushOrg.x, brushOrg.y ); #endif // Erase the background ::FillRect(hdc, (RECT*)&Rect, hBrush); VERIFY(::DeleteObject(hBrush)); #ifdef _WIN32 // Restore the brush origin ::SetBrushOrgEx(hdc, tempPoint.x, tempPoint.y, NULL); #endif ReleaseContextDC(hdc); return; } if (mask) { maskInfo = (FEBitmapInfo*) mask->client_data; } // If the width (or height) of the image is less than the smaller of // 32 and half the width (or height) of the area to be tiled, then tile the // image into a larger temporary bitmap and use the temporary bitmap // as the tile. We also limit the actual area of the temporary tile to 4096. iOrigWidth = imageInfo->width * GetXConvertUnit(); iOrigHeight = imageInfo->height *GetYConvertUnit(); iRectWidth = Rect.right - Rect.left; iRectHeight = Rect.bottom - Rect.top; iMinTileWidth = MIN(32,MAX(iRectWidth/2,1)); // Tile must be at least this wide. iMinTileHeight = MIN(32,MAX(iRectHeight/2,1)); // Tile must be at least this high. iTileWidth = ROUNDUP(iMinTileWidth, iOrigWidth); // Actual width of temporary tile. iTileHeight = ROUNDUP(iMinTileHeight, iOrigHeight); // Actual height of temporary tile. if ((iOrigWidth < iMinTileWidth || iOrigHeight < iMinTileHeight) && (iTileWidth * iTileHeight < 4096)) { HDC pTmpDC = NULL; // Create a temporary larger tile and use it instead of the original tile. HDC hhDC = GetContextDC(); pTmpDC = CreateCompatibleDC(hhDC); ReleaseContextDC(hhDC); if (!pTmpDC) return; HPALETTE hOldPal; if (m_bUseDibPalColors) hOldPal = ::SelectPalette(pTmpDC, GetPalette(), FALSE); pTmpImageBitmap = CreateLargerTile(hhDC, pTmpDC, m_pImageDC, image, m_bUseDibPalColors, iOrigWidth, iOrigHeight, iTileWidth, iTileHeight); if (!pTmpImageBitmap) { // OOM if (m_bUseDibPalColors) ::SelectPalette(pTmpDC, hOldPal, FALSE); VERIFY(::DeleteDC(pTmpDC)); return; } if (mask) { pTmpMaskBitmap = CreateLargerTile(hhDC, pTmpDC, m_pImageDC, mask, m_bUseDibPalColors, iOrigWidth, iOrigHeight, iTileWidth, iTileHeight); if (!pTmpMaskBitmap) { // OOM if (m_bUseDibPalColors) ::SelectPalette(pTmpDC, hOldPal, FALSE); VERIFY(::DeleteDC(pTmpDC)); VERIFY(::DeleteObject(pTmpImageBitmap)); return; } } pSavedImageBitmap = imageInfo->hBitmap; imageInfo->hBitmap = pTmpImageBitmap; imageInfo->width = iTileWidth; imageInfo->height = iTileHeight; if (mask) { pSavedMaskBitmap = maskInfo->hBitmap; maskInfo->hBitmap = pTmpMaskBitmap; maskInfo->width = iTileWidth; maskInfo->height = iTileHeight; } if (m_bUseDibPalColors) ::SelectPalette(pTmpDC, hOldPal, FALSE); VERIFY(::DeleteDC(pTmpDC)); } // Set a flag to indicate that we are in the tiling code. imageInfo->IsTile = TRUE; if (mask) maskInfo->IsTile = TRUE; // If we are going to call StretchPixmap, avoid selecting the image bitmap // into the memory DC each time. if (!mask && imageInfo->hBitmap) pOldObj = ::SelectObject(m_pImageDC, imageInfo->hBitmap); // We need to properly align the backdrop vertically (in logical units) int srcY = CASTINT((((Rect.top - GetTopMargin())/ GetYConvertUnit()) - lDrawingOrgY + m_lOrgY ) % (imageInfo->height)); int dstHeight = CASTINT((imageInfo->height* GetYConvertUnit()) - (srcY * GetYConvertUnit())); // MWH -- this loop needs a rewrite. I just do this for first pass on win16 compiler. // Should not check for the which Blt we want to use inside the loop. // Redraw the backdrop from left to right and top to bottom for (int currentY = CASTINT(Rect.top); currentY < CASTINT(Rect.bottom);) { // We need to properly align the backdrop horizontally (in logical units) int srcX = CASTINT((((Rect.left - GetLeftMargin()) / GetXConvertUnit()) - lDrawingOrgX + m_lOrgX)% (imageInfo->width)); int dstWidth = CASTINT((imageInfo->width * GetXConvertUnit()) - srcX * GetXConvertUnit()); // Only draw as far down as we've been asked to draw if (CASTINT(currentY + dstHeight) > CASTINT(Rect.bottom)) dstHeight = CASTINT(Rect.bottom - currentY); // Loop across the row for (int currentX = CASTINT(Rect.left); currentX < CASTINT(Rect.right);) { // Only draw as far across as we've been asked to draw if (currentX + dstWidth > Rect.right) dstWidth = CASTINT(Rect.right - currentX); // m_pImageDC is in device space, so we need to convert coordinates RECT srcRect; ::SetRect(&srcRect, srcX, srcY, srcX + (dstWidth/ GetXConvertUnit()), srcY + (dstHeight/ GetYConvertUnit())); if (mask) { if (imageInfo->hBitmap && maskInfo->hBitmap) { #ifdef _WIN32 if (sysInfo.m_bWinNT && (GetContextType() != MetaFile)) { HBITMAP hOldBitmap = (HBITMAP)::SelectObject(m_pImageDC, imageInfo->hBitmap); #ifdef USE_DIB_SECTION if (image->bits) MaskBlt(hdc, currentX, currentY, dstWidth, dstHeight, m_pImageDC, srcRect.left, srcRect.top, maskInfo->hBitmap, srcRect.left, srcRect.top, MAKEROP4(SRCCOPY, 0x00AA0029)); // 0x00AA0029 is destination... else #endif MaskBlt(hdc, currentX, currentY, dstWidth, dstHeight, m_pImageDC, srcRect.left, srcRect.top, maskInfo->hBitmap, srcRect.left, srcRect.top, MAKEROP4(0x00AA0029, SRCCOPY)); // 0x00AA0029 is destination... ::SelectObject(m_pImageDC, hOldBitmap); } else #endif StretchMaskBlt(hdc, imageInfo->hBitmap, maskInfo->hBitmap, currentX, currentY, dstWidth, dstHeight, srcRect.left, srcRect.top, srcRect.right - srcRect.left, srcRect.bottom - srcRect.top); } else { // blt bitmap with mask. _StretchDIBitsWithMask(hdc, currentX, currentY, dstWidth, dstHeight, srcRect.left, // the reason for this calculation is that Window's bitmap // is reverse. The first scan line will be at the bottom of // the bitmap buffer. imageInfo->height - srcRect.bottom, srcRect.right - srcRect.left, srcRect.bottom - srcRect.top, image, mask); } } else { StretchPixmap(hdc, image, currentX, currentY, dstWidth, dstHeight, srcRect.left, srcRect.top, srcRect.right - srcRect.left, srcRect.bottom - srcRect.top); } currentX += dstWidth; srcX = 0; dstWidth = imageInfo->width * GetXConvertUnit(); } currentY += dstHeight; srcY = 0; dstHeight = imageInfo->height * GetYConvertUnit(); } // If we called StretchPixmap, restore the memory DC to its previous state. if (!mask && imageInfo->hBitmap) ::SelectObject(m_pImageDC, pOldObj); // If we created a temporary tile, then restore the original bitmaps. if (pTmpImageBitmap) { imageInfo->width = iOrigWidth; imageInfo->height = iOrigHeight; imageInfo->hBitmap = pSavedImageBitmap; VERIFY(::DeleteObject(pTmpImageBitmap)); } if (pTmpMaskBitmap) { maskInfo->width = iOrigWidth; maskInfo->height = iOrigHeight; maskInfo->hBitmap = pSavedMaskBitmap; VERIFY(::DeleteObject(pTmpMaskBitmap)); } // Reset the flags to indicate that we are done tiling. imageInfo->IsTile = FALSE; if (mask) maskInfo->IsTile = FALSE; }