mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-30 08:12:05 +00:00
3926 lines
126 KiB
C++
3926 lines
126 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
*
|
|
* 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 "intl_csi.h"
|
|
#include "prefinfo.h"
|
|
#include "cxprint.h"
|
|
#include "edt.h"
|
|
|
|
#if defined(OJI)
|
|
#include "jvmmgr.h"
|
|
#elif defined(JAVA)
|
|
#include "java.h"
|
|
#endif
|
|
|
|
// These four are all specified in pixels
|
|
#define IMAGE_SMICON_MARGIN 4
|
|
|
|
#define IMAGE_SMICON_WIDTH 14
|
|
#define IMAGE_SMICON_HEIGHT 16
|
|
|
|
#define IMAGE_SMICON_TEXT_OFFSET 2
|
|
|
|
|
|
#define IS_SECOND_TO_LAST_LAYER(layer) (CL_GetLayerBelow(layer) && \
|
|
CL_GetLayerName(CL_GetLayerBelow(layer)) && \
|
|
(strcmp(CL_GetLayerName(CL_GetLayerBelow(layer)), \
|
|
LO_BACKGROUND_LAYER_NAME) == 0))
|
|
|
|
#define LOADBITMAP(id) \
|
|
::LoadBitmap(AfxGetResourceHandle(), MAKEINTRESOURCE(id))
|
|
|
|
CDCCX::CDCCX() {
|
|
// Purpose: Constructor for DC Context
|
|
// Arguments: void
|
|
// Returns: none
|
|
// Comments: Sets the context type basically
|
|
// Revision History:
|
|
// 05-27-95 created GAB
|
|
//
|
|
m_cxType = DeviceContext;
|
|
m_bOwnDC = FALSE;
|
|
m_bClassDC = FALSE;
|
|
|
|
// Our mapping mode will be anisotropic unless those which derive
|
|
// set otherwise.
|
|
m_MM = MM_ANISOTROPIC;
|
|
|
|
m_pPal = NULL;
|
|
m_lWidth = 0;
|
|
m_lHeight = 0;
|
|
m_iOffset = 0;
|
|
CString csNo(SZ_NO);
|
|
|
|
m_pImageDC = NULL;
|
|
curColorSpace = 0;
|
|
|
|
// As a default starting background color, use that of the button face.
|
|
m_rgbBackgroundColor = sysInfo.m_clrBtnFace;
|
|
m_rgbDarkColor = sysInfo.m_clrBtnShadow;
|
|
m_rgbLightColor = sysInfo.m_clrBtnHilite;
|
|
Set3DColors(m_rgbBackgroundColor);
|
|
|
|
// Set that we have no document, and we currently
|
|
// won't autodelete what may get assigned in.
|
|
m_pDocument = NULL;
|
|
m_bAutoDeleteDocument = FALSE;
|
|
|
|
// No previously selected font.
|
|
m_pSelectedCachedFont = NULL;
|
|
m_lastDCWithCachedFont = NULL;
|
|
|
|
// Document has no substance.
|
|
m_lDocWidth = 0;
|
|
m_lDocHeight = 0;
|
|
m_lOrgX = m_lOrgY = 0;
|
|
|
|
|
|
// Start out with some default values in the conversions from pix 2 twips.
|
|
m_lConvertX = 1;
|
|
m_lConvertY = 1;
|
|
GetContext()->convertPixX = 1;
|
|
GetContext()->convertPixY = 1;
|
|
|
|
// Assume the driver doesn't support 565 mode for 16 bpp DIBs
|
|
m_bRGB565 = FALSE;
|
|
|
|
// Allow resolving of layout elements.
|
|
m_bResolveElements = TRUE;
|
|
|
|
// We're not in an OLE server.
|
|
m_bOleServer = FALSE;
|
|
|
|
// Form text entry box font
|
|
m_pFormFixFont = NULL;
|
|
m_pFormPropFont = NULL;
|
|
m_iFormFixCSID = CS_LATIN1;
|
|
m_iFormPropCSID = CS_LATIN1;
|
|
|
|
m_bLoadImagesNow = FALSE;
|
|
m_bNexttimeLoadImagesNow = FALSE;
|
|
|
|
GetContext()->XpixelsPerPoint = 0;
|
|
GetContext()->YpixelsPerPoint = 0;
|
|
}
|
|
|
|
CDCCX::~CDCCX() {
|
|
// Purpose: Destructor for DC Context
|
|
// Arguments: void
|
|
// Returns: none
|
|
// Comments:
|
|
// Revision History:
|
|
// 05-27-95 created GAB
|
|
//
|
|
|
|
// If we've got a document, let it know we're gone now.
|
|
if(GetDocument() != NULL) {
|
|
TRACE("Clearing document context\n");
|
|
GetDocument()->ClearContext();
|
|
}
|
|
|
|
if(m_pImageDC != NULL) {
|
|
if (!IsGridCell()) { // only delete the temporary DC if we are the parent.
|
|
if (m_bUseDibPalColors)
|
|
::SelectPalette(m_pImageDC, (HPALETTE)::GetStockObject(DEFAULT_PALETTE), TRUE);
|
|
VERIFY(::DeleteDC( m_pImageDC));
|
|
}
|
|
}
|
|
|
|
// Do not delete the default palette.
|
|
if(m_pPal && m_pPal != WFE_GetUIPalette(NULL)) {
|
|
VERIFY(::DeleteObject(m_pPal));
|
|
}
|
|
if(m_pDocument != NULL && m_bAutoDeleteDocument == TRUE) {
|
|
// We call OnCloseDocument here, to delete the document.
|
|
// If we do this here, it basically indicates that we created the
|
|
// document ourselves (probably a print context), and it
|
|
// wasn't made in the MFC framework.
|
|
m_pDocument->OnCloseDocument();
|
|
}
|
|
|
|
if (curColorSpace)
|
|
IL_ReleaseColorSpace(curColorSpace);
|
|
}
|
|
|
|
void CDCCX::DestroyContext() {
|
|
if(IsDestroyed() == FALSE) {
|
|
// Give the document a chance to copy any needed information before
|
|
// we go down. This helps the OLE server stuff survive while
|
|
// the context of the view has gone to the twilight zone and back.
|
|
if(GetDocument()) {
|
|
GetDocument()->CacheEphemeralData();
|
|
}
|
|
|
|
// Get rid of all our fonts.
|
|
ClearFontCache();
|
|
}
|
|
|
|
|
|
// Call the base.
|
|
CStubsCX::DestroyContext();
|
|
}
|
|
|
|
BOOL CDCCX::ResolveTextExtent(HDC pDC, LPCTSTR pString, int iLength, LPSIZE pSize, CyaFont *pFont)
|
|
{
|
|
return ResolveTextExtent(
|
|
INTL_GetCSIWinCSID(LO_GetDocumentCharacterSetInfo(GetContext()))
|
|
, pDC, pString, iLength, pSize, pFont);
|
|
}
|
|
|
|
#ifdef XP_WIN32
|
|
static BOOL
|
|
SupportsRGB565(HDC pDC)
|
|
{
|
|
BITMAPINFO *lpBMInfo = NULL;
|
|
int iFlags;
|
|
int nSize = sizeof(BITMAPINFOHEADER) + 3 * sizeof(RGBQUAD);
|
|
LPDWORD lpMasks;
|
|
|
|
// Use the QUERYDIBSUPPORT escape to determine if the driver
|
|
// supports RGB565 format DIBs
|
|
lpBMInfo = (BITMAPINFO *)XP_ALLOC(nSize);
|
|
if (!lpBMInfo)
|
|
return FALSE;
|
|
|
|
memset(lpBMInfo, 0, nSize);
|
|
lpBMInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
|
lpBMInfo->bmiHeader.biWidth = 10;
|
|
lpBMInfo->bmiHeader.biHeight = 10;
|
|
lpBMInfo->bmiHeader.biPlanes = 1;
|
|
lpBMInfo->bmiHeader.biBitCount = 16;
|
|
lpBMInfo->bmiHeader.biCompression = BI_BITFIELDS;
|
|
|
|
// Define the color masks for a RGB565 DIB
|
|
lpMasks = (LPDWORD)lpBMInfo->bmiColors;
|
|
lpMasks[0] = 0xF800; // red color mask
|
|
lpMasks[1] = 0x07E0; // green color mask
|
|
lpMasks[2] = 0x001F; // blue color mask
|
|
|
|
// Ask the driver
|
|
::Escape(pDC, QUERYDIBSUPPORT, nSize, (LPCSTR)lpBMInfo, &iFlags);
|
|
XP_FREE(lpBMInfo);
|
|
|
|
return (iFlags & (QDI_SETDIBITS | QDI_DIBTOSCREEN | QDI_STRETCHDIB)) != 0;
|
|
}
|
|
#endif
|
|
|
|
void CDCCX::PrepareDraw()
|
|
{
|
|
if (m_pImageDC) {
|
|
if (m_bUseDibPalColors && m_pPal)
|
|
::SelectPalette(m_pImageDC, (HPALETTE)GetStockObject(DEFAULT_PALETTE), FALSE);
|
|
::DeleteDC(m_pImageDC);
|
|
}
|
|
m_pImageDC = ::CreateCompatibleDC(GetContextDC());
|
|
if (m_bUseDibPalColors && m_pPal) {
|
|
::SelectPalette(m_pImageDC, m_pPal, FALSE);
|
|
}
|
|
|
|
}
|
|
|
|
void CDCCX::EndDraw()
|
|
{
|
|
if (m_pImageDC) {
|
|
if (m_bUseDibPalColors && m_pPal)
|
|
::SelectPalette(m_pImageDC, (HPALETTE)GetStockObject(DEFAULT_PALETTE), FALSE);
|
|
::DeleteDC(m_pImageDC);
|
|
}
|
|
m_pImageDC = 0;
|
|
}
|
|
|
|
|
|
void CDCCX::Initialize(BOOL bOwnDC, RECT *pRect, BOOL bInitialPalette, BOOL bNewMemDC) {
|
|
// First thing, we need to create a document
|
|
// if no one has bothered assigning us one.
|
|
if(m_pDocument == NULL) {
|
|
m_pDocument = new CGenericDoc();
|
|
m_bAutoDeleteDocument = TRUE; // We clean up.
|
|
}
|
|
|
|
// There exists a document.
|
|
// Let it know which context it can manipulate.
|
|
GetDocument()->SetContext(this);
|
|
|
|
HDC hdc = GetContextDC();
|
|
|
|
// Initialize some values which are used in CDC contexts
|
|
// for drawing purposes.
|
|
SetMappingMode(hdc);
|
|
::SetBkMode(hdc, TRANSPARENT);
|
|
|
|
// Figure out the depth of the CDC.
|
|
m_iBitsPerPixel = sysInfo.m_iBitsPerPixel;
|
|
|
|
// Now, if the bits per pixel are less than 16, and this device doesn't support
|
|
// a palette, then we need to set the bits per pixel to a very high value
|
|
// to emulate true color (so that we don't attempt to use the palette
|
|
// function later on).
|
|
// This is the Epson Stylus Color Printer bug fix on Win16.
|
|
if(m_iBitsPerPixel < 16 && (::GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE) == 0) {
|
|
// 24 is the largest common denominator which we should be able to set
|
|
// in order to avoid palette operations.
|
|
// Uped to 24 from 16 as the Hewlett Packard Laserjet 5L bug fix on Win32.
|
|
m_iBitsPerPixel = 24;
|
|
}
|
|
|
|
// Detect if we are going to be using DibPalColors. We only do this if the device
|
|
// is a palette device and we never do this when printing
|
|
m_bUseDibPalColors = !IsPrintContext() && (::GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE);
|
|
|
|
|
|
// Do some stretch blit setup.
|
|
#ifndef WIN32
|
|
::SetStretchBltMode(hdc, STRETCH_DELETESCANS);
|
|
#else
|
|
::SetStretchBltMode(hdc, COLORONCOLOR);
|
|
#endif
|
|
|
|
JMCException* exc = NULL;
|
|
IMGCB* imageLibObj = IMGCBFactory_Create(&exc);
|
|
|
|
m_pImageGroupContext = IL_NewGroupContext(GetContext(), (IMGCBIF *)imageLibObj);
|
|
GetContext()->img_cx = m_pImageGroupContext; // Need this to be cross platform.
|
|
IL_AddGroupObserver(m_pImageGroupContext, ImageGroupObserver, (void*)GetContext());
|
|
|
|
COLORREF rgbColor = prefInfo.m_rgbBackgroundColor;
|
|
SetTransparentColor(GetRValue(rgbColor), GetGValue(rgbColor), GetBValue(rgbColor));
|
|
if (!IsGridCell()) {
|
|
if(m_iBitsPerPixel < 16) {
|
|
|
|
// Set the transparency to a default color.
|
|
// This may change below.
|
|
SetTransparentColor(192, 192, 192);
|
|
|
|
// 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);
|
|
if (bInitialPalette)
|
|
m_pPal = CDCCX::InitPalette(hdc);
|
|
else // If we don't want to initialize the Palette, use the default palette.
|
|
m_pPal = WFE_GetUIPalette(NULL);
|
|
CDCCX::SetColormap(hdc, defaultColorMap, rgbTransparentColor, m_pPal);
|
|
curColorSpace = IL_CreatePseudoColorSpace(defaultColorMap, MAX_IMAGE_PALETTE_ENTRIES+1,
|
|
m_iBitsPerPixel);
|
|
HPALETTE hOldPal = NULL;
|
|
if(m_pPal) {
|
|
if ( bInitialPalette)
|
|
hOldPal = (HPALETTE) ::SelectPalette(hdc, m_pPal, FALSE);
|
|
else
|
|
hOldPal = (HPALETTE) ::SelectPalette(hdc, m_pPal, TRUE);
|
|
int error = RealizePalette(hdc); // In with the new
|
|
}
|
|
#ifdef DEBUG_mhwang
|
|
HWND hwnd = ::GetFocus();
|
|
#endif
|
|
|
|
}
|
|
else { // use RGB value
|
|
IL_RGBBits colorRGBBits;
|
|
// Enable true color.
|
|
if(m_iBitsPerPixel >= 16) {
|
|
if(m_iBitsPerPixel == 16) {
|
|
#ifdef XP_WIN32
|
|
// If this is Win95 we need to do rounding during quantization of
|
|
// 24 bpp RGB values to 16 bpp RGB values
|
|
if (sysInfo.IsWin4_32() == TRUE &&
|
|
SupportsRGB565(hdc) != FALSE &&
|
|
IsPrintContext() == FALSE) {
|
|
|
|
// Metafiles can't handle this hack.
|
|
// Also, the image lib will force metafiles to share the
|
|
// same image even though the settings would be slightly different.
|
|
// Pump us up to 24 bit images in this case.
|
|
if(GetContextType() == MetaFile) {
|
|
colorRGBBits.red_shift = 16;
|
|
colorRGBBits.red_bits = 8; /* Offset for red channel bits. */
|
|
colorRGBBits.green_shift = 8; /* Number of bits assigned to green channel. */
|
|
colorRGBBits.green_bits = 8; /* Offset for green channel bits. */
|
|
colorRGBBits.blue_shift = 0; /* Number of bits assigned to blue channel. */
|
|
colorRGBBits.blue_bits = 8; /* Offset for blue channel bits. */
|
|
curColorSpace = IL_CreateTrueColorSpace(&colorRGBBits, 24);
|
|
|
|
}
|
|
else {
|
|
m_bRGB565 = TRUE; // remember this when building BITMAPINFO struct
|
|
colorRGBBits.red_shift = 11;
|
|
colorRGBBits.red_bits = 5; /* Offset for red channel bits. */
|
|
colorRGBBits.green_shift = 5; /* Number of bits assigned to green channel. */
|
|
colorRGBBits.green_bits = 6; /* Offset for green channel bits. */
|
|
colorRGBBits.blue_shift = 0; /* Number of bits assigned to blue channel. */
|
|
colorRGBBits.blue_bits = 5; /* Offset for blue channel bits. */
|
|
curColorSpace = IL_CreateTrueColorSpace(&colorRGBBits, 16);
|
|
}
|
|
|
|
} else {
|
|
colorRGBBits.red_shift = 10;
|
|
colorRGBBits.red_bits = 5; /* Offset for red channel bits. */
|
|
colorRGBBits.green_shift = 5; /* Number of bits assigned to green channel. */
|
|
colorRGBBits.green_bits = 5; /* Offset for green channel bits. */
|
|
colorRGBBits.blue_shift = 0; /* Number of bits assigned to blue channel. */
|
|
colorRGBBits.blue_bits = 5; /* Offset for blue channel bits. */
|
|
curColorSpace =IL_CreateTrueColorSpace(&colorRGBBits, 16);
|
|
}
|
|
#else
|
|
// 16 bpp DIB format isn't supported by all drivers in Win 3.1
|
|
colorRGBBits.red_shift = 16;
|
|
colorRGBBits.red_bits = 8; /* Offset for red channel bits. */
|
|
colorRGBBits.green_shift = 8; /* Number of bits assigned to green channel. */
|
|
colorRGBBits.green_bits = 8; /* Offset for green channel bits. */
|
|
colorRGBBits.blue_shift = 0; /* Number of bits assigned to blue channel. */
|
|
colorRGBBits.blue_bits = 8; /* Offset for blue channel bits. */
|
|
curColorSpace = IL_CreateTrueColorSpace(&colorRGBBits, 24);
|
|
#endif
|
|
}
|
|
else {
|
|
colorRGBBits.red_shift = 16;
|
|
colorRGBBits.red_bits = 8; /* Offset for red channel bits. */
|
|
colorRGBBits.green_shift = 8; /* Number of bits assigned to green channel. */
|
|
colorRGBBits.green_bits = 8; /* Offset for green channel bits. */
|
|
colorRGBBits.blue_shift = 0; /* Number of bits assigned to blue channel. */
|
|
colorRGBBits.blue_bits = 8; /* Offset for blue channel bits. */
|
|
curColorSpace = IL_CreateTrueColorSpace(&colorRGBBits, 24);
|
|
}
|
|
}
|
|
}
|
|
GetContext()->color_space = curColorSpace; // Need this to be cross platform.
|
|
}
|
|
else {
|
|
MWContext* cxtx = GetParentContext();
|
|
GetContext()->color_space = cxtx->color_space;
|
|
curColorSpace =cxtx->color_space;
|
|
IL_AddRefToColorSpace(curColorSpace);
|
|
m_bRGB565 = CXDC(cxtx)->m_bRGB565;
|
|
}
|
|
|
|
IL_AddRefToColorSpace(GetContext()->color_space);
|
|
// Get image prefs on a per context basis.
|
|
IL_DitherMode ditherMode = IL_Auto;
|
|
|
|
char * prefStr=NULL;
|
|
PREF_CopyCharPref("images.dither",&prefStr);
|
|
// Images
|
|
if (prefStr) {
|
|
if(!strcmpi(prefStr,"yes")) {
|
|
ditherMode = IL_Dither;
|
|
} else if(!strcmpi(prefStr,"no")) { // closest
|
|
ditherMode = IL_ClosestColor;
|
|
} else {
|
|
ditherMode = IL_Auto;
|
|
}
|
|
XP_FREE(prefStr);
|
|
}
|
|
|
|
PRBool bIncremental = ResolveIncrementalImages();
|
|
IL_DisplayData displayData;
|
|
displayData.dither_mode = IL_Auto;
|
|
|
|
if (IsPrintContext())
|
|
displayData.display_type = IL_Printer;
|
|
else
|
|
displayData.display_type = IL_Console;
|
|
displayData.color_space = curColorSpace;
|
|
displayData.progressive_display= bIncremental;
|
|
IL_SetDisplayMode(m_pImageGroupContext, IL_PROGRESSIVE_DISPLAY | IL_DITHER_MODE | IL_COLOR_SPACE | IL_DISPLAY_TYPE,
|
|
&displayData);
|
|
|
|
if (bNewMemDC) {
|
|
if (!IsGridCell()) { // only create the tempary CD only for gird parent.
|
|
// Ensure our memory DC exists for speedy image draws.
|
|
m_pImageDC = ::CreateCompatibleDC(hdc);
|
|
if (m_bUseDibPalColors && m_pPal) {
|
|
::SelectPalette(m_pImageDC, m_pPal, FALSE);
|
|
}
|
|
}
|
|
else {
|
|
MWContext *parentContext = GetParentContext();
|
|
m_pImageDC = CXDC(parentContext)->m_pImageDC;
|
|
}
|
|
}
|
|
GetContext()->XpixelsPerPoint = ((double)GetDeviceCaps (GetAttribDC(), LOGPIXELSX)) / 72.0 ;
|
|
GetContext()->YpixelsPerPoint = ((double)GetDeviceCaps (GetAttribDC(), LOGPIXELSY)) / 72.0 ;
|
|
|
|
#ifdef DEBUG_aliu
|
|
double dd = ((double)GetDeviceCaps (hdc, LOGPIXELSX)) / 72.0 ;
|
|
dd = ((double)GetDeviceCaps (hdc, LOGPIXELSY)) / 72.0 ;
|
|
#endif
|
|
|
|
ReleaseContextDC(hdc);
|
|
|
|
// We optimize those DCs which we know are persistant (don't change or reset
|
|
// their values) for font caching and other stuff.
|
|
// As a default, consider all such DC classes as persistent, if not, then
|
|
// set this value otherwise.
|
|
// This needs to go at the end of this function, since the mapping mode should
|
|
// now be correctly set, et al....
|
|
m_bOwnDC = bOwnDC;
|
|
|
|
#ifdef LAYERS
|
|
GetContext()->compositor = NULL;
|
|
#endif // LAYERS
|
|
|
|
}
|
|
|
|
// Default implementation of incremental image display switch.
|
|
PRBool CDCCX::ResolveIncrementalImages()
|
|
{
|
|
XP_Bool bRetval = prefInfo.m_bAutoLoadImages;
|
|
|
|
return (bRetval) ? PR_TRUE : PR_FALSE;
|
|
}
|
|
|
|
HPALETTE CDCCX::GetPalette() const {
|
|
// Return our palette.
|
|
return(m_pPal);
|
|
}
|
|
|
|
|
|
void CDCCX::ClearFontCache() {
|
|
// If we're a persistant DC, we need to select a stock object before we release
|
|
// all the fonts.
|
|
if(IsClassDC() || IsOwnDC()) {
|
|
HDC hdc = GetContextDC();
|
|
::SelectObject(hdc, ::GetStockObject(ANSI_FIXED_FONT));
|
|
ReleaseContextDC(hdc);
|
|
|
|
// We have no previously selected font.
|
|
m_pSelectedCachedFont = NULL;
|
|
m_lastDCWithCachedFont = NULL;
|
|
|
|
}
|
|
|
|
#ifdef MOZ_NGLAYOUT
|
|
XP_ASSERT(0);
|
|
#else
|
|
// Tell layout to get rid of all of it's cached FE font data
|
|
// in the LO_TextAttr.
|
|
LO_InvalidateFontData(GetDocumentContext());
|
|
#endif
|
|
|
|
|
|
// Go through our context list of cached fonts and get rid of them all.
|
|
POSITION rIndexnew = m_cplCachedFontList.GetHeadPosition();
|
|
CyaFont *pCachedFont = NULL;
|
|
while(rIndexnew) {
|
|
pCachedFont = (CyaFont *)m_cplCachedFontList.GetNext(rIndexnew);
|
|
if(pCachedFont) {
|
|
delete pCachedFont;
|
|
}
|
|
}
|
|
// Remove them all from the list.
|
|
if(!m_cplCachedFontList.IsEmpty()) {
|
|
m_cplCachedFontList.RemoveAll();
|
|
}
|
|
|
|
// Get rid of widget fonts.
|
|
if(m_pFormFixFont) {
|
|
VERIFY(::DeleteObject(m_pFormFixFont));
|
|
m_pFormFixFont = NULL;
|
|
}
|
|
if(m_pFormPropFont) {
|
|
VERIFY(::DeleteObject(m_pFormPropFont));
|
|
m_pFormPropFont = NULL;
|
|
}
|
|
}
|
|
|
|
void CDCCX::ClearAllFontCaches() {
|
|
MWContext *pTraverseContext = NULL;
|
|
CAbstractCX *pTraverseCX = NULL;
|
|
XP_List *pTraverse = XP_GetGlobalContextList();
|
|
while (pTraverseContext = (MWContext *)XP_ListNextObject(pTraverse)) {
|
|
if(pTraverseContext != NULL && ABSTRACTCX(pTraverseContext) != NULL) {
|
|
pTraverseCX = ABSTRACTCX(pTraverseContext);
|
|
|
|
if(pTraverseCX->IsDCContext() == TRUE) {
|
|
CDCCX *pDCCX = VOID2CX(pTraverseCX, CDCCX);
|
|
pDCCX->ClearFontCache();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// size is the size of the font from layout
|
|
// iBaseSize is the users font size from the encoding
|
|
// iOffset is the offset based on increment and decrement font
|
|
double CDCCX::CalcFontPointSize(int size, int iBaseSize, int iOffset)
|
|
{
|
|
double dFontSize;
|
|
|
|
if( iBaseSize <=0 )
|
|
iBaseSize = 10;
|
|
|
|
/* size += iOffset;*/
|
|
if(size < 0)
|
|
size = 0;
|
|
|
|
if(size > 8)
|
|
size = 8;
|
|
|
|
switch(size) {
|
|
case 0:
|
|
dFontSize = iBaseSize / 2;
|
|
break;
|
|
case 1:
|
|
dFontSize = 7 * iBaseSize / 10;
|
|
break;
|
|
case 2:
|
|
dFontSize = 85 * iBaseSize / 100;
|
|
break;
|
|
case 4:
|
|
dFontSize = 12 * iBaseSize / 10;
|
|
break;
|
|
case 5:
|
|
dFontSize = 3 * iBaseSize / 2;
|
|
break;
|
|
case 6:
|
|
dFontSize = 2 * iBaseSize;
|
|
break;
|
|
case 7:
|
|
dFontSize = 3 * iBaseSize;
|
|
break;
|
|
case 8:
|
|
dFontSize = 4 * iBaseSize;
|
|
break;
|
|
case 3:
|
|
default:
|
|
dFontSize = iBaseSize;
|
|
}
|
|
|
|
//if(MMIsText() != TRUE) // for printer scaling to pointsize interface.
|
|
// dFontSize *= 2.8; //todo this is a hack!!
|
|
|
|
if(GetContext())
|
|
dFontSize *= GetContext()->fontScalingPercentage;
|
|
|
|
return dFontSize;
|
|
|
|
} // CalcFontPointSize
|
|
|
|
|
|
// Manage DC level font cache: If font is selected into dc, don't do anything.
|
|
// Otherwise, call SelectNetscapeFont() and cache it into dc.
|
|
// return 1 if we miss any font in pAttr->font_face list.
|
|
int CDCCX::SelectNetscapeFontWithCache( HDC hdc, LO_TextAttr *pAttr, CyaFont *& pMyFont )
|
|
{
|
|
// Purpose: Font selector
|
|
// Arguments: pDC The DC in which to select the font
|
|
// pAttr Layout attributes by which we select the font.
|
|
// pSelected This is more of a return value. It sets the reference of
|
|
// the pointer value ot the font actually selected.
|
|
// Returns: no meaning, old font is saved in CyaFont.
|
|
// Comments:
|
|
|
|
// Determine the size of the font and other stuff.
|
|
// Get the font out of the cache.
|
|
int returnCode = 0; // assuming we don't miss any font.
|
|
// #ifdef nofontcache
|
|
CyaFont *pCachedFont = (CyaFont *)pAttr->FE_Data;
|
|
pMyFont = pCachedFont;
|
|
// See if we've already got this font selected if we're a persistant DC.
|
|
// We'll assume it's in the font cache if so.
|
|
if(IsOwnDC() == TRUE && m_lastDCWithCachedFont == hdc && m_pSelectedCachedFont) {
|
|
if( m_pSelectedCachedFont == pCachedFont) {
|
|
// Simply return, already selected.
|
|
return( 0 );
|
|
} else {
|
|
// relase the selected font.
|
|
ReleaseNetscapeFont( hdc, m_pSelectedCachedFont );
|
|
m_pSelectedCachedFont = NULL;
|
|
m_lastDCWithCachedFont = NULL;
|
|
// fall through to select a font.
|
|
}
|
|
}
|
|
|
|
// create font (or use FE_Data cached font) for the text
|
|
returnCode = SelectNetscapeFont( hdc, pAttr, pMyFont );
|
|
|
|
if( ! pMyFont->IsEmptyFont() ) {
|
|
|
|
// If this is a persistant DC, then we mark the font currently selected so that
|
|
// we don't select it again if the same request comes in.
|
|
// We don't want to do this if this was the memory DC we're dealing with.
|
|
if(IsOwnDC() == TRUE) {
|
|
m_lastDCWithCachedFont = hdc;
|
|
m_pSelectedCachedFont = pMyFont; // pSelectThis;
|
|
}
|
|
}
|
|
//#else
|
|
// returnCode = SelectNetscapeFont( hdc, pAttr, pMyFont );
|
|
//#endif // nofontcache
|
|
|
|
return( returnCode );
|
|
|
|
}
|
|
|
|
// SelectNetscapeFont() does:
|
|
// always select the font into dc.
|
|
// manage FE_Data level cache.
|
|
// Create the font if not cached,
|
|
// follow font list and use default font at last.
|
|
// return 1 if the any font in list not found.
|
|
// After creation,
|
|
// cache it into FE_Data, and calculate meanwidth.
|
|
// link-list the font, so it can be deleted when destroy document.
|
|
int CDCCX::SelectNetscapeFont( HDC hdc, LO_TextAttr *pAttr, CyaFont *& pMyFont )
|
|
{
|
|
#ifdef MOZ_NGLAYOUT
|
|
XP_ASSERT(0);
|
|
return 0;
|
|
#else
|
|
// create font for the text and cache it in pAttr->FE_Data.
|
|
EncodingInfo *pEncoding = theApp.m_pIntlFont->GetEncodingInfo(GetContext());
|
|
BOOL bItalic = FALSE;
|
|
BOOL bFixed = FALSE;
|
|
int iFontWeight = FW_NORMAL;
|
|
double dFontSize;
|
|
int iBaseSize;
|
|
int iCharset = DEFAULT_CHARSET; // used for Win95 font selection
|
|
char aFontName[MAXFONTFACENAME];
|
|
char * pCharsetStr;
|
|
int reCode;
|
|
int returnCode = 0; // assuming we don't miss any font.
|
|
|
|
CyaFont *pCachedFont = (CyaFont *)pAttr->FE_Data;
|
|
if(pCachedFont != NULL && ! pCachedFont->IsEmptyFont() ) {
|
|
// It's cached.
|
|
|
|
// use the old font, and select the font.
|
|
pMyFont = pCachedFont;
|
|
pMyFont->PrepareDrawText( hdc ); // actually, select the font into hdc
|
|
return( 0 ); // we don't miss this font.
|
|
}
|
|
|
|
// retrieve face-name-independent attributes first.
|
|
|
|
if(pAttr->fontmask & LO_FONT_BOLD) {
|
|
iFontWeight = FW_BOLD;
|
|
}
|
|
|
|
// font_weight has the highest priority.
|
|
if( pAttr->font_weight > 0 )
|
|
iFontWeight = pAttr->font_weight;
|
|
|
|
if(pAttr->fontmask & LO_FONT_ITALIC) {
|
|
bItalic = TRUE;
|
|
}
|
|
|
|
if(pAttr->fontmask & LO_FONT_FIXED) {
|
|
bFixed = TRUE;
|
|
}
|
|
|
|
if( bFixed) {
|
|
iBaseSize = pEncoding->iFixSize;
|
|
iCharset = pEncoding->iFixCharset;
|
|
} else { // ! bFixed
|
|
iBaseSize = pEncoding->iPropSize;
|
|
iCharset = pEncoding->iPropCharset;
|
|
}
|
|
|
|
// Map the base size to the real font size.
|
|
dFontSize = CalcFontPointSize(pAttr->size, iBaseSize, m_iOffset);
|
|
|
|
// pAttr->point_size has the highest priority.
|
|
if( pAttr->point_size > 0 ) {
|
|
dFontSize = pAttr->point_size;
|
|
}
|
|
|
|
// save the encording flag in font, so it will use textOutW() for Unicode.
|
|
// refer to BOOL CIntlWin::TextOut() in file intlwin.cpp
|
|
// INTL_GetCSIWinCSID(LO_GetDocumentCharacterSetInfo(pContext))
|
|
char *pEncordingStr = NULL;
|
|
int isUnicode = 0;
|
|
#ifdef XP_WIN32
|
|
if ( CIntlWin::UseUnicodeFontAPI( pEncoding->iCSID )) {
|
|
// set the encording to use ::TextOutW()
|
|
pEncordingStr = "Unicode";
|
|
isUnicode = 1;
|
|
}
|
|
#endif
|
|
|
|
int nUnderline = nfUnderlineDontCare ;
|
|
if(pAttr->attrmask & LO_ATTR_ANCHOR) {
|
|
XP_Bool prefBool = prefInfo.m_bUnderlineAnchors; // ? prefInfo.m_bUnderlineAnchors->m_Value.xp_bool : TRUE;
|
|
if(prefBool)
|
|
nUnderline = nfUnderlineYes;
|
|
}
|
|
if(pAttr->attrmask & LO_ATTR_UNDERLINE) {
|
|
nUnderline = nfUnderlineYes;
|
|
}
|
|
|
|
pMyFont = new CyaFont();
|
|
|
|
// If a font name is listed, use that instead.
|
|
BOOL bUseDefault = TRUE;
|
|
|
|
if(pAttr->font_face) {
|
|
// Go through the comma delimeted list, and find one that we have.
|
|
char wantedFontName[MAXFONTFACENAME];
|
|
char *pFontName = NULL;
|
|
int offSet = 0;
|
|
do {
|
|
offSet = FEU_ExtractCommaDilimetedFontName(pAttr->font_face, offSet, wantedFontName );
|
|
|
|
// for(int iTraverse = 1; pExtracted = FEU_ExtractCommaDilimetedString(pAttr->font_face, iTraverse); iTraverse++)
|
|
if( offSet > 0 && *wantedFontName != 0) {
|
|
pFontName = theGlobalNSFont.converGenericFont(wantedFontName);
|
|
|
|
strcpy(aFontName, pFontName);
|
|
if(CIntlWin::UseUnicodeFontAPI(pEncoding->iCSID)) {
|
|
iCharset = DEFAULT_CHARSET;
|
|
}
|
|
// On Win95, charset info is important for Wingdings font
|
|
if (sysInfo.m_bWin4 && (strcmpi(aFontName, "wingdings") == 0))
|
|
iCharset = DEFAULT_CHARSET;
|
|
// web font use string for charSet
|
|
pCharsetStr = theGlobalNSFont.convertToFmiCharset( iCharset );
|
|
|
|
if (isUnicode == 0 )
|
|
{
|
|
pEncordingStr = pCharsetStr;
|
|
}
|
|
|
|
// Create the font.
|
|
reCode = pMyFont->CreateNetscapeFont(
|
|
GetContext(),
|
|
hdc, // HDC hDC,
|
|
aFontName, // char *FmiName,
|
|
pCharsetStr, // char *FmiCharset,
|
|
pEncordingStr, // char *FmiEncoding,
|
|
iFontWeight, // int FmiWeight,
|
|
bFixed?nfSpacingMonospaced:nfSpacingProportional, // int FmiPitch,
|
|
bItalic?nfStyleItalic:nfStyleNormal, // int FmiStyle,
|
|
nUnderline, // int FmiUnderline,
|
|
(pAttr->attrmask & LO_ATTR_STRIKEOUT) ? nfStrikeOutYes : nfStrikeOutDontCare, // int FmiStrikeOut,
|
|
0, // int FmiResolutionX,
|
|
::GetDeviceCaps(GetAttribDC(), LOGPIXELSY), // int FmiResolutionY,
|
|
dFontSize // int fontHeight // not a fmi field
|
|
);
|
|
|
|
//if( theGlobalNSFont.HasFaceName( hdc, pExtracted))
|
|
// Use this.
|
|
if( reCode == FONTERR_OK ) {
|
|
bUseDefault = FALSE; // we got the font!
|
|
} else {
|
|
// remenber there is font face name not found,
|
|
returnCode = 1;
|
|
}
|
|
}
|
|
|
|
// Our responsibility to clean this up.
|
|
// XP_FREE(pExtracted);
|
|
|
|
// If we've set that we're using a font, get out.
|
|
if(!bUseDefault) {
|
|
break;
|
|
}
|
|
} while ( offSet > 0 ); // do offSet = FEU_ExtractCommaDilimetedFontName() ...
|
|
} // if(pAttr->font_face)
|
|
|
|
if(bUseDefault) {
|
|
if( bFixed)
|
|
strcpy(aFontName, pEncoding->szFixName);
|
|
else // ! bFixed
|
|
strcpy(aFontName, pEncoding->szPropName);
|
|
|
|
if(CIntlWin::UseUnicodeFontAPI(pEncoding->iCSID)) {
|
|
iCharset = DEFAULT_CHARSET;
|
|
}
|
|
// On Win95, charset info is important for Wingdings font
|
|
if (sysInfo.m_bWin4 && (strcmpi(aFontName, "wingdings") == 0))
|
|
iCharset = DEFAULT_CHARSET;
|
|
// web font use string for charSet
|
|
pCharsetStr = theGlobalNSFont.convertToFmiCharset( iCharset );
|
|
if (isUnicode == 0 )
|
|
{
|
|
pEncordingStr = pCharsetStr;
|
|
}
|
|
|
|
// Create the font.
|
|
reCode = pMyFont->CreateNetscapeFont(
|
|
GetContext(),
|
|
hdc, // HDC hDC,
|
|
aFontName, // char *FmiName,
|
|
pCharsetStr, // char *FmiCharset,
|
|
pEncordingStr, // char *FmiEncoding,
|
|
iFontWeight, // int FmiWeight,
|
|
bFixed?nfSpacingMonospaced:nfSpacingProportional, // int FmiPitch,
|
|
bItalic?nfStyleItalic:nfStyleNormal, // int FmiStyle,
|
|
nUnderline, // int FmiUnderline,
|
|
(pAttr->attrmask & LO_ATTR_STRIKEOUT) ? nfStrikeOutYes : nfStrikeOutDontCare, // int FmiStrikeOut,
|
|
0, // int FmiResolutionX,
|
|
::GetDeviceCaps(GetAttribDC(), LOGPIXELSY), // int FmiResolutionY,
|
|
dFontSize // int fontHeight // not a fmi field
|
|
);
|
|
}
|
|
|
|
if( FONTERR_OK != reCode ) {
|
|
// user selected default font failed, use hardcoded default font
|
|
iCharset = DEFAULT_CHARSET;
|
|
|
|
// web font use string for charSet
|
|
pCharsetStr = theGlobalNSFont.convertToFmiCharset( iCharset );
|
|
if (isUnicode == 0 )
|
|
{
|
|
pEncordingStr = pCharsetStr;
|
|
}
|
|
|
|
// get the face name
|
|
#ifdef _WIN32
|
|
LOGFONT theLogFont;
|
|
CFont *pCFont= CFont::FromHandle((HFONT)GetStockObject(bFixed?ANSI_FIXED_FONT:ANSI_VAR_FONT));
|
|
pCFont->GetLogFont( &theLogFont );
|
|
strncpy(aFontName, theLogFont.lfFaceName,LF_FACESIZE);
|
|
#else
|
|
strncpy(aFontName, ( bFixed? "Courier New" : "Times New Roman" ) ,LF_FACESIZE);
|
|
#endif
|
|
// Create the font.
|
|
reCode = pMyFont->CreateNetscapeFont(
|
|
GetContext(),
|
|
hdc, // HDC hDC,
|
|
aFontName, // char *FmiName,
|
|
pCharsetStr, // char *FmiCharset,
|
|
pEncordingStr, // char *FmiEncoding,
|
|
iFontWeight, // int FmiWeight,
|
|
bFixed?nfSpacingMonospaced:nfSpacingProportional, // int FmiPitch,
|
|
bItalic?nfStyleItalic:nfStyleNormal, // int FmiStyle,
|
|
nUnderline, // int FmiUnderline,
|
|
(pAttr->attrmask & LO_ATTR_STRIKEOUT) ? nfStrikeOutYes : nfStrikeOutDontCare, // int FmiStrikeOut,
|
|
0, // int FmiResolutionX,
|
|
::GetDeviceCaps(GetAttribDC(), LOGPIXELSY), // int FmiResolutionY,
|
|
dFontSize // int fontHeight // not a fmi field
|
|
);
|
|
}
|
|
|
|
// if( FONTERR_OK != reCode ) real problem, todo show dialog to user!!!
|
|
|
|
// Select the font.
|
|
pMyFont->PrepareDrawText( hdc ); // actually, select the font into hdc
|
|
|
|
pMyFont->CalculateMeanWidth( hdc, isUnicode);
|
|
|
|
// and cache it in pAttr->FE_Data.
|
|
// Cache this font for future usage.
|
|
// First, make sure that the text attribute points to it.
|
|
pAttr->FE_Data = (void *)pMyFont;
|
|
|
|
// Second, add it to our context list of fonts (so we know to delete it later).
|
|
m_cplCachedFontList.AddTail((void *)pMyFont); // pSelectThis
|
|
|
|
return( returnCode );
|
|
#endif /* MOZ_NGLAYOUT */
|
|
} // HFONT CDCCX::SelectNetscapeFont()
|
|
|
|
void CDCCX::ReleaseNetscapeFontWithCache(HDC hdc, CyaFont * pNetscapeFont)
|
|
{
|
|
//#ifdef nofontcache
|
|
if( IsOwnDC() == TRUE )
|
|
return;
|
|
m_pSelectedCachedFont = NULL;
|
|
m_lastDCWithCachedFont = NULL;
|
|
|
|
//#endif
|
|
ReleaseNetscapeFont(hdc, pNetscapeFont);
|
|
}
|
|
|
|
void CDCCX::ReleaseNetscapeFont(HDC hdc, CyaFont * pNetscapeFont)
|
|
{
|
|
#ifdef MOZ_NGLAYOUT
|
|
XP_ASSERT(0);
|
|
#else
|
|
pNetscapeFont->EndDrawText( hdc ); // restore the old font.
|
|
#endif /* MOZ_NGLAYOUT */
|
|
}
|
|
|
|
// m_iOffset can be at most 8 or at least -8 based on the values in
|
|
// CalcFontPointSize;
|
|
void CDCCX::ChangeFontOffset(int iIncrementor)
|
|
{
|
|
/* BOOL bDontReload = (m_iOffset == 8 && iIncrementor >= 0) || (m_iOffset == -8 && iIncrementor <= 0);
|
|
|
|
m_iOffset += iIncrementor;
|
|
if(m_iOffset < -8)
|
|
m_iOffset = -8;
|
|
else if(m_iOffset > 8)
|
|
m_iOffset = 8;
|
|
|
|
if(!bDontReload)*/
|
|
|
|
m_iOffset += iIncrementor;
|
|
if(GetContext()){
|
|
#ifdef MOZ_NGLAYOUT
|
|
XP_ASSERT(0);
|
|
#else
|
|
GetContext()->fontScalingPercentage = LO_GetScalingFactor(m_iOffset);
|
|
#endif
|
|
}
|
|
|
|
NiceReload();
|
|
}
|
|
|
|
|
|
|
|
void CDCCX::ExtendCoord(LTRB& Rect)
|
|
{
|
|
int32 lOrgX, lOrgY;
|
|
|
|
GetDrawingOrigin(&lOrgX, &lOrgY);
|
|
|
|
Rect.left += lOrgX;
|
|
Rect.top += lOrgY;
|
|
Rect.right += lOrgX;
|
|
Rect.bottom += lOrgY;
|
|
}
|
|
|
|
BOOL CDCCX::ResolveElement(LTRB& Rect, int32 x, int32 y, int32 x_offset, int32 y_offset,
|
|
int32 width, int32 height)
|
|
{
|
|
BOOL bRetval = TRUE;
|
|
// First, figure the coordinates.
|
|
Rect.left = x + x_offset - m_lOrgX;
|
|
Rect.top = y + y_offset - m_lOrgY;
|
|
Rect.right = Rect.left + width;
|
|
Rect.bottom = Rect.top + height;
|
|
|
|
ExtendCoord(Rect);
|
|
|
|
// Return FALSE if this doesn't fall into view of the context.
|
|
if(Rect.top > m_lHeight || Rect.bottom < 0 || Rect.right < 0 || Rect.left > m_lWidth) {
|
|
if(CanBlockDisplay()) {
|
|
bRetval = FALSE;
|
|
}
|
|
}
|
|
return bRetval;
|
|
}
|
|
BOOL CDCCX::ResolveElement(LTRB& Rect, LO_TextStruct *pText, int iLocation, int32 lStartPos, int32 lEndPos, int iClear) {
|
|
#ifdef MOZ_NGLAYOUT
|
|
XP_ASSERT(0);
|
|
return FALSE;
|
|
#else
|
|
BOOL bRetval = TRUE;
|
|
|
|
// Subtext, in order to be considered at all, must first pass the text resolution.
|
|
if(ResolveElement(Rect, pText->x, pText->y, pText->x_offset,
|
|
pText->y_offset,pText->width, pText->height)) {
|
|
// Adjust the coordinates further for the specific subtext we're going to be
|
|
// drawing.
|
|
// This means we actually have to size the text....
|
|
HDC hdc = GetContextDC();
|
|
|
|
CyaFont *pMyFont;
|
|
SelectNetscapeFontWithCache( hdc, pText->text_attr, pMyFont );
|
|
CSize sz;
|
|
ResolveTextExtent(hdc, (const char *)pText->text, CASTINT(lStartPos), &sz, pMyFont);
|
|
Rect.left += sz.cx;
|
|
ResolveTextExtent(hdc, (const char *)pText->text + lStartPos, CASTINT(lEndPos - lStartPos + 1), &sz, pMyFont);
|
|
Rect.right = Rect.left + sz.cx;
|
|
|
|
Rect.bottom = Rect.top + sz.cy;
|
|
|
|
ReleaseNetscapeFontWithCache( hdc, pMyFont );
|
|
|
|
ReleaseContextDC(hdc);
|
|
|
|
// Return FALSE if this doesn't fall into view of the context.
|
|
if(Rect.top > m_lHeight || Rect.bottom < 0 || Rect.right < 0 || Rect.left > m_lWidth) {
|
|
if(CanBlockDisplay()) {
|
|
bRetval = FALSE;
|
|
}
|
|
}
|
|
}
|
|
else if(CanBlockDisplay()) {
|
|
// Didn't pass even the normal text filter.
|
|
bRetval = FALSE;
|
|
}
|
|
|
|
return(bRetval);
|
|
#endif /* MOZ_NGLAYOUT */
|
|
}
|
|
|
|
/*
|
|
* Note that this was brought back, since form element positions are
|
|
* expressed in document coordinates, not layer coordinates, so the
|
|
* standard ResolveElement techniques will not work.
|
|
*/
|
|
BOOL CDCCX::ResolveElement(LTRB& Rect, LO_FormElementStruct *pFormElement) {
|
|
BOOL bRetval = TRUE;
|
|
|
|
// First, figure the coordinates.
|
|
Rect.left = pFormElement->x + pFormElement->x_offset - m_lOrgX;
|
|
Rect.top = pFormElement->y + pFormElement->y_offset - m_lOrgY;
|
|
Rect.right = Rect.left + pFormElement->width;
|
|
Rect.bottom = Rect.top + pFormElement->height;
|
|
|
|
/* Don't call ExtendCoord() for forms. Form element positions are in
|
|
document coordinates, not layer coordinates. */
|
|
|
|
// Return FALSE if this doesn't fall into view of the context.
|
|
if(Rect.top > m_lHeight || Rect.bottom < 0 || Rect.right < 0 || Rect.left > m_lWidth) {
|
|
if(CanBlockDisplay()) {
|
|
bRetval = FALSE;
|
|
}
|
|
}
|
|
|
|
return(bRetval);
|
|
}
|
|
|
|
BOOL CDCCX::ResolveElement(LTRB& Rect, NI_Pixmap *pImage, int32 lX, int32 lY,
|
|
int32 orgx, int32 orgy,
|
|
uint32 ulWidth, uint32 ulHeight,
|
|
int32 lScaleWidth, int32 lScaleHeight)
|
|
{
|
|
BOOL bRetval = TRUE;
|
|
|
|
/* Use the size of the image if size not provided. */
|
|
if(ulWidth == 0) {
|
|
ulWidth = pImage->header.width;
|
|
}
|
|
|
|
if(ulHeight == 0) {
|
|
ulHeight = pImage->header.height;
|
|
}
|
|
|
|
/* Scaled size overrides further if this is a print context.*/
|
|
if(IsPrintContext()) {
|
|
if(lScaleWidth) {
|
|
ulWidth = (uint32)lScaleWidth;
|
|
}
|
|
if(lScaleHeight) {
|
|
ulHeight = (uint32)lScaleHeight;
|
|
}
|
|
}
|
|
|
|
Rect.left = orgx + lX - m_lOrgX;
|
|
Rect.top = orgy + lY - m_lOrgY;
|
|
|
|
ExtendCoord(Rect);
|
|
|
|
if (Rect.top < 0 && lX) Rect.top = 0;
|
|
if (Rect.left < 0 && lY) Rect.left = 0;
|
|
|
|
Rect.right = Rect.left + ulWidth;
|
|
Rect.bottom = Rect.top + ulHeight;
|
|
|
|
return(bRetval);
|
|
}
|
|
|
|
BOOL CDCCX::ResolveElement(LTRB& Rect, LO_TableStruct *pTable, int iLocation) {
|
|
BOOL bRetval = TRUE;
|
|
|
|
// First, figure the coordinates.
|
|
Rect.left = pTable->x + pTable->x_offset - m_lOrgX;
|
|
Rect.top = pTable->y + pTable->y_offset - m_lOrgY;
|
|
Rect.right = Rect.left + pTable->width;
|
|
Rect.bottom = Rect.top + pTable->height;
|
|
|
|
// Return FALSE if this doesn't fall into view of the context.
|
|
if(Rect.top > m_lHeight || Rect.bottom < 0 || Rect.right < 0 || Rect.left > m_lWidth) {
|
|
if(CanBlockDisplay()) {
|
|
bRetval = FALSE;
|
|
}
|
|
}
|
|
|
|
return(bRetval);
|
|
}
|
|
|
|
BOOL CDCCX::ResolveElement(LTRB& Rect, LO_SubDocStruct *pSubDoc, int iLocation) {
|
|
BOOL bRetval = TRUE;
|
|
|
|
// First, figure the coordinates.
|
|
Rect.left = pSubDoc->x + pSubDoc->x_offset - m_lOrgX;
|
|
Rect.top = pSubDoc->y + pSubDoc->y_offset - m_lOrgY;
|
|
Rect.right = Rect.left + pSubDoc->width;
|
|
Rect.bottom = Rect.top + pSubDoc->height;
|
|
|
|
// Return FALSE if this doesn't fall into view of the context.
|
|
if(Rect.top > m_lHeight || Rect.bottom < 0 || Rect.right < 0 || Rect.left > m_lWidth) {
|
|
if(CanBlockDisplay()) {
|
|
bRetval = FALSE;
|
|
}
|
|
}
|
|
|
|
return(bRetval);
|
|
}
|
|
|
|
BOOL CDCCX::ResolveElement(LTRB& Rect, LO_CellStruct *pCell, int iLocation) {
|
|
BOOL bRetval = TRUE;
|
|
|
|
// First, figure the coordinates.
|
|
Rect.left = pCell->x + pCell->x_offset - m_lOrgX;
|
|
Rect.top = pCell->y + pCell->y_offset - m_lOrgY;
|
|
Rect.right = Rect.left + pCell->width;
|
|
Rect.bottom = Rect.top + pCell->height;
|
|
|
|
// Return FALSE if this doesn't fall into view of the context.
|
|
if(Rect.top > m_lHeight || Rect.bottom < 0 || Rect.right < 0 || Rect.left > m_lWidth) {
|
|
if(CanBlockDisplay()) {
|
|
bRetval = FALSE;
|
|
}
|
|
}
|
|
|
|
return(bRetval);
|
|
}
|
|
|
|
BOOL CDCCX::ResolveElement(LTRB& Rect, LO_EmbedStruct *pEmbed, int iLocation, Bool bWindowed) {
|
|
BOOL bRetval = TRUE;
|
|
|
|
// First, figure the coordinates.
|
|
Rect.left = -m_lOrgX;
|
|
Rect.top = -m_lOrgY;
|
|
|
|
// For windowed embeds, we only need the position of the embed,
|
|
// and we ignore the layer origin. For windowless embeds, we only
|
|
// need the layer origin, and not the position of the embed.
|
|
if (bWindowed) {
|
|
Rect.left += pEmbed->objTag.x + pEmbed->objTag.x_offset + pEmbed->objTag.border_width;
|
|
Rect.top += pEmbed->objTag.y + pEmbed->objTag.y_offset + pEmbed->objTag.border_width;
|
|
}
|
|
|
|
Rect.right = Rect.left + pEmbed->objTag.width;
|
|
Rect.bottom = Rect.top + pEmbed->objTag.height;
|
|
|
|
if (!bWindowed)
|
|
ExtendCoord(Rect);
|
|
|
|
// Return FALSE if this doesn't fall into view of the context.
|
|
if(Rect.top > m_lHeight || Rect.bottom < 0 || Rect.right < 0 || Rect.left > m_lWidth) {
|
|
if(CanBlockDisplay()) {
|
|
bRetval = FALSE;
|
|
}
|
|
}
|
|
|
|
return(bRetval);
|
|
}
|
|
|
|
BOOL CDCCX::ResolveElement(LTRB& Rect, LO_LinefeedStruct *pLineFeed, int iLocation) {
|
|
BOOL bRetval = TRUE;
|
|
|
|
// First, figure the coordinates.
|
|
Rect.left = pLineFeed->x + pLineFeed->x_offset - m_lOrgX;
|
|
Rect.top = pLineFeed->y + pLineFeed->y_offset - m_lOrgY;
|
|
Rect.right = Rect.left + pLineFeed->width;
|
|
Rect.bottom = Rect.top + pLineFeed->height;
|
|
|
|
// Return FALSE if this doesn't fall into view of the context.
|
|
if(Rect.top > m_lHeight || Rect.bottom < 0 || Rect.right < 0 || Rect.left > m_lWidth) {
|
|
if(CanBlockDisplay()) {
|
|
bRetval = FALSE;
|
|
}
|
|
}
|
|
|
|
return(bRetval);
|
|
}
|
|
|
|
inline BOOL CDCCX::ResolveLineSolid() {
|
|
// Don't default to all solid lines.
|
|
return(FALSE);
|
|
}
|
|
|
|
COLORREF CDCCX::ResolveTextColor(LO_TextAttr *pAttr) {
|
|
// Purpose: Determine the Forground color of the attribute.
|
|
// Arguments: pAttr The attributes from which we will obtain the color.
|
|
// Returns: COLORREF The color.
|
|
// Comments: Override this if you need finer control over the selections
|
|
// of color such as printing.
|
|
// Revision History:
|
|
// 06-09-95 created GAB
|
|
|
|
// Default implementation simply returns the color requested. Make sure that
|
|
// we get the closest match in the palette and not one of the static system
|
|
// colors. or'ing 0x02000000L in here is easier than finding every occurence
|
|
// of SetTextColor downstream
|
|
if(pAttr != NULL) {
|
|
return(0x02000000L | RGB(pAttr->fg.red, pAttr->fg.green, pAttr->fg.blue));
|
|
}
|
|
else {
|
|
return(RGB(0,0,0));
|
|
}
|
|
}
|
|
|
|
//
|
|
// if we are not in true-color mode snap the color to the palette
|
|
// otherwise they will get dithered to the windows 16-color palette
|
|
// in the view's EraseBackground method
|
|
//
|
|
COLORREF CDCCX::ResolveBGColor(unsigned uRed, unsigned uGreen, unsigned uBlue)
|
|
{
|
|
|
|
int index = 0;
|
|
if ((m_iBitsPerPixel <= 8) && m_pPal) {
|
|
|
|
index = ::GetNearestPaletteIndex(m_pPal, RGB(uRed, uGreen, uBlue));
|
|
|
|
PALETTEENTRY palEntry;
|
|
::GetPaletteEntries(m_pPal, index, 1, &palEntry);
|
|
uRed = palEntry.peRed;
|
|
uGreen = palEntry.peGreen;
|
|
uBlue = palEntry.peBlue;
|
|
|
|
}
|
|
|
|
return(RGB(uRed, uGreen, uBlue));
|
|
|
|
}
|
|
|
|
BOOL CDCCX::ResolveHRSolid(LO_HorizRuleStruct *pHorizRule)
|
|
{
|
|
// Determine if an HR is to be solid or 3D.
|
|
// Override this if you need to specifically control the display of
|
|
// HRs.
|
|
if((pHorizRule->ele_attrmask & LO_ELE_SHADED) == LO_ELE_SHADED && pHorizRule->thickness > 1) {
|
|
return(FALSE);
|
|
}
|
|
return(TRUE);
|
|
}
|
|
|
|
inline COLORREF CDCCX::ResolveDarkLineColor() {
|
|
// By default, return the dark color.
|
|
// Override if you need to control HR colors.
|
|
return(m_rgbDarkColor);
|
|
}
|
|
|
|
inline COLORREF CDCCX::ResolveLightLineColor() {
|
|
// By default, return the light color.
|
|
// Override if you need to control HR colors.
|
|
return(m_rgbLightColor);
|
|
}
|
|
|
|
COLORREF CDCCX::ResolveBorderColor(LO_TextAttr *pAttr) {
|
|
// Default is to simply return the color requested.
|
|
// Override if you need to control border display.
|
|
if(pAttr != NULL) {
|
|
return(RGB(pAttr->fg.red, pAttr->fg.green, pAttr->fg.blue));
|
|
}
|
|
else {
|
|
return(RGB(0,0,0));
|
|
}
|
|
}
|
|
|
|
COLORREF CDCCX::ResolveLOColor(LO_Color *color) {
|
|
// Default is to simply return the color requested.
|
|
// Override if you need to control border display.
|
|
if(color != NULL) {
|
|
return(RGB(color->red, color->green, color->blue));
|
|
}
|
|
else {
|
|
return(RGB(0,0,0));
|
|
}
|
|
}
|
|
|
|
void CDCCX::ResolveTransparentColor(unsigned uRed, unsigned uGreen, unsigned uBlue) {
|
|
// Sets the transparency color of images.
|
|
// This in most cases is the same as the background color.
|
|
// Override this if you take special interest in controlling the background color.
|
|
|
|
int iIndex = 0;
|
|
IL_IRGB *rgbTransparent = GetContext()->transparent_pixel;
|
|
|
|
if ((m_iBitsPerPixel <= 8) && m_pPal) {
|
|
iIndex = ::GetNearestPaletteIndex(m_pPal, m_rgbBackgroundColor);
|
|
curColorSpace->cmap.index[MAX_IMAGE_PALETTE_ENTRIES] = iIndex;
|
|
}
|
|
|
|
// Simply let the image lib know what's up.
|
|
if (!rgbTransparent) {
|
|
rgbTransparent = XP_NEW_ZAP(IL_IRGB);
|
|
GetContext()->transparent_pixel = rgbTransparent;
|
|
}
|
|
|
|
rgbTransparent->index = MAX_IMAGE_PALETTE_ENTRIES;
|
|
rgbTransparent->red = uRed;
|
|
rgbTransparent->green = uGreen;
|
|
rgbTransparent->blue = uBlue;
|
|
}
|
|
|
|
// rgbLight is used to render the top/left edges, and rgbDark is used to
|
|
// render the bottom/right edges
|
|
void CDCCX::Display3DBox(LTRB& Rect, COLORREF rgbLight, COLORREF rgbDark, int32 lWidth, BOOL bAdjust) {
|
|
HDC hDC = GetContextDC();
|
|
|
|
// Adjust the y value by half the height. We'll need to move it back
|
|
// to the original position, since we have a reference to the rect.
|
|
int32 lAdjust = 0;
|
|
if(bAdjust == TRUE) {
|
|
// This should only happen with HRs!
|
|
lAdjust = Rect.Height() / 2;
|
|
if(MMIsText() == FALSE) {
|
|
Rect.top -= lAdjust;
|
|
Rect.bottom -= lAdjust;
|
|
}
|
|
}
|
|
else {
|
|
// When bAdjust is false, this means we are dealing with a table/cell/subdoc.
|
|
// To properly draw these, we need to shrink the rect on the right and bottom
|
|
// by the width.
|
|
lAdjust = lWidth;
|
|
Rect.right -= lAdjust;
|
|
Rect.bottom -= lAdjust;
|
|
}
|
|
|
|
// If there's a thick border then miter the join where the different
|
|
// colors meet
|
|
if(lWidth > Pix2TwipsX(1) && ResolveLineSolid() == FALSE) {
|
|
HPEN hOldPen = (HPEN)::SelectObject(hDC, GetStockObject(NULL_PEN));
|
|
POINT aPoints[6];
|
|
HBRUSH hbDark, hbLight, hOldBrush;
|
|
|
|
// Make sure that in 256 color mode we get a PALETTE RGB color
|
|
hbDark = ::CreateSolidBrush(0x02000000L | rgbDark);
|
|
hbLight = ::CreateSolidBrush(0x02000000L | rgbLight);
|
|
|
|
// Map all the points.
|
|
// Left and top.
|
|
aPoints[0].x = CASTINT(Rect.left + lWidth);
|
|
aPoints[0].y = CASTINT(Rect.top + lWidth);
|
|
aPoints[1].x = CASTINT(Rect.left + lWidth);
|
|
aPoints[1].y = CASTINT(Rect.bottom);
|
|
aPoints[2].x = CASTINT(Rect.left);
|
|
aPoints[2].y = CASTINT(Rect.bottom + lWidth);
|
|
aPoints[3].x = CASTINT(Rect.left);
|
|
aPoints[3].y = CASTINT(Rect.top);
|
|
aPoints[4].x = CASTINT(Rect.right + lWidth);
|
|
aPoints[4].y = CASTINT(Rect.top);
|
|
aPoints[5].x = CASTINT(Rect.right);
|
|
aPoints[5].y = CASTINT(Rect.top + lWidth);
|
|
|
|
hOldBrush = (HBRUSH)::SelectObject(hDC, hbLight);
|
|
::Polygon(hDC, aPoints, 6);
|
|
|
|
// Right and bottom.
|
|
aPoints[0].x = CASTINT(Rect.right);
|
|
aPoints[0].y = CASTINT(Rect.bottom);
|
|
aPoints[3].x = CASTINT(Rect.right + lWidth);
|
|
aPoints[3].y = CASTINT(Rect.bottom + lWidth);
|
|
|
|
::SelectObject(hDC, hbDark);
|
|
::Polygon(hDC, aPoints, 6);
|
|
|
|
::SelectObject(hDC, hOldPen);
|
|
::SelectObject(hDC, hOldBrush);
|
|
VERIFY(::DeleteObject(hbDark));
|
|
VERIFY(::DeleteObject(hbLight));
|
|
}
|
|
else {
|
|
HBRUSH hbLight, hbDark, hOldBrush;
|
|
|
|
// Left/top edges
|
|
hbLight = ::CreateSolidBrush(0x02000000L | rgbLight);
|
|
hOldBrush = (HBRUSH)::SelectObject(hDC, hbLight);
|
|
|
|
::PatBlt(hDC, CASTINT(Rect.left), CASTINT(Rect.top),
|
|
CASTINT(Rect.right - Rect.left), lWidth, PATCOPY);
|
|
::PatBlt(hDC, CASTINT(Rect.left), CASTINT(Rect.top),
|
|
lWidth, CASTINT(Rect.bottom - Rect.top), PATCOPY);
|
|
|
|
::SelectObject(hDC, hOldBrush);
|
|
VERIFY(::DeleteObject(hbLight));
|
|
|
|
// Bottom/right edges
|
|
hbDark = ::CreateSolidBrush(0x02000000L | rgbDark);
|
|
hOldBrush = (HBRUSH)::SelectObject(hDC, hbDark);
|
|
|
|
::PatBlt(hDC, CASTINT(Rect.left), CASTINT(Rect.bottom),
|
|
CASTINT(Rect.right - Rect.left), lWidth, PATCOPY);
|
|
::PatBlt(hDC, CASTINT(Rect.right), CASTINT(Rect.top),
|
|
lWidth, CASTINT(Rect.bottom - Rect.top) + 1, PATCOPY);
|
|
|
|
::SelectObject(hDC, hOldBrush);
|
|
VERIFY(::DeleteObject(hbDark));
|
|
}
|
|
// Reposition.
|
|
if(bAdjust == TRUE) {
|
|
// HRs
|
|
if(MMIsText() == FALSE) {
|
|
Rect.top += lAdjust;
|
|
Rect.bottom += lAdjust;
|
|
}
|
|
}
|
|
else {
|
|
// Table/cell/subdoc
|
|
Rect.right += lAdjust;
|
|
Rect.bottom += lAdjust;
|
|
}
|
|
|
|
ReleaseContextDC(hDC);
|
|
}
|
|
|
|
static HPEN
|
|
CreateStyledPen(COLORREF color, int nWidth, int nPenStyle)
|
|
{
|
|
#ifdef _WIN32
|
|
LOGBRUSH lb;
|
|
DWORD dwPenStyle;
|
|
#endif
|
|
|
|
#ifdef _WIN32
|
|
lb.lbStyle = 0; // ignored
|
|
lb.lbColor = 0x02000000L | color;
|
|
lb.lbStyle = 0; // ignored
|
|
|
|
dwPenStyle = PS_GEOMETRIC | PS_ENDCAP_SQUARE | PS_JOIN_MITER;
|
|
|
|
return ::ExtCreatePen(dwPenStyle | nPenStyle, nWidth, &lb, 0, NULL);
|
|
#else
|
|
return ::CreatePen(nPenStyle, nWidth, 0x02000000L | color);
|
|
#endif
|
|
}
|
|
|
|
static void
|
|
DisplaySpecialBorder(HDC hDC, RECT &r, COLORREF color, int iWidth, BOOL bSolid)
|
|
{
|
|
HPEN hPen = ::CreatePen(PS_DOT, 1, 0x02000000L | color);
|
|
HPEN hOldPen = (HPEN)::SelectObject(hDC, hPen);
|
|
HBRUSH hOldBrush = (HBRUSH) ::SelectObject(hDC, ::GetStockObject(NULL_BRUSH));
|
|
|
|
::SetBkMode(hDC, TRANSPARENT);
|
|
for( int i = 0; i < iWidth; i++ )
|
|
{
|
|
::Rectangle(hDC, r.left, r.top, r.right, r.bottom);
|
|
::InflateRect(&r, -1, -1);
|
|
}
|
|
|
|
::SelectObject(hDC, hOldPen);
|
|
::SelectObject(hDC, hOldBrush);
|
|
VERIFY(::DeleteObject(hPen));
|
|
}
|
|
|
|
static void
|
|
DisplaySolidBorder(HDC hDC, RECT &r, COLORREF color, LTRB &widths)
|
|
{
|
|
// See if all border edges are the same width
|
|
if (widths.left == widths.top && widths.left == widths.right && widths.left == widths.bottom) {
|
|
HPEN hPen = ::CreatePen(PS_INSIDEFRAME, widths.left, 0x02000000L | color);
|
|
HPEN hOldPen = (HPEN)::SelectObject(hDC, hPen);
|
|
HBRUSH hOldBrush = (HBRUSH) ::SelectObject(hDC, ::GetStockObject(NULL_BRUSH));
|
|
|
|
// Draw it using a single rectangle call
|
|
::Rectangle(hDC, r.left, r.top, r.right, r.bottom);
|
|
::SelectObject(hDC, hOldPen);
|
|
::SelectObject(hDC, hOldBrush);
|
|
VERIFY(::DeleteObject(hPen));
|
|
|
|
} else {
|
|
HBRUSH hBrush = ::CreateSolidBrush(0x02000000L | color);
|
|
HBRUSH hOldBrush = (HBRUSH)::SelectObject(hDC, hBrush);
|
|
|
|
// Draw each of the individual edges using PatBlt
|
|
if (widths.left > 0)
|
|
::PatBlt(hDC, r.left, r.top, widths.left, r.bottom - r.top, PATCOPY);
|
|
|
|
if (widths.top > 0)
|
|
::PatBlt(hDC, r.left, r.top, r.right - r.left, widths.top, PATCOPY);
|
|
|
|
if (widths.right > 0)
|
|
::PatBlt(hDC, r.right - widths.right, r.top, widths.right, r.bottom - r.top, PATCOPY);
|
|
|
|
if (widths.bottom > 0)
|
|
::PatBlt(hDC, r.left, r.bottom - widths.bottom, r.right - r.left, widths.bottom, PATCOPY);
|
|
|
|
::SelectObject(hDC, hOldBrush);
|
|
VERIFY(::DeleteObject(hBrush));
|
|
}
|
|
}
|
|
|
|
static void
|
|
DisplayDoubleBorder(HDC hDC, RECT &r, COLORREF color, LTRB &widths)
|
|
{
|
|
LTRB strokeWidths;
|
|
|
|
// Compute the stroke width for each of the edges
|
|
strokeWidths.left = (widths.left + 1) / 3;
|
|
strokeWidths.top = (widths.top + 1) / 3;
|
|
strokeWidths.right = (widths.right + 1) / 3;
|
|
strokeWidths.bottom = (widths.bottom + 1) / 3;
|
|
|
|
// Draw the outer lines
|
|
DisplaySolidBorder(hDC, r, color, strokeWidths);
|
|
|
|
// Adjust the rectangle to be the inner rectangle
|
|
r.left += CASTINT(widths.left - strokeWidths.left);
|
|
r.top += CASTINT(widths.top - strokeWidths.top);
|
|
r.right -= CASTINT(widths.right - strokeWidths.right);
|
|
r.bottom -= CASTINT(widths.bottom - strokeWidths.bottom);
|
|
|
|
// Draw the inner lines
|
|
DisplaySolidBorder(hDC, r, color, strokeWidths);
|
|
}
|
|
|
|
// rgbLight is used to render the top/left edges, and rgbDark is used to
|
|
// render the bottom/right edges
|
|
void
|
|
CDCCX::Display3DBorder(LTRB& Rect, COLORREF rgbLight, COLORREF rgbDark, LTRB &widths)
|
|
{
|
|
if (widths.left == widths.top && widths.left == widths.right && widths.left == widths.bottom) {
|
|
// This routine is faster especially for one-pixel thick lines
|
|
Display3DBox(Rect, rgbLight, rgbDark, widths.left, FALSE);
|
|
|
|
} else {
|
|
HDC hDC = GetContextDC();
|
|
|
|
HPEN hOldPen = (HPEN)::SelectObject(hDC, GetStockObject(NULL_PEN));
|
|
POINT aPoints[6];
|
|
HBRUSH hbDark, hbLight, hOldBrush;
|
|
|
|
// Make sure that in 256 color mode we get a PALETTE RGB color
|
|
hbDark = ::CreateSolidBrush(0x02000000L | rgbDark);
|
|
hbLight = ::CreateSolidBrush(0x02000000L | rgbLight);
|
|
|
|
// Map all the points. Draw it inside of the rect. Draw the left
|
|
// and top edges first
|
|
aPoints[0].x = CASTINT(Rect.left + widths.left);
|
|
aPoints[0].y = CASTINT(Rect.top + widths.top);
|
|
aPoints[1].x = CASTINT(Rect.left + widths.left);
|
|
aPoints[1].y = CASTINT(Rect.bottom - widths.bottom);
|
|
aPoints[2].x = CASTINT(Rect.left);
|
|
aPoints[2].y = CASTINT(Rect.bottom);
|
|
aPoints[3].x = CASTINT(Rect.left);
|
|
aPoints[3].y = CASTINT(Rect.top);
|
|
aPoints[4].x = CASTINT(Rect.right);
|
|
aPoints[4].y = CASTINT(Rect.top);
|
|
aPoints[5].x = CASTINT(Rect.right - widths.right);
|
|
aPoints[5].y = CASTINT(Rect.top + widths.top);
|
|
|
|
hOldBrush = (HBRUSH)::SelectObject(hDC, hbLight);
|
|
::Polygon(hDC, aPoints, 6);
|
|
|
|
// Right and bottom.
|
|
aPoints[0].x = CASTINT(Rect.right - widths.right);
|
|
aPoints[0].y = CASTINT(Rect.bottom - widths.bottom);
|
|
aPoints[3].x = CASTINT(Rect.right);
|
|
aPoints[3].y = CASTINT(Rect.bottom);
|
|
|
|
::SelectObject(hDC, hbDark);
|
|
::Polygon(hDC, aPoints, 6);
|
|
|
|
::SelectObject(hDC, hOldPen);
|
|
::SelectObject(hDC, hOldBrush);
|
|
VERIFY(::DeleteObject(hbDark));
|
|
VERIFY(::DeleteObject(hbLight));
|
|
|
|
ReleaseContextDC(hDC);
|
|
}
|
|
}
|
|
|
|
// Adjust border for selection feedback of table or cell
|
|
// Returns width used in excess of table border (into space between cells)
|
|
// because that will have to be restored to background when removing selection
|
|
int32 SetSelectionBorder(int32 *pWidth, int32 iCellSpacing)
|
|
{
|
|
int32 iOldWidth = *pWidth;
|
|
int32 iExcess = 0;
|
|
// Allow wider selection if border is very large
|
|
int32 iMaxWidth = 2*ED_SELECTION_BORDER;
|
|
//
|
|
*pWidth = min(*pWidth,iMaxWidth);
|
|
// Also use spacing between cells if less than maximum
|
|
if( *pWidth < 6 )
|
|
{
|
|
iExcess = min(iCellSpacing, 6-*pWidth);
|
|
*pWidth += iExcess;
|
|
}
|
|
return iExcess;
|
|
}
|
|
|
|
int32
|
|
CDCCX::DisplayTableBorder(LTRB& Rect, LO_TableStruct *pTable)
|
|
{
|
|
COLORREF rgbBorder = ResolveLOColor(&pTable->border_color);
|
|
COLORREF rgbLight, rgbDark;
|
|
HDC hDC;
|
|
RECT r = {CASTINT(Rect.left), CASTINT(Rect.top), CASTINT(Rect.right), CASTINT(Rect.bottom)};
|
|
LTRB insetRect;
|
|
LTRB borderWidths(pTable->border_left_width, pTable->border_top_width,
|
|
pTable->border_right_width, pTable->border_bottom_width);
|
|
//TRACE0("DisplayTableBorder\n");
|
|
|
|
// Only the Editor sets table elements as selected, so we don't need EDT_IS_EDITOR
|
|
if( pTable->ele_attrmask & LO_ELE_SELECTED )
|
|
{
|
|
// Use the selection background color to draw a solid border
|
|
COLORREF rgbBorder;
|
|
wfe_GetSelectionColors(m_rgbBackgroundColor, NULL, &rgbBorder);
|
|
hDC = GetContextDC();
|
|
// Use same border thickness for all sides - use the minimum Table border thickness
|
|
// and the space between cells if available
|
|
int32 iBorderWidth = min(borderWidths.bottom,min(borderWidths.top,min(borderWidths.left, borderWidths.right)));
|
|
SetSelectionBorder(&iBorderWidth, pTable->inter_cell_space);
|
|
borderWidths.left = borderWidths.right = borderWidths.top = borderWidths.bottom = iBorderWidth;
|
|
|
|
// Show a solid border up to twice default selection border as the selection feedback
|
|
DisplaySolidBorder(hDC, r, rgbBorder, borderWidths);
|
|
ReleaseContextDC(hDC);
|
|
// Return actual border width used
|
|
return iBorderWidth;
|
|
}
|
|
else
|
|
{
|
|
if (pTable->border_style == BORDER_GROOVE || pTable->border_style == BORDER_RIDGE ||
|
|
pTable->border_style == BORDER_INSET || pTable->border_style == BORDER_OUTSET) {
|
|
|
|
// Compute the 3D colors to use. If the border color is the same as the background
|
|
// color then just use the light/dark colors we've already computed
|
|
if (rgbBorder == m_rgbBackgroundColor) {
|
|
rgbLight = m_rgbLightColor;
|
|
rgbDark = m_rgbDarkColor;
|
|
|
|
} else {
|
|
Compute3DColors(rgbBorder, rgbLight, rgbDark);
|
|
}
|
|
}
|
|
|
|
hDC = GetContextDC();
|
|
switch (pTable->border_style) {
|
|
case BORDER_NONE:
|
|
break;
|
|
|
|
case BORDER_DOTTED:
|
|
case BORDER_DASHED:
|
|
case BORDER_SOLID:
|
|
// hDC = GetContextDC();
|
|
DisplaySolidBorder(hDC, r, rgbBorder, borderWidths);
|
|
// ReleaseContextDC(hDC);
|
|
break;
|
|
|
|
case BORDER_DOUBLE:
|
|
// hDC = GetContextDC();
|
|
DisplayDoubleBorder(hDC, r, rgbBorder, borderWidths);
|
|
// ReleaseContextDC(hDC);
|
|
break;
|
|
|
|
case BORDER_GROOVE:
|
|
// This is done as a sunken outer border with a raised inner
|
|
// border. Windows group boxes have this appearance
|
|
borderWidths.left /= 2;
|
|
borderWidths.top /= 2;
|
|
borderWidths.right /= 2;
|
|
borderWidths.bottom /= 2;
|
|
Display3DBorder(Rect, rgbDark, rgbLight, borderWidths);
|
|
insetRect.left = Rect.left + borderWidths.left;
|
|
insetRect.top = Rect.top + borderWidths.top;
|
|
insetRect.right = Rect.right - borderWidths.right;
|
|
insetRect.bottom = Rect.bottom - borderWidths.bottom;
|
|
Display3DBorder(insetRect, rgbLight, rgbDark, borderWidths);
|
|
break;
|
|
|
|
case BORDER_RIDGE:
|
|
// This is done as a raised outer border with a sunken inner border
|
|
borderWidths.left /= 2;
|
|
borderWidths.top /= 2;
|
|
borderWidths.right /= 2;
|
|
borderWidths.bottom /= 2;
|
|
Display3DBorder(Rect, rgbLight, rgbDark, borderWidths);
|
|
insetRect.left = Rect.left + borderWidths.left;
|
|
insetRect.top = Rect.top + borderWidths.top;
|
|
insetRect.right = Rect.right - borderWidths.right;
|
|
insetRect.bottom = Rect.bottom - borderWidths.bottom;
|
|
Display3DBorder(insetRect, rgbDark, rgbLight, borderWidths);
|
|
break;
|
|
|
|
case BORDER_INSET:
|
|
// This is what Windows refers to as a sunken border
|
|
Display3DBorder(Rect, rgbDark, rgbLight, borderWidths);
|
|
break;
|
|
|
|
case BORDER_OUTSET:
|
|
// This is what Windows refers to as a raised border
|
|
Display3DBorder(Rect, rgbLight, rgbDark, borderWidths);
|
|
break;
|
|
|
|
default:
|
|
ASSERT(FALSE);
|
|
break;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void CDCCX::EditorDisplayZeroWidthBorder(LTRB& Rect, BOOL bSelected){
|
|
// Show a 1-pixel dotted border. Used in the editor
|
|
// Use the same color we would use for a selection background,
|
|
// but use the opposite color if we will be selecting,
|
|
// so NOT opperation yields a contrasting color relative to background
|
|
COLORREF rgbColor;
|
|
wfe_GetSelectionColors(m_rgbBackgroundColor, NULL, &rgbColor);
|
|
|
|
HDC hdc = GetContextDC();
|
|
// Use dotted line if not selected, or solid if selecting
|
|
HPEN pPen = ::CreatePen(bSelected ? PS_SOLID : PS_DOT, 1, rgbColor);
|
|
HPEN pOldPen = (HPEN)::SelectObject(hdc, pPen);
|
|
HBRUSH hOldBrush = (HBRUSH) ::SelectObject(hdc, ::GetStockObject(NULL_BRUSH));
|
|
::Rectangle(hdc, Rect.left, Rect.top, Rect.right, Rect.bottom);
|
|
::SelectObject(hdc, hOldBrush);
|
|
::SelectObject(hdc, pOldPen);
|
|
ReleaseContextDC(hdc);
|
|
VERIFY(::DeleteObject(pPen));
|
|
}
|
|
|
|
void CDCCX::DrawRectBorder(LTRB& Rect, COLORREF rgbColor, int32 lWidth) {
|
|
// This should only be called for display of the border for images, and embeds.
|
|
HDC hdc = GetContextDC();
|
|
|
|
// The border goes outside of the rectangle, so we need to adjust the
|
|
// rectangle accordingly
|
|
int32 lAdjust = lWidth / 2;
|
|
int32 rAdjust = lAdjust;
|
|
if(lWidth % 2) {
|
|
lAdjust += Pix2TwipsX(1);
|
|
}
|
|
rAdjust += Pix2TwipsX(1);
|
|
|
|
LTRB rect(Rect.left - lAdjust, Rect.top - lAdjust,
|
|
Rect.right + rAdjust, Rect.bottom + rAdjust);
|
|
SafeSixteen(rect);
|
|
|
|
HPEN hBorder = ::CreatePen(PS_SOLID, CASTINT(lWidth), rgbColor);
|
|
HPEN hOldPen = (HPEN)::SelectObject(hdc, hBorder);
|
|
HBRUSH hOldBrush = (HBRUSH) ::SelectObject(hdc, ::GetStockObject(NULL_BRUSH));
|
|
|
|
// Draw it.
|
|
::Rectangle(hdc, CASTINT(rect.left), CASTINT(rect.top),
|
|
CASTINT(rect.right), CASTINT(rect.bottom));
|
|
|
|
::SelectObject(hdc, hOldBrush);
|
|
::SelectObject(hdc, hOldPen);
|
|
VERIFY(::DeleteObject(hBorder));
|
|
ReleaseContextDC(hdc);
|
|
|
|
}
|
|
|
|
void CDCCX::DisplaySelectionFeedback(uint16 ele_attrmask, const LTRB& rect)
|
|
{
|
|
BOOL bSelect = ele_attrmask & LO_ELE_SELECTED;
|
|
// Don't do anything if unselecting any other objects
|
|
// since these will be completely redrawn.
|
|
if ( !bSelect || !EDT_IS_EDITOR(GetContext()) ) {
|
|
return;
|
|
}
|
|
LTRB Rect(rect.left, rect.top,
|
|
rect.right, rect.bottom);
|
|
|
|
SafeSixteen(Rect);
|
|
// Draw selection feedback. It has to fit entirely within rect, because
|
|
// when it's turned off, all that will happen is that it won't be drawn.
|
|
HDC hdc = GetContextDC();
|
|
|
|
int32 rWidth = Rect.right - Rect.left;
|
|
int32 rHeight = Rect.bottom - Rect.top;
|
|
if ( rWidth <= (ED_SELECTION_BORDER*2) || rHeight <= (ED_SELECTION_BORDER*2) ) {
|
|
// Too narrow to draw frame. Draw solid.
|
|
RECT r;
|
|
::SetRect(&r, CASTINT(Rect.left), CASTINT(Rect.top),
|
|
CASTINT(Rect.right), CASTINT(Rect.bottom));
|
|
::InvertRect(hdc, &r);
|
|
}
|
|
else {
|
|
// Frame.
|
|
LTRB inner(Rect.left + ED_SELECTION_BORDER, Rect.top + ED_SELECTION_BORDER,
|
|
Rect.right - ED_SELECTION_BORDER, Rect.bottom - ED_SELECTION_BORDER);
|
|
SafeSixteen(inner);
|
|
|
|
RECT SelRect;
|
|
::SetRect(&SelRect, CASTINT(Rect.left), CASTINT(Rect.top), CASTINT(Rect.right), CASTINT(inner.top));
|
|
::InvertRect(hdc, &SelRect);
|
|
::SetRect(&SelRect, CASTINT(Rect.left), CASTINT(inner.top), CASTINT(inner.left), CASTINT(inner.bottom));
|
|
::InvertRect(hdc, &SelRect);
|
|
::SetRect(&SelRect, CASTINT(inner.right), CASTINT(inner.top), CASTINT(Rect.right), CASTINT(inner.bottom));
|
|
::InvertRect(hdc, &SelRect);
|
|
::SetRect(&SelRect, CASTINT(Rect.left), CASTINT(inner.bottom), CASTINT(Rect.right), CASTINT(Rect.bottom));
|
|
::InvertRect(hdc, &SelRect);
|
|
}
|
|
|
|
ReleaseContextDC(hdc);
|
|
}
|
|
|
|
void CDCCX::EraseToBackground(const LTRB& rect, int32 borderWidth)
|
|
{
|
|
if(!EDT_IS_EDITOR(GetContext())){
|
|
return;
|
|
}
|
|
LTRB Rect(rect.left - borderWidth, rect.top - borderWidth,
|
|
rect.right + borderWidth, rect.bottom + borderWidth);
|
|
|
|
// The editor draws selection feedback. Touch all the pixels so that
|
|
// any pre-existing selection feedback is erased.
|
|
HDC hdc = GetContextDC();
|
|
|
|
RECT destRect;
|
|
::SetRect(&destRect, CASTINT(Twips2PixX(Rect.left)), CASTINT(Twips2PixY(Rect.top)),
|
|
CASTINT(Twips2PixX(Rect.right)), CASTINT(Twips2PixX(Rect.bottom)));
|
|
|
|
// Is this really true? (Troy thinks conversion is only needed for
|
|
// memory DC)
|
|
// Coordinates to _EraseBkgnd() must be in device units
|
|
// NOTE: _EraseBkgnd() call will use m_pImageDC, that's why we
|
|
// aren't using it
|
|
_EraseBkgnd(hdc,destRect,
|
|
Twips2PixX(GetOriginX() ),
|
|
Twips2PixY(GetOriginY() ),
|
|
NULL);
|
|
ReleaseContextDC(hdc);
|
|
}
|
|
|
|
|
|
#ifdef LAYERS
|
|
// Erase the background at the given rect. x, y, width and height are
|
|
// in document coordinates.
|
|
void CDCCX::EraseBackground(MWContext *pContext, int iLocation,
|
|
int32 x, int32 y, uint32 width, uint32 height,
|
|
LO_Color *pColor)
|
|
{
|
|
#ifdef EDITOR
|
|
if( EDT_IS_EDITOR(pContext) )
|
|
WFE_HideEditCaret(pContext);
|
|
#endif
|
|
HDC hdc = GetContextDC();
|
|
int32 orgX = GetOriginX();
|
|
int32 orgY = GetOriginY();
|
|
int32 lDrawingOrgX, lDrawingOrgY;
|
|
RECT eraseRect;
|
|
int32 x0, y0;
|
|
|
|
x0 = (x > orgX) ? x - orgX : orgX - x;
|
|
y0 = (y > orgY) ? y - orgY : orgY - y;
|
|
::SetRect(&eraseRect, CASTINT(x0), CASTINT(y0),
|
|
CASTINT(x0+width), CASTINT(y0+height));
|
|
GetDrawingOrigin(&lDrawingOrgX, &lDrawingOrgY);
|
|
_EraseBkgnd(hdc, eraseRect, orgX-lDrawingOrgX, orgY-lDrawingOrgY,
|
|
pColor);
|
|
|
|
ReleaseContextDC(hdc);
|
|
#ifdef EDITOR
|
|
if( EDT_IS_EDITOR(pContext) )
|
|
WFE_ShowEditCaret(pContext);
|
|
#endif
|
|
}
|
|
#endif /* LAYERS */
|
|
|
|
static BOOL
|
|
CanCreateBrush(HBITMAP hBitmap)
|
|
{
|
|
BITMAP bitmap;
|
|
|
|
// We can create a brush if the bitmap is exacly 8x8
|
|
::GetObject(hBitmap, sizeof(bitmap), &bitmap);
|
|
return bitmap.bmWidth == 8 && bitmap.bmHeight == 8;
|
|
}
|
|
|
|
|
|
// orgX, orgY, and crRect are interpreted in the logical coordinates
|
|
// of pDC
|
|
//
|
|
// Note: The caller is responsible for having selected the logical palette
|
|
// before calling this routine. If not, the call to CreateSolidBrush() will
|
|
// get mapped to the nearest system color (probably not the desired behavior)
|
|
BOOL CDCCX::_EraseBkgnd(HDC pDC, RECT& crRect, int32 orgX, int32 orgY,
|
|
LO_Color* bg)
|
|
{
|
|
// The order of priority is as follows:
|
|
// 1. passed in image
|
|
// 2. passed in color
|
|
// 3. document backdrop image
|
|
// 4. document solid color
|
|
COLORREF bgColor = bg ? RGB(bg->red, bg->green, bg->blue) : m_rgbBackgroundColor;
|
|
|
|
HBRUSH hBrush = NULL;
|
|
if (m_iBitsPerPixel == 16)
|
|
// We don't want a dithered brush
|
|
hBrush = ::CreateSolidBrush(::GetNearestColor(pDC,bgColor));
|
|
else
|
|
hBrush = ::CreateSolidBrush(0x02000000L | bgColor);
|
|
|
|
::FillRect(pDC, &crRect, hBrush);
|
|
|
|
#ifdef DDRAW
|
|
if (GetPrimarySurface()) {
|
|
::FillRect(GetDispDC(), &crRect, hBrush);
|
|
}
|
|
#if 0 //DEBUG_mhwang
|
|
TRACE("CDCCX::_EraseBkgnd, %d,%d,%d,%d(ltrb)\n", crRect.left, crRect.top,
|
|
crRect.right, crRect.bottom);
|
|
#endif
|
|
#endif
|
|
VERIFY(::DeleteObject(hBrush));
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
struct iconMap{
|
|
int iIconNum;
|
|
int x;
|
|
int y;
|
|
unsigned int bitmapID;
|
|
unsigned int maskID;
|
|
}
|
|
|
|
#define SMIME_ICON_CX 50
|
|
#define SMIME_ICON_CY 30
|
|
#define SECADV_ICON_CX 51
|
|
#define SECADV_ICON_CY 30
|
|
|
|
#define ICONMAPSIZE 31
|
|
|
|
static iconMap[ICONMAPSIZE] = {
|
|
IL_IMAGE_DELAYED, IMAGE_SMICON_WIDTH, IMAGE_SMICON_HEIGHT,IDB_SMIMAGE_DELAYED, IDB_SMIMAGE_MASK,
|
|
IL_IMAGE_NOT_FOUND, IMAGE_ICON_SIZE, IMAGE_ICON_SIZE, IDB_IMAGE_NOTFOUND,IDB_IMAGE_MASK,
|
|
IL_IMAGE_BAD_DATA, IMAGE_ICON_SIZE, IMAGE_ICON_SIZE, IDB_IMAGE_BAD, IDB_IMAGE_BAD_MASK,
|
|
IL_IMAGE_INSECURE, IMAGE_ICON_SIZE, IMAGE_ICON_SIZE, IDB_IMAGE_SEC_REPLACE,IDB_IMAGE_MASK,
|
|
IL_GOPHER_FOLDER,GOPHER_ICON_SIZE, GOPHER_ICON_SIZE + 1, IDB_GOPHER_FOLDER,IDB_GOPHER_FOLDER_MASK,
|
|
IL_GOPHER_IMAGE, GOPHER_ICON_SIZE, GOPHER_ICON_SIZE + 1, IDB_GOPHER_IMAGE,IDB_GOPHER_AUDIO_MASK,
|
|
IL_GOPHER_TEXT, GOPHER_ICON_SIZE, GOPHER_ICON_SIZE+1, IDB_GOPHER_TEXT, IDB_GOPHER_AUDIO_MASK,
|
|
IL_GOPHER_BINARY, GOPHER_ICON_SIZE, GOPHER_ICON_SIZE+1, IDB_GOPHER_BINARY, IDB_GOPHER_AUDIO_MASK,
|
|
IL_GOPHER_SOUND, GOPHER_ICON_SIZE, GOPHER_ICON_SIZE+1, IDB_GOPHER_AUDIO, IDB_GOPHER_AUDIO_MASK,
|
|
IL_GOPHER_MOVIE, GOPHER_ICON_SIZE, GOPHER_ICON_SIZE+1, IDB_GOPHER_FIND, IDB_GOPHER_FIND_MASK,
|
|
IL_GOPHER_TELNET, GOPHER_ICON_SIZE, GOPHER_ICON_SIZE+1, IDB_GOPHER_TELNET,IDB_GOPHER_TELNET_MASK,
|
|
IL_GOPHER_UNKNOWN, GOPHER_ICON_SIZE, GOPHER_ICON_SIZE+1, IDB_GOPHER_GENERIC, IDB_GOPHER_AUDIO_MASK,
|
|
IL_EDIT_NAMED_ANCHOR, GOPHER_ICON_SIZE, GOPHER_ICON_SIZE+1, IDB_EDIT_NAMED_ANCHOR, IDB_EDIT_NAMED_ANCHOR_MASK,
|
|
IL_EDIT_FORM_ELEMENT, GOPHER_ICON_SIZE, GOPHER_ICON_SIZE+1, IDB_EDIT_FORM_ELEMENT,IDB_EDIT_FORM_ELEMENT_MASK,
|
|
IL_EDIT_UNSUPPORTED_TAG, GOPHER_ICON_SIZE, GOPHER_ICON_SIZE+1, IDB_EDIT_UNSUPPORTED_TAG, IDB_EDIT_UNSUPPORTED_TAG_MASK,
|
|
IL_EDIT_UNSUPPORTED_END_TAG, GOPHER_ICON_SIZE, GOPHER_ICON_SIZE+1, IDB_EDIT_UNSUPPORTED_END_TAG, IDB_EDIT_UNSUPPORTED_END_TAG_MASK,
|
|
IL_EDIT_JAVA, GOPHER_ICON_SIZE, GOPHER_ICON_SIZE+1, IDB_EDIT_JAVA, IDB_EDIT_JAVA_MASK,
|
|
IL_EDIT_PLUGIN, GOPHER_ICON_SIZE, GOPHER_ICON_SIZE+1, IDB_EDIT_PLUGIN,IDB_EDIT_PLUGIN_MASK,
|
|
|
|
IL_SA_SIGNED, SECADV_ICON_CX, SECADV_ICON_CY, IDB_SASIGNED, IDB_SASIGNED_MASK,
|
|
IL_SA_ENCRYPTED, SECADV_ICON_CX, SECADV_ICON_CY, IDB_SAENCRYPTED, IDB_SAENCRYPTED_MASK,
|
|
IL_SA_NONENCRYPTED, SECADV_ICON_CX, SECADV_ICON_CY, IDB_SAUNENCRYPTED, IDB_SAUNENCRYPTED_MASK,
|
|
IL_SA_SIGNED_BAD, SECADV_ICON_CX, SECADV_ICON_CY, IDB_SASIGNED, IDB_SASIGNED_MASK,
|
|
IL_SA_ENCRYPTED_BAD, SECADV_ICON_CX, SECADV_ICON_CY, IDB_SASIGNEDBAD, IDB_SASIGNEDBAD_MASK,
|
|
IL_SMIME_ATTACHED, SMIME_ICON_CX, SMIME_ICON_CY, IDB_MSGATTACHED, IDB_MSGSTAMPMASK,
|
|
IL_SMIME_SIGNED, SMIME_ICON_CX, SMIME_ICON_CY, IDB_MSGSIGNED, IDB_MSGSTAMPMASK,
|
|
IL_SMIME_ENCRYPTED, SMIME_ICON_CX, SMIME_ICON_CY, IDB_MSGENCRYPTED, IDB_MSGSTAMPMASK,
|
|
IL_SMIME_ENC_SIGNED, SMIME_ICON_CX, SMIME_ICON_CY, IDB_MSGSIGNEDENCRYPTED, IDB_MSGSTAMPMASK,
|
|
IL_SMIME_SIGNED_BAD, SMIME_ICON_CX, SMIME_ICON_CY, IDB_MSGSIGNEDBAD, IDB_MSGSTAMPMASK,
|
|
IL_SMIME_ENCRYPTED_BAD, SMIME_ICON_CX, SMIME_ICON_CY, IDB_MSGENCRYPTEDBAD, IDB_MSGSTAMPMASK,
|
|
IL_SMIME_ENC_SIGNED_BAD, SMIME_ICON_CX, SMIME_ICON_CY, IDB_MSGSIGNEDENCRYPTEDBAD, IDB_MSGSTAMPMASK,
|
|
|
|
IL_MSG_ATTACH, 24, 29, IDB_MSGATTACHBUTTON, IDB_MSGATTACHBUTTONMASK
|
|
};
|
|
|
|
|
|
|
|
void CDCCX::GetIconDimensions(int32* width, int32* height, int iconNumber)
|
|
{
|
|
unsigned int bitmapID; // resource ID of bitmap to load
|
|
unsigned int maskID = 0; // resource ID of mask (if any)
|
|
|
|
if (iconNumber < 0)
|
|
return;
|
|
|
|
int x, y;
|
|
|
|
for (int i = 0; i < ICONMAPSIZE ; i++) {
|
|
if (iconMap[i].iIconNum == iconNumber) {
|
|
x = iconMap[i].x;
|
|
y = iconMap[i].y;
|
|
bitmapID = iconMap[i].bitmapID;
|
|
maskID = iconMap[i].maskID;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i == ICONMAPSIZE) { // used default icon here.
|
|
x = GOPHER_ICON_SIZE;
|
|
y = GOPHER_ICON_SIZE + 1;
|
|
bitmapID = IDB_FILE;
|
|
maskID = IDB_GOPHER_AUDIO_MASK;
|
|
}
|
|
|
|
|
|
*width = CASTINT(x);
|
|
*height = CASTINT(y);
|
|
}
|
|
|
|
#ifndef XP_WIN32
|
|
/* Quaternary raster codes */
|
|
#define MAKEROP4(fore,back) (DWORD)((((back) << 8) & 0xFF000000) | (fore))
|
|
#endif
|
|
|
|
static BOOL
|
|
AlterBackgroundColor(HDC pSrcDC, int width, int height, HBITMAP hMask, HBRUSH hBrush)
|
|
{
|
|
HDC memDC;
|
|
|
|
// Create a memory DC for holding the mask
|
|
if (!(memDC = ::CreateCompatibleDC(NULL))) {
|
|
TRACE("AlterBackgroundColor() can't create compatible memory DC!\n");
|
|
return FALSE;
|
|
}
|
|
|
|
// Select the mask into the memory DC
|
|
HBITMAP hOldMaskBitmap = (HBITMAP)::SelectObject(memDC, hMask);
|
|
|
|
// 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(pSrcDC, hBrush);
|
|
|
|
// Draw the brush where the mask is 0
|
|
::BitBlt(pSrcDC,
|
|
0,
|
|
0,
|
|
width,
|
|
height,
|
|
memDC,
|
|
0,
|
|
0,
|
|
// ROP_PSDPxax);
|
|
MAKEROP4(SRCPAINT, R2_COPYPEN));
|
|
|
|
// Restore the DCs
|
|
::SelectObject(memDC, hOldMaskBitmap);
|
|
::SelectObject(pSrcDC, hOldBrush);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// equivalent to LoadBitmap(), except uses pDC for
|
|
// correct color mapping of BMP into pDC's palette.
|
|
BOOL CDCCX::cxLoadBitmap(LPCSTR pszBmName, char** bits, BITMAPINFOHEADER** myBitmapInfo)
|
|
{
|
|
HINSTANCE hResHandle = AfxGetResourceHandle();
|
|
|
|
// get the resource from the file
|
|
HBITMAP hBmp = (HBITMAP)FindResource(hResHandle, pszBmName, RT_BITMAP);
|
|
if(NULL == hBmp) {
|
|
ASSERT(0);
|
|
return FALSE;
|
|
}
|
|
|
|
HGLOBAL hRes = LoadResource(hResHandle, (HRSRC)hBmp);
|
|
ASSERT(hRes != NULL);
|
|
if(!hRes)
|
|
return FALSE;
|
|
LPBITMAPINFO pPackedDib = (LPBITMAPINFO)(LockResource(hRes));
|
|
ASSERT(pPackedDib != NULL);
|
|
if(!pPackedDib)
|
|
return FALSE;
|
|
|
|
// build a DDB header for pDC
|
|
|
|
// create the DDB
|
|
int iColorTableSize =
|
|
(1 << pPackedDib->bmiHeader.biBitCount) * sizeof(RGBQUAD);
|
|
LPBITMAPINFOHEADER bitmapInfo;
|
|
bitmapInfo = (LPBITMAPINFOHEADER)calloc(sizeof(BITMAPINFOHEADER) + iColorTableSize, 1);;
|
|
memcpy(bitmapInfo, pPackedDib, sizeof(BITMAPINFOHEADER) + iColorTableSize);
|
|
bitmapInfo->biBitCount = m_iBitsPerPixel;
|
|
bitmapInfo->biClrUsed = 0;
|
|
bitmapInfo->biClrImportant = 0;
|
|
*myBitmapInfo = bitmapInfo;
|
|
void* pBits =
|
|
((char*)pPackedDib) + pPackedDib->bmiHeader.biSize + iColorTableSize;
|
|
int widthBytes = (((bitmapInfo->biWidth * bitmapInfo->biBitCount) + 31) && ~31) >> 3;
|
|
*bits =(char*) CDCCX::HugeAlloc(widthBytes * bitmapInfo->biHeight, 1);
|
|
memcpy(bits, pBits, widthBytes * bitmapInfo->biHeight);
|
|
// done, clean up
|
|
UnlockResource(hRes);
|
|
BOOL bResult = FreeResource(hRes);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void CDCCX::DisplayIcon(int32 x0, int32 y0, int icon_number)
|
|
{
|
|
unsigned int bitmapID; // resource ID of bitmap to load
|
|
unsigned int maskID = 0; // resource ID of mask (if any)
|
|
|
|
if (icon_number < 0)
|
|
return;
|
|
|
|
int x, y;
|
|
LTRB Rect;
|
|
|
|
for (int i = 0; i < ICONMAPSIZE ; i++) {
|
|
if (iconMap[i].iIconNum == icon_number) {
|
|
x = iconMap[i].x;
|
|
y = iconMap[i].y;
|
|
bitmapID = iconMap[i].bitmapID;
|
|
maskID = iconMap[i].maskID;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i == ICONMAPSIZE) { // used default icon here.
|
|
x = GOPHER_ICON_SIZE;
|
|
y = GOPHER_ICON_SIZE + 1;
|
|
bitmapID = IDB_FILE;
|
|
maskID = IDB_GOPHER_AUDIO_MASK;
|
|
}
|
|
|
|
int width = CASTINT(Pix2TwipsX(x));
|
|
int height = CASTINT(Pix2TwipsY(y));
|
|
|
|
if (ResolveElement(Rect, x0, y0, 0, 0, width, height)) {
|
|
SafeSixteen(Rect);
|
|
|
|
HBITMAP hBitmap = NULL;
|
|
HDC hdc = GetContextDC();
|
|
|
|
#ifdef XP_WIN32
|
|
if (icon_number == IL_IMAGE_DELAYED) {
|
|
static HICON hIcon=NULL;
|
|
|
|
// The icon is represented as a small icon resource which is 16x16 pixels
|
|
if(!hIcon)
|
|
hIcon = (HICON)::LoadImage(AfxGetResourceHandle(),
|
|
MAKEINTRESOURCE(IDI_IMAGE_DELAYED), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
|
|
|
|
VERIFY(::DrawIconEx(hdc, CASTINT(Rect.left), CASTINT(Rect.top),
|
|
hIcon, Pix2TwipsX(16), Pix2TwipsY(16), 0, NULL, DI_NORMAL));
|
|
|
|
/* don't destroy hIcon because it's static */
|
|
|
|
// return;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
// load the bitmap out of the resource file
|
|
HBITMAP mask;
|
|
if (!IsPrintContext()) {
|
|
hBitmap = LOADBITMAP(bitmapID);
|
|
if(maskID)
|
|
mask = LOADBITMAP(maskID);
|
|
|
|
HBITMAP hOldBitmap = NULL;
|
|
|
|
if(maskID) {
|
|
if (IsPrintContext()) {
|
|
HBITMAP hOldBitmap = (HBITMAP)::SelectObject(m_pImageDC, hBitmap);
|
|
// filled in the background color for transparent bitmap.
|
|
AlterBackgroundColor(m_pImageDC, x, y, mask,
|
|
(HBRUSH)::GetStockObject(WHITE_BRUSH));
|
|
::StretchBlt(hdc,
|
|
CASTINT(Rect.left),
|
|
CASTINT(Rect.top),
|
|
CASTINT(width),
|
|
CASTINT(height),
|
|
m_pImageDC,
|
|
CASTINT(0),
|
|
CASTINT(0),
|
|
CASTINT(x),
|
|
CASTINT(y),
|
|
SRCCOPY);
|
|
::SelectObject(m_pImageDC, hOldBitmap);
|
|
}
|
|
else {
|
|
// load the mask out of the resource file
|
|
StretchMaskBlt(hdc, hBitmap, mask,
|
|
Rect.left, Rect.top, width, height,
|
|
0, 0, x, y);
|
|
}
|
|
VERIFY(::DeleteObject(mask));
|
|
}
|
|
else {
|
|
// load the bitmap into the cached image CDC
|
|
hOldBitmap = (HBITMAP) ::SelectObject(m_pImageDC, hBitmap);
|
|
|
|
::StretchBlt(hdc,
|
|
CASTINT(Rect.left),
|
|
CASTINT(Rect.top),
|
|
CASTINT(width),
|
|
CASTINT(height),
|
|
m_pImageDC,
|
|
CASTINT(0),
|
|
CASTINT(0),
|
|
CASTINT(x),
|
|
CASTINT(y),
|
|
SRCCOPY);
|
|
::SelectObject(m_pImageDC, hOldBitmap);
|
|
}
|
|
|
|
// restore the old bitmap
|
|
VERIFY(::DeleteObject(hBitmap));
|
|
}
|
|
else { // printing icon
|
|
char* image_bits = NULL;
|
|
BITMAPINFOHEADER* imageInfo = NULL;
|
|
char* mask_bits = NULL;
|
|
BITMAPINFOHEADER* maskInfo = NULL;
|
|
if (cxLoadBitmap(MAKEINTRESOURCE(bitmapID), &image_bits, &imageInfo)) {
|
|
if(maskID) {
|
|
BOOL fillBack = TRUE;
|
|
#ifdef MOZ_NGLAYOUT
|
|
XP_ASSERT(0);
|
|
#else
|
|
#ifdef XP_WIN32
|
|
CPrintCX* pPrintCx = (CPrintCX*)this;
|
|
fillBack = pPrintCx->IsPrintingBackground() ? FALSE : TRUE;
|
|
#endif
|
|
#endif
|
|
cxLoadBitmap(MAKEINTRESOURCE(maskID), &mask_bits, &maskInfo);
|
|
WFE_StretchDIBitsWithMask(hdc,TRUE, m_pImageDC,
|
|
CASTINT(Rect.left),
|
|
CASTINT(Rect.top),
|
|
CASTINT(width),
|
|
CASTINT(height),
|
|
CASTINT(0),
|
|
CASTINT(0),
|
|
CASTINT(x),
|
|
CASTINT(y),
|
|
image_bits,
|
|
(BITMAPINFO*)imageInfo,
|
|
mask_bits,
|
|
m_bUseDibPalColors,
|
|
fillBack);
|
|
}
|
|
else {
|
|
::StretchDIBits(hdc,
|
|
CASTINT(Rect.left),
|
|
CASTINT(Rect.top),
|
|
CASTINT(width),
|
|
CASTINT(height),
|
|
CASTINT(0),
|
|
CASTINT(0),
|
|
CASTINT(x),
|
|
CASTINT(y),
|
|
image_bits,
|
|
(BITMAPINFO*)imageInfo,
|
|
DIB_RGB_COLORS,
|
|
SRCCOPY);
|
|
}
|
|
}
|
|
|
|
if (image_bits)
|
|
delete image_bits;
|
|
if (imageInfo)
|
|
delete imageInfo;
|
|
if(maskID) {
|
|
if (mask_bits)
|
|
delete mask_bits;
|
|
if (maskInfo)
|
|
delete maskInfo;
|
|
}
|
|
}
|
|
}
|
|
ReleaseContextDC(hdc);
|
|
}
|
|
}
|
|
|
|
int CDCCX::GetUrl(URL_Struct *pUrl, FO_Present_Types iFormatOut, BOOL bReallyLoading, BOOL bForceNew) {
|
|
// Save the location of the current document, if not at the very top.
|
|
// Reset to top, then see if we need to change more....
|
|
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 */
|
|
|
|
// Handle forced image loading.
|
|
m_csForceLoadImage = m_csNexttimeForceLoadImage;
|
|
m_csNexttimeForceLoadImage.Empty();
|
|
m_bLoadImagesNow = m_bNexttimeLoadImagesNow;
|
|
m_bNexttimeLoadImagesNow = FALSE;
|
|
|
|
// Call the base.
|
|
return(CStubsCX::GetUrl(pUrl, iFormatOut, bReallyLoading, bForceNew));
|
|
}
|
|
|
|
// rewrite the BULLET_BASIC and BULLET_DISC part
|
|
// the origional "o" approach cause a lot of problem in non-LATIN page
|
|
void CDCCX::DisplayBullet(MWContext *pContext, int iLocation, LO_BullettStruct *pBullet) {
|
|
// Figure the coordinates.
|
|
LTRB Rect;
|
|
int reduce;
|
|
// if(ResolveElement(Rect, pBullet, iLocation) == TRUE) {
|
|
if (ResolveElement(Rect, pBullet->x, pBullet->y,
|
|
pBullet->x_offset, pBullet->y_offset,
|
|
pBullet->width, pBullet->height) == TRUE) {
|
|
SafeSixteen(Rect);
|
|
|
|
COLORREF rgbBullet = ResolveTextColor(pBullet->text_attr);
|
|
HDC hdc = GetContextDC();
|
|
|
|
int w;
|
|
if( pBullet->bullet_type == BULLET_MQUOTE
|
|
|| pBullet->bullet_type == BULLET_SQUARE ) {
|
|
w = 1;
|
|
} else {
|
|
w = CASTINT( (Rect.bottom - Rect.top) / 10);
|
|
if(w < 1)
|
|
w = 1;
|
|
}
|
|
|
|
HPEN hpen = ::CreatePen(PS_SOLID,w,rgbBullet);
|
|
HPEN oldPen = (HPEN)::SelectObject(hdc,hpen);
|
|
|
|
// draw_bullet_with_Ellipse
|
|
HBRUSH hBrush = ::CreateSolidBrush(rgbBullet);
|
|
HBRUSH hOldBrush = (HBRUSH)::SelectObject(hdc, hBrush);
|
|
|
|
switch(pBullet->bullet_type) {
|
|
|
|
case BULLET_MQUOTE:
|
|
// BUG#61210 draw quote as one pixel bar on the left
|
|
#if defined (WIN32)
|
|
::MoveToEx(hdc, CASTINT(Rect.left), CASTINT(Rect.top), NULL);
|
|
#else
|
|
::MoveTo(hdc, CASTINT(Rect.left), CASTINT(Rect.top));
|
|
#endif
|
|
::LineTo(hdc,CASTINT(Rect.left), CASTINT(Rect.bottom));
|
|
break;
|
|
case BULLET_SQUARE:
|
|
// Size of square is too large relative to solid and open circle,
|
|
// so reduce a little
|
|
Rect.top++;
|
|
Rect.bottom--;
|
|
Rect.left++;
|
|
Rect.right--;
|
|
::Rectangle(hdc, CASTINT(Rect.left), CASTINT(Rect.top), CASTINT(Rect.right), CASTINT(Rect.bottom));
|
|
break;
|
|
|
|
case BULLET_NONE:
|
|
// Do nothing
|
|
break;
|
|
|
|
case BULLET_BASIC: // solid bullet
|
|
case BULLET_ROUND : // todo ::RoundRect()?
|
|
default : // Circle
|
|
if( BULLET_BASIC != pBullet->bullet_type ) { // Circle
|
|
// don't touch hOldBrush, put hOldBrush back after draw.
|
|
::SelectObject(hdc, ::GetStockObject(NULL_BRUSH));
|
|
}
|
|
reduce = (Rect.bottom - Rect.top ) / 4;
|
|
::Ellipse(hdc, CASTINT(Rect.left+reduce), CASTINT(Rect.top+reduce),
|
|
CASTINT(Rect.right-reduce), CASTINT(Rect.bottom-reduce));
|
|
break;
|
|
}
|
|
::SelectObject(hdc, hOldBrush);
|
|
VERIFY(::DeleteObject( hBrush ));
|
|
|
|
::SelectObject(hdc,oldPen);
|
|
::DeleteObject(hpen);
|
|
// end of draw_bullet_with_Ellipse
|
|
|
|
ReleaseContextDC(hdc);
|
|
}
|
|
}
|
|
|
|
#ifdef Frank_code
|
|
void CDCCX::DisplayBullet(MWContext *pContext, int iLocation, LO_BullettStruct *pBullet) {
|
|
// Figure the coordinates.
|
|
LTRB Rect;
|
|
// if(ResolveElement(Rect, pBullet, iLocation) == TRUE) {
|
|
if (ResolveElement(Rect, pBullet->x, pBullet->y,
|
|
pBullet->x_offset, pBullet->y_offset,
|
|
pBullet->width, pBullet->height) == TRUE) {
|
|
SafeSixteen(Rect);
|
|
|
|
COLORREF rgbBullet = ResolveTextColor(pBullet->text_attr);
|
|
HDC hdc = GetContextDC();
|
|
|
|
|
|
Rect.top++;
|
|
Rect.bottom--;
|
|
Rect.left++;
|
|
Rect.right--;
|
|
|
|
switch(pBullet->bullet_type) {
|
|
|
|
case BULLET_MQUOTE:
|
|
case BULLET_SQUARE: {
|
|
HBRUSH hBrush = ::CreateSolidBrush(rgbBullet);
|
|
HBRUSH hOldBrush = (HBRUSH)::SelectObject(hdc, hBrush);
|
|
|
|
::Rectangle(hdc, CASTINT(Rect.left), CASTINT(Rect.top), CASTINT(Rect.right), CASTINT(Rect.bottom));
|
|
::SelectObject(hdc, hOldBrush);
|
|
VERIFY(::DeleteObject( hBrush ));
|
|
break;
|
|
}
|
|
|
|
case BULLET_BASIC: {
|
|
HBRUSH hBrush = ::CreateSolidBrush(rgbBullet);
|
|
HBRUSH hOldBrush = (HBRUSH)::SelectObject(hdc, hBrush);
|
|
|
|
::Ellipse(hdc, CASTINT(Rect.left), CASTINT(Rect.top), CASTINT(Rect.right), CASTINT(Rect.bottom));
|
|
::SelectObject(hdc, hOldBrush);
|
|
VERIFY(::DeleteObject( hBrush ));
|
|
break;
|
|
|
|
}
|
|
|
|
default: {
|
|
int w = CASTINT( (Rect.bottom - Rect.top) / 10);
|
|
if(w < 1)
|
|
w = 1;
|
|
HBRUSH hBrush = (HBRUSH)::GetStockObject(NULL_BRUSH);
|
|
HBRUSH hOldBrush = (HBRUSH)::SelectObject(hdc, hBrush);
|
|
HPEN hStrike = ::CreatePen(PS_SOLID, CASTINT( w ), rgbBullet);
|
|
HPEN hOldStrike = (HPEN)::SelectObject(hdc, hStrike);
|
|
|
|
::Ellipse(hdc, CASTINT(Rect.left), CASTINT(Rect.top), CASTINT(Rect.right), CASTINT(Rect.bottom));
|
|
::SelectObject(hdc, hOldBrush);
|
|
// Don't delete hBrush since it is a stock object
|
|
|
|
::SelectObject(hdc, hOldStrike);
|
|
VERIFY(::DeleteObject( hStrike ));
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
ReleaseContextDC(hdc);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// Display a border of the specified size and color. x, y, width and height
|
|
// refer to the outside perimeter of the border.
|
|
void CDCCX::DisplayBorder(MWContext *pContext, int iLocation, int x, int y, int width, int height, int bw, LO_Color *color, LO_LineStyle style)
|
|
{
|
|
LTRB Rect;
|
|
|
|
if (bw) {
|
|
// Adjust the input parameters so that they describe the inside
|
|
// perimeter of the border. Don't do this for 3D borders since
|
|
// Draw3DBox does this for us.
|
|
if (style != LO_BEVEL) {
|
|
x += bw;
|
|
y += bw;
|
|
width -= 2 * bw;
|
|
height -= 2 * bw;
|
|
}
|
|
|
|
if (ResolveElement(Rect, x, y, 0, 0, width, height)) {
|
|
SafeSixteen(Rect);
|
|
|
|
// Call the method which really draws the border.
|
|
switch(style) {
|
|
case LO_SOLID:
|
|
DrawRectBorder(Rect, ResolveLOColor(color), bw);
|
|
break;
|
|
|
|
case LO_BEVEL:
|
|
Display3DBox(Rect, ResolveDarkLineColor(),
|
|
ResolveLightLineColor(), Pix2TwipsX(bw), FALSE);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void CDCCX::DisplayImageFeedback(MWContext *pContext, int iLocation, LO_Element *pElement, lo_MapAreaRec * theArea, uint32 drawFlag )
|
|
{
|
|
if (pElement->lo_any.type == LO_IMAGE) {
|
|
LO_ImageStruct *pImage = (LO_ImageStruct *)pElement;
|
|
LTRB Rect;
|
|
int borderWidth = CASTINT(pImage->border_width);
|
|
int x = CASTINT(pImage->x + pImage->x_offset + borderWidth);
|
|
int y = CASTINT(pImage->y + pImage->y_offset + borderWidth);
|
|
|
|
if (ResolveElement(Rect, x, y, 0, 0, pImage->width, pImage->height)) {
|
|
SafeSixteen(Rect);
|
|
|
|
DisplaySelectionFeedback(pImage->ele_attrmask, Rect);
|
|
|
|
//#ifndef NO_TAB_NAVIGATION
|
|
if((FE_DRAW_TAB_FOCUS & drawFlag) &&
|
|
pImage->suppress_mode != LO_SUPPRESS) {
|
|
|
|
// use the Rect from code above.
|
|
if( theArea != NULL) {
|
|
// It is a focused area in map, draw a focus border.
|
|
DrawMapAreaBorder( CASTINT(Rect.left), CASTINT(Rect.top), theArea );
|
|
} else {
|
|
// draw a focus border for the whole image
|
|
lo_MapAreaRec area;
|
|
int32 coord[4];
|
|
area.coords = coord;
|
|
area.type = AREA_SHAPE_RECT ;
|
|
area.coord_cnt = 4;
|
|
area.coords[0] = Rect.left;
|
|
area.coords[1] = Rect.top;
|
|
area.coords[2] = Rect.right;
|
|
area.coords[3] = Rect.bottom;
|
|
DrawMapAreaBorder( 0, 0, &area );
|
|
}
|
|
}
|
|
//#endif /* NO_TAB_NAVIGATION */
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
BOOL CDCCX::IsPluginFullPage(LO_EmbedStruct *pLayoutData)
|
|
{
|
|
// 1x1 size is signal that plugin is full page, not embedded
|
|
if((pLayoutData->objTag.width == Pix2TwipsX(1))
|
|
&& (pLayoutData->objTag.height == Pix2TwipsX(1)))
|
|
return TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
// returns TRUE if there is a plugin on the page and that plugin
|
|
// is of pluginType == NPWFE_FULL_PAGE. There can be only one
|
|
// plugin on a page that contains a NPWFE_FULL_PAGE plugin.
|
|
BOOL CDCCX::ContainsFullPagePlugin()
|
|
{
|
|
NPEmbeddedApp* pEmbeddedApp = GetContext()->pluginList;
|
|
if(pEmbeddedApp) {
|
|
if(pEmbeddedApp->pagePluginType == NP_FullPage)
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
// Determine location of plugin rect, convert from TWIPS to PIXELS
|
|
void CDCCX::GetPluginRect(MWContext *pContext,
|
|
LO_EmbedStruct *pLayoutData,
|
|
RECT &rect, int iLocation,
|
|
BOOL windowed)
|
|
{
|
|
if(IsPluginFullPage(pLayoutData))
|
|
{
|
|
::GetClientRect(PANECX(pContext)->GetPane(), &rect);
|
|
}
|
|
else // plugin embedded in page
|
|
{
|
|
// get the display area and clamp it
|
|
LTRB Rect;
|
|
ResolveElement(Rect, pLayoutData, iLocation, windowed);
|
|
|
|
SafeSixteen(Rect);
|
|
rect.left = (int)Rect.left;
|
|
rect.top = (int)Rect.top;
|
|
rect.right = (int)Rect.right;
|
|
rect.bottom = (int)Rect.bottom;
|
|
}
|
|
}
|
|
|
|
void CDCCX::DisplayWindowlessPlugin(MWContext *pContext,
|
|
LO_EmbedStruct *pEmbed,
|
|
NPEmbeddedApp *pEmbeddedApp,
|
|
int iLocation)
|
|
{
|
|
RECT rect;
|
|
NPWindow* pAppWin = pEmbeddedApp->wdata;
|
|
HDC hDC = GetContextDC();
|
|
NPEvent event;
|
|
FE_Region clip;
|
|
|
|
// Get the coordinates of where it should be positioned
|
|
GetPluginRect(pContext, pEmbed, rect, iLocation, FALSE);
|
|
|
|
if ((pAppWin->window != (void *)hDC) ||
|
|
(pAppWin->x != (uint32) rect.left) ||
|
|
(pAppWin->y != (uint32) rect.top) ||
|
|
(pAppWin->width != (uint32) (rect.right - rect.left)) ||
|
|
(pAppWin->height != (uint32) (rect.bottom - rect.top)))
|
|
{
|
|
pAppWin->window = (void *)hDC;
|
|
pAppWin->x = rect.left;
|
|
pAppWin->y = rect.top;
|
|
pAppWin->width = rect.right - rect.left;
|
|
pAppWin->height = rect.bottom - rect.top;
|
|
pAppWin->type = NPWindowTypeDrawable;
|
|
|
|
#ifdef MOZ_NGLAYOUT
|
|
XP_ASSERT(0);
|
|
#else
|
|
NPL_EmbedSize(pEmbeddedApp);
|
|
#endif
|
|
}
|
|
|
|
#ifdef LAYERS
|
|
clip = GetDrawingClip();
|
|
if (clip)
|
|
{
|
|
XP_Rect xprect;
|
|
|
|
FE_GetRegionBoundingBox(clip, &xprect);
|
|
rect.left = CASTINT(xprect.left);
|
|
rect.top = CASTINT(xprect.top);
|
|
rect.right = CASTINT(xprect.right);
|
|
rect.bottom = CASTINT(xprect.bottom);
|
|
}
|
|
#endif /* LAYERS */
|
|
|
|
event.event = WM_PAINT;
|
|
event.wParam = (uint32)hDC;
|
|
event.lParam = (uint32)▭
|
|
|
|
#ifdef MOZ_NGLAYOUT
|
|
XP_ASSERT(0);
|
|
#else
|
|
NPL_HandleEvent(pEmbeddedApp, (void *)&event, pAppWin->window);
|
|
#endif
|
|
|
|
ReleaseContextDC(hDC);
|
|
}
|
|
|
|
|
|
// create a window and pass its offset/size to the plugin
|
|
void CDCCX::DisplayPlugin(MWContext *pContext, LO_EmbedStruct *pEmbed,
|
|
NPEmbeddedApp* pEmbeddedApp, int iLocation)
|
|
{
|
|
RECT rect;
|
|
NPWindow* pAppWin = pEmbeddedApp->wdata;
|
|
|
|
if(pAppWin->window == NULL)
|
|
return;
|
|
|
|
if (::IsWindowVisible((HWND)pAppWin->window) &&
|
|
(pEmbed->objTag.ele_attrmask & LO_ELE_INVISIBLE))
|
|
::ShowWindow((HWND)pAppWin->window, SW_HIDE);
|
|
|
|
// If the plugin is embedded we need to make sure the window is
|
|
// positioned properly
|
|
if (!IsPluginFullPage(pEmbed)) {
|
|
RECT curRect;
|
|
|
|
// Get the coordinates of where it should be positioned
|
|
GetPluginRect(pContext, pEmbed, rect, iLocation, TRUE);
|
|
|
|
// Get the current coordinates relative to the parent window's
|
|
// client area
|
|
::GetWindowRect((HWND)pAppWin->window, &curRect);
|
|
MapWindowPoints(NULL, ::GetParent((HWND)pAppWin->window),
|
|
(POINT FAR *)&curRect, 2);
|
|
|
|
// Only move/size the window if necessary
|
|
if ((rect.left != curRect.left) ||
|
|
(rect.right != curRect.right) ||
|
|
(rect.top != curRect.top) ||
|
|
(rect.bottom != curRect.bottom)){
|
|
::SetWindowPos((HWND)pAppWin->window, NULL, rect.left, rect.top,
|
|
rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER | SWP_NOACTIVATE);
|
|
|
|
}
|
|
|
|
// Update the NPWindow rect
|
|
pAppWin->x = rect.left;
|
|
pAppWin->y = rect.top;
|
|
pAppWin->width = rect.right - rect.left;
|
|
pAppWin->height = rect.bottom - rect.top;
|
|
}
|
|
|
|
if (!::IsWindowVisible((HWND)pAppWin->window) &&
|
|
!(pEmbed->objTag.ele_attrmask & LO_ELE_INVISIBLE))
|
|
::ShowWindow((HWND)pAppWin->window, SW_SHOW);
|
|
|
|
}
|
|
|
|
#ifndef MOZ_NGLAYOUT
|
|
|
|
void CDCCX::DisplayEmbed(MWContext *pContext, int iLocation, LO_EmbedStruct *pEmbed)
|
|
{
|
|
NPEmbeddedApp* pEmbeddedApp = (NPEmbeddedApp*)pEmbed->objTag.FE_Data;
|
|
|
|
if(pEmbeddedApp == NULL)
|
|
return;
|
|
|
|
if(wfe_IsTypePlugin(pEmbeddedApp)) {
|
|
if (NPL_IsEmbedWindowed(pEmbeddedApp)) {
|
|
DisplayPlugin(pContext, pEmbed, pEmbeddedApp, iLocation);
|
|
(void)NPL_EmbedSize(pEmbeddedApp);
|
|
}
|
|
else
|
|
DisplayWindowlessPlugin(pContext, pEmbed, pEmbeddedApp, iLocation);
|
|
|
|
if(IsPluginFullPage(pEmbed))
|
|
pEmbeddedApp->pagePluginType = NP_FullPage;
|
|
else
|
|
pEmbeddedApp->pagePluginType = NP_Embedded;
|
|
return;
|
|
}
|
|
|
|
// else must be an OLE display
|
|
LTRB Rect;
|
|
if(ResolveElement(Rect, pEmbed, iLocation, FALSE) == TRUE) {
|
|
int32 lOrgX, lOrgY;
|
|
|
|
GetDrawingOrigin(&lOrgX, &lOrgY);
|
|
SafeSixteen(Rect);
|
|
|
|
// Draw a border around the embed if needed.
|
|
if(pEmbed->objTag.border_width != 0) {
|
|
DrawRectBorder(Rect, ResolveBorderColor(NULL), pEmbed->objTag.border_width);
|
|
}
|
|
|
|
// Get the embedded item
|
|
CNetscapeCntrItem *pItem = (CNetscapeCntrItem *)pEmbeddedApp->fe_data;
|
|
if(pItem == NULL) {
|
|
DisplayIcon(Rect.left, Rect.top, IL_IMAGE_BAD_DATA);
|
|
return;
|
|
}
|
|
|
|
// Handle delayed, broken, and currently loading items.
|
|
else if(pItem->m_bDelayed == TRUE) {
|
|
DisplayIcon(Rect.left - lOrgX, Rect.top - lOrgY, IL_IMAGE_DELAYED);
|
|
return;
|
|
}
|
|
else if(pItem->m_bBroken == TRUE) {
|
|
DisplayIcon(Rect.left - lOrgX, Rect.top - lOrgY, IL_IMAGE_BAD_DATA);
|
|
}
|
|
else if(pItem->m_bLoading == TRUE) {
|
|
// Can't draw if still loading.
|
|
return;
|
|
}
|
|
|
|
// Okay to draw.
|
|
HDC hdc = GetContextDC();
|
|
RECT crRect;
|
|
::SetRect(&crRect, (int)Rect.left,(int)Rect.top,(int)Rect.right,(int)Rect.bottom);
|
|
CDC dc;
|
|
dc.Attach(hdc);
|
|
COLORREF backgroundColor = (COLORREF)GetSysColor(COLOR_WINDOW);
|
|
HBRUSH tempBrush = ::CreateSolidBrush(backgroundColor);
|
|
::FillRect(dc.GetSafeHdc(), &crRect,tempBrush);
|
|
::DeleteObject(tempBrush);
|
|
if (pItem->IsInPlaceActive()) {
|
|
if (!pItem->m_bSetExtents) {
|
|
pItem->m_bSetExtents = TRUE;
|
|
SIZEL temp1;
|
|
temp1.cx = Twips2MetricX(crRect.right - crRect.left);
|
|
temp1.cy = Twips2MetricY(crRect.bottom - crRect.top);
|
|
HRESULT sc = pItem->m_lpObject->SetExtent(DVASPECT_CONTENT, &temp1);
|
|
sc = pItem->m_lpObject->Update();
|
|
}
|
|
crRect.left += sysInfo.m_iScrollWidth + sysInfo.m_iBorderWidth;
|
|
crRect.top += sysInfo.m_iScrollHeight + sysInfo.m_iBorderHeight;
|
|
crRect.right -= sysInfo.m_iScrollWidth + sysInfo.m_iBorderWidth;
|
|
crRect.bottom -= sysInfo.m_iScrollHeight + sysInfo.m_iBorderHeight;
|
|
pItem->SetItemRects(&crRect);
|
|
}
|
|
pItem->Draw(&dc, &crRect);
|
|
dc.Detach();
|
|
ReleaseContextDC(hdc);
|
|
}
|
|
}
|
|
#endif /* MOZ_NGLAYOUT */
|
|
|
|
void CDCCX::DisplayHR(MWContext *pContext, int iLocation, LO_HorizRuleStruct *pHorizRule)
|
|
{
|
|
// Figure out the coordinates of where to draw the HR.
|
|
LTRB Rect;
|
|
// if(ResolveElement(Rect, pHorizRule, iLocation) == TRUE) {
|
|
if(ResolveElement(Rect, pHorizRule->x,pHorizRule->y,
|
|
pHorizRule->x_offset, pHorizRule->y_offset,
|
|
pHorizRule->width, pHorizRule->height) == TRUE) {
|
|
SafeSixteen(Rect);
|
|
|
|
#ifdef EDITOR
|
|
// Don't draw the editor's end-of-document hrule unless we're
|
|
// displaying paragraph marks.
|
|
if ( pHorizRule->edit_offset < 0 && ! EDT_DISPLAY_PARAGRAPH_MARKS(pContext) ) {
|
|
return;
|
|
}
|
|
|
|
// Increase height of selection rect if it is very small
|
|
LTRB SelRect = Rect;
|
|
if( SelRect.Height() < 6 )
|
|
{
|
|
SelRect.top -= (6 - SelRect.Height())/2;
|
|
SelRect.bottom = SelRect.top + 6;
|
|
}
|
|
// EraseToBackground(SelRect);
|
|
#endif /* EDITOR */
|
|
|
|
// Find out if we are doing a solid or 3D HR.
|
|
if(ResolveHRSolid(pHorizRule) == TRUE) {
|
|
HDC hdc = GetContextDC();
|
|
|
|
// Draw a solid HR.
|
|
// We'll be using the darker color to do this.
|
|
COLORREF rgbColor = ResolveDarkLineColor();
|
|
|
|
HPEN cpHR = ::CreatePen(PS_SOLID, CASTINT(Pix2TwipsY(pHorizRule->thickness)), rgbColor);
|
|
HPEN pOldPen = (HPEN)::SelectObject(hdc, cpHR);
|
|
if(MMIsText() == TRUE) {
|
|
::MoveToEx(hdc, CASTINT(Rect.left), CASTINT(Rect.top + Rect.Height() / 2), NULL);
|
|
::LineTo(hdc, CASTINT(Rect.right), CASTINT(Rect.top + Rect.Height() / 2)); // use top, or diagonal.
|
|
}
|
|
else {
|
|
::MoveToEx(hdc, CASTINT(Rect.left), CASTINT(Rect.top), NULL);
|
|
::LineTo(hdc, CASTINT(Rect.right), CASTINT(Rect.top)); // use top, or diagonal.
|
|
}
|
|
::SelectObject(hdc, pOldPen);
|
|
VERIFY(::DeleteObject(cpHR));
|
|
|
|
ReleaseContextDC(hdc);
|
|
}
|
|
else {
|
|
Display3DBox(Rect, ResolveDarkLineColor(), ResolveLightLineColor(),
|
|
Pix2TwipsX(1), TRUE);
|
|
}
|
|
#ifdef EDITOR
|
|
DisplaySelectionFeedback(pHorizRule->ele_attrmask, SelRect);
|
|
#endif //EDITOR
|
|
}
|
|
}
|
|
|
|
// Common algorithm for setting contrasting background and text colors
|
|
void wfe_GetSelectionColors( COLORREF rgbBackgroundColor,
|
|
COLORREF* pTextColor, COLORREF* pBackColor)
|
|
{
|
|
//CLM: Always use Blue text on white or white text on blue if selecting
|
|
// Test intensity of real background so entire selection uses same colors
|
|
// This algorithm favors using dark
|
|
// Possible problem: If we have relatively bright text on a dark background image
|
|
BOOL bDarkBackground = (GetRValue(rgbBackgroundColor) +
|
|
GetGValue(rgbBackgroundColor) +
|
|
GetBValue(rgbBackgroundColor)) < 192;
|
|
|
|
if( pTextColor ){
|
|
*pTextColor = bDarkBackground ? RGB(0,0,128) : RGB(255,255,255);
|
|
}
|
|
if( pBackColor ){
|
|
*pBackColor = bDarkBackground ? RGB(255,255,255) : RGB(0,0,128);
|
|
}
|
|
}
|
|
|
|
|
|
void CDCCX::DisplayLineFeed(MWContext *pContext, int iLocation, LO_LinefeedStruct *pLineFeed, XP_Bool clear)
|
|
{
|
|
LTRB Rect;
|
|
Bool bElementResolved;
|
|
Bool bSpecialDrawing = EDT_IS_EDITOR(pContext) && pLineFeed->break_type;
|
|
|
|
#ifdef EDITOR
|
|
// Allow selection feedback and display of end-of-paragraph marks in the editor.
|
|
// We do nothing if we're not in the editor.
|
|
// We do nothing if this isn't an end-of-paragraph or hard break.
|
|
// If we're displaying the marks, then we display them as little squares.
|
|
// Otherwise we just do the selection feedback.
|
|
// The selection feedback is a rectangle the height of the linefeed 1/2 of the rectangle's height.
|
|
// located at the left edge of the linefeed's range.
|
|
|
|
// We need to expand the linefeed's width here so that ResolveElement thinks it's at least as wide
|
|
// as we're going to draw it.
|
|
Bool bExpanded = FALSE;
|
|
int32 expandedWidth;
|
|
int32 expandedHeight;
|
|
if ( bSpecialDrawing ) {
|
|
const int32 kMinimumWidth = 7;
|
|
const int32 kMinimumHeight = 12;
|
|
|
|
int32 originalWidth = pLineFeed->width;
|
|
int32 originalHeight= pLineFeed->height;
|
|
expandedWidth = originalWidth;
|
|
expandedHeight = originalHeight;
|
|
|
|
if ( expandedWidth < kMinimumWidth ) {
|
|
expandedWidth = kMinimumWidth;
|
|
bExpanded = TRUE;
|
|
}
|
|
if ( expandedHeight < kMinimumHeight ) {
|
|
expandedHeight = kMinimumHeight;
|
|
bExpanded = TRUE;
|
|
}
|
|
pLineFeed->width = expandedWidth;
|
|
pLineFeed->height = expandedHeight;
|
|
// bElementResolved = ResolveElement(Rect, pLineFeed, iLocation);
|
|
bElementResolved = ResolveElement(Rect, pLineFeed->x, pLineFeed->y,
|
|
pLineFeed->x_offset,pLineFeed->y_offset,
|
|
pLineFeed->width, pLineFeed->height);
|
|
pLineFeed->width = originalWidth;
|
|
pLineFeed->height = originalHeight;
|
|
}
|
|
else
|
|
{
|
|
// bElementResolved = ResolveElement(Rect, pLineFeed, iLocation);
|
|
bElementResolved = ResolveElement(Rect, pLineFeed->x, pLineFeed->y,
|
|
pLineFeed->x_offset, pLineFeed->y_offset,
|
|
pLineFeed->width, pLineFeed->height);
|
|
}
|
|
#else
|
|
// bElementResolved = ResolveElement(Rect, pLineFeed, iLocation);
|
|
bElementResolved = ResolveElement(Rect, pLineFeed->x, pLineFeed->y,
|
|
pLineFeed->x_offset, pLineFeed->y_offset,
|
|
pLineFeed->width, pLineFeed->height);
|
|
#endif
|
|
|
|
if (bElementResolved) {
|
|
SafeSixteen(Rect);
|
|
|
|
if ( ! EDT_IS_EDITOR(pContext) || ! pLineFeed->break_type ) {
|
|
// If the linefeed has a solid background color, then use it.
|
|
// To Be Done: If we're selected, use the fg color instead of the bg color.
|
|
#ifndef LAYERS
|
|
// For layers, we don't want to draw the background
|
|
if (pLineFeed->text_attr->no_background == FALSE && !IsPrintContext()) {
|
|
HBRUSH hBrush;
|
|
CRect cRect(CASTINT(Rect.left), CASTINT(Rect.top), CASTINT(Rect.right), CASTINT(Rect.bottom));
|
|
HDC hdc = GetContextDC(iLocation);
|
|
|
|
if (m_iBitsPerPixel == 16)
|
|
// We don't want a dithered brush
|
|
hBrush = ::CreateSolidBrush(::GetNearestColor(hdc, RGB(pLineFeed->text_attr->bg.red,
|
|
pLineFeed->text_attr->bg.green, pLineFeed->text_attr->bg.blue)));
|
|
else
|
|
hBrush = ::CreateSolidBrush(0x02000000L | ResolveBGColor(pLineFeed->text_attr->bg.red,
|
|
pLineFeed->text_attr->bg.green, pLineFeed->text_attr->bg.blue));
|
|
HBRUSH hOldBrush;
|
|
hOldBrush = ::SelectObject(hdc, hBrush);
|
|
::FillRect(hdc, &cRect, hBrush);
|
|
::SelectObject(hdc, hOldBrush);
|
|
VERIFY(::DeleteObject(hBrush));
|
|
|
|
ReleaseContextDC(hdc, iLocation);
|
|
}
|
|
#endif // LAYERS
|
|
return;
|
|
}
|
|
|
|
HDC hdc = GetContextDC();
|
|
RECT r;
|
|
::SetRect(&r, CASTINT(Rect.left), CASTINT(Rect.top), CASTINT(Rect.right), CASTINT(Rect.bottom));
|
|
// Need to look up the text color.
|
|
LO_TextAttr * attr = pLineFeed->text_attr;
|
|
|
|
// Determine the color.
|
|
COLORREF rgbColor = ResolveTextColor(attr);
|
|
COLORREF textBackColor;
|
|
Bool selected = pLineFeed->ele_attrmask & LO_ELE_SELECTED;
|
|
|
|
if ( selected ) {
|
|
wfe_GetSelectionColors(m_rgbBackgroundColor, &rgbColor, &textBackColor);
|
|
}
|
|
|
|
if (clear & ! selected) {
|
|
#ifdef EDITOR
|
|
// If the linefeed has a solid background color, then use it
|
|
if (pLineFeed->text_attr->no_background == FALSE && !IsPrintContext()) {
|
|
HBRUSH hBrush;
|
|
RECT cRect;
|
|
::SetRect(&cRect, CASTINT(Rect.left), CASTINT(Rect.top), CASTINT(Rect.right), CASTINT(Rect.bottom));
|
|
|
|
if (m_iBitsPerPixel == 16)
|
|
// We don't want a dithered brush
|
|
hBrush = ::CreateSolidBrush(::GetNearestColor(hdc, RGB(pLineFeed->text_attr->bg.red,
|
|
pLineFeed->text_attr->bg.green, pLineFeed->text_attr->bg.blue)));
|
|
else
|
|
hBrush = ::CreateSolidBrush(0x02000000L | ResolveBGColor(pLineFeed->text_attr->bg.red,
|
|
pLineFeed->text_attr->bg.green, pLineFeed->text_attr->bg.blue));
|
|
::FillRect(hdc, &cRect, hBrush);
|
|
VERIFY(::DeleteObject(hBrush));
|
|
}
|
|
else {
|
|
EraseToBackground(Rect);
|
|
}
|
|
// If this linefeed draws outside it bounds, then
|
|
// EraseToBackground could have
|
|
// smashed a nearby element.
|
|
// So invalidate this portion. (The main examples of this are
|
|
// linefeeds in tables.)
|
|
if ( bExpanded && IsWindowContext()) {
|
|
::InvalidateRect(PANECX(pContext)->GetPane(), &r, FALSE);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#ifdef EDITOR
|
|
// Limit the size of the drawn paragraph marker.
|
|
const int32 kMaxHeight = 30;
|
|
if ( expandedHeight > kMaxHeight ){
|
|
expandedHeight = kMaxHeight;
|
|
}
|
|
int32 desiredWidth = expandedHeight / 2;
|
|
if ( expandedWidth > desiredWidth ) {
|
|
expandedWidth = desiredWidth;
|
|
}
|
|
|
|
r.right = CASTINT(r.left + expandedWidth);
|
|
r.bottom = CASTINT(r.top + expandedHeight);
|
|
|
|
#endif
|
|
if (selected) {
|
|
HBRUSH cbBrush = ::CreateSolidBrush(textBackColor);
|
|
::FillRect(hdc, &r, cbBrush);
|
|
VERIFY(::DeleteObject(cbBrush));
|
|
}
|
|
if ( EDT_DISPLAY_PARAGRAPH_MARKS(pContext)
|
|
&& (! pLineFeed->prev // Don't draw mark after end-of-doc mark
|
|
|| pLineFeed->prev->lo_any.edit_offset >= 0 ) ) {
|
|
HBRUSH cbBrush = ::CreateSolidBrush(rgbColor);
|
|
if ( r.right - r.left > 5 ) {
|
|
r.left += 2;
|
|
r.right -= 2;
|
|
}
|
|
if ( r.bottom - r.top > 5 ) {
|
|
r.top += 2;
|
|
r.bottom -= 2;
|
|
}
|
|
// draw line breaks at 1/3 height of paragraph marks
|
|
if ( pLineFeed->break_type == LO_LINEFEED_BREAK_HARD ){
|
|
r.top += (r.bottom - r.top) * 2 / 3;
|
|
}
|
|
::FillRect(hdc, &r, cbBrush);
|
|
VERIFY(::DeleteObject(cbBrush));
|
|
}
|
|
ReleaseContextDC(hdc);
|
|
}
|
|
}
|
|
|
|
void CDCCX::DisplaySubDoc(MWContext *pContext, int iLocation, LO_SubDocStruct *pSubDoc) {
|
|
LTRB Rect;
|
|
// if(ResolveElement(Rect, pSubDoc, iLocation) == TRUE) {
|
|
if(ResolveElement(Rect, pSubDoc->x, pSubDoc->y, pSubDoc->x_offset,
|
|
pSubDoc->y_offset, pSubDoc->width, pSubDoc->height) == TRUE) {
|
|
SafeSixteen(Rect);
|
|
|
|
if(pSubDoc->border_width > 0) {
|
|
Display3DBox(Rect, ResolveLightLineColor(), ResolveDarkLineColor(), pSubDoc->border_width);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CDCCX::DisplayCell(MWContext *pContext, int iLocation, LO_CellStruct *pCell) {
|
|
LTRB Rect;
|
|
if(ResolveElement(Rect, pCell->x, pCell->y, pCell->x_offset,
|
|
pCell->y_offset, pCell->width, pCell->height) == TRUE) {
|
|
SafeSixteen(Rect);
|
|
|
|
#ifndef LAYERS
|
|
// With layers, the background color is done with a layer
|
|
|
|
// If the cell has a background color, then use it
|
|
if (pCell->bg_color && !IsPrintContext()) {
|
|
HBRUSH hBrush;
|
|
RECT cRect;
|
|
::SetRect(&cRect, CASTINT(Rect.left), CASTINT(Rect.top), CASTINT(Rect.right), CASTINT(Rect.bottom));
|
|
HDC hdc = GetContextDC(iLocation);
|
|
|
|
if (m_iBitsPerPixel == 16)
|
|
// We don't want a dithered brush
|
|
hBrush = ::CreateSolidBrush(::GetNearestColor(hdc, RGB(pCell->bg_color->red,
|
|
pCell->bg_color->green, pCell->bg_color->blue)));
|
|
else
|
|
hBrush = ::CreateSolidBrush(0x02000000L | ResolveBGColor(pCell->bg_color->red,
|
|
pCell->bg_color->green, pCell->bg_color->blue));
|
|
|
|
::FillRect(hdc, &cRect, hBrush);
|
|
VERIFY(::DeleteObject(hBrush));
|
|
|
|
ReleaseContextDC(pDC, iLocation);
|
|
}
|
|
|
|
// If we decide to allow nested table cells to have the
|
|
// background show through then we need this code
|
|
#endif /* LAYERS */
|
|
|
|
#ifdef EDITOR
|
|
if( EDT_IS_EDITOR(pContext) )
|
|
{
|
|
if( pCell->border_width == 0 || LO_IsEmptyCell(pCell) )
|
|
{
|
|
// If we do this, image background doesn't show up
|
|
//EraseToBackground(Rect);
|
|
}
|
|
int32 iExtraSpace = 0;
|
|
int32 iBorder = pCell->border_width;
|
|
// Cell highlightin is thicker
|
|
int32 iMaxWidth = 2 * ED_SELECTION_BORDER;
|
|
BOOL bSelected = pCell->ele_attrmask & LO_ELE_SELECTED;
|
|
BOOL bSelectedSpecial = pCell->ele_attrmask & LO_ELE_SELECTED_SPECIAL;
|
|
COLORREF rgbBorder;
|
|
HDC hDC = 0;
|
|
|
|
if( bSelected || bSelectedSpecial )
|
|
{
|
|
// Use the selection background color to draw a solid border
|
|
wfe_GetSelectionColors(m_rgbBackgroundColor, NULL, &rgbBorder);
|
|
hDC = GetContextDC();
|
|
RECT r;
|
|
::SetRect(&r, CASTINT(Rect.left), CASTINT(Rect.top), CASTINT(Rect.right), CASTINT(Rect.bottom));
|
|
if( iBorder > 0 )
|
|
{
|
|
// If there is inter-cell spacing,
|
|
// draw selection in that region as much as possible
|
|
if( pCell->inter_cell_space > 0 && iBorder < iMaxWidth )
|
|
{
|
|
iExtraSpace = min(iMaxWidth - iBorder, pCell->inter_cell_space / 2);
|
|
iBorder += iExtraSpace;
|
|
::InflateRect(&r, iExtraSpace, iExtraSpace);
|
|
}
|
|
LTRB borderWidths(iBorder, iBorder, iBorder, iBorder);
|
|
|
|
if( bSelectedSpecial )
|
|
{
|
|
// Show a solid DASHED border as the special selection feedback
|
|
DisplaySpecialBorder(hDC, r, rgbBorder, iBorder, TRUE);
|
|
} else {
|
|
// Show a solid border as the selection feedback
|
|
DisplaySolidBorder(hDC, r, rgbBorder, borderWidths);
|
|
}
|
|
}
|
|
}
|
|
|
|
if( pCell->border_width == 0 || LO_IsEmptyCell(pCell) )
|
|
{
|
|
// Draw zero-border and empty cells with the dotted line
|
|
// (Navigator will not display borders of empty cells)
|
|
// Don't bother testing (EDT_DISPLAY_TABLE_BORDERS)
|
|
// since we don't support turning borders off now
|
|
EditorDisplayZeroWidthBorder(Rect, bSelected | bSelectedSpecial );
|
|
|
|
}
|
|
else if( !bSelected )
|
|
{
|
|
Display3DBox(Rect, ResolveDarkLineColor(), ResolveLightLineColor(), pCell->border_width);
|
|
}
|
|
|
|
// If directly-drawn selection border is narrower than minimum selection width (ED_SELECTION_BORDER)
|
|
// add inverse highlighting whose width is ED_SELECTION_BORDER
|
|
// Thus total selection effect will always be between
|
|
// ED_SELECTION_BORDER and (2*ED_SELECTION_BORDER) in thickness
|
|
if( hDC && (bSelected || bSelectedSpecial) &&
|
|
iBorder < ED_SELECTION_BORDER )
|
|
{
|
|
// TODO: IMAGES THAT FILL CELL WILL OVERWRITE THIS SELECTION - Especially bad when iBorder = 0
|
|
LTRB CellRect = Rect;
|
|
// Draw inside the border rect
|
|
CellRect.Inflate(-1);
|
|
|
|
if( bSelectedSpecial )
|
|
{
|
|
RECT r;
|
|
::SetRect(&r, CASTINT(CellRect.left), CASTINT(CellRect.top),
|
|
CASTINT(CellRect.right), CASTINT(CellRect.bottom));
|
|
|
|
// Show an inverted DASHED border as the special selection feedback
|
|
DisplaySpecialBorder(hDC, r, rgbBorder, ED_SELECTION_BORDER, FALSE);
|
|
} else {
|
|
DisplaySelectionFeedback(LO_ELE_SELECTED, CellRect);
|
|
}
|
|
}
|
|
|
|
if( hDC )
|
|
ReleaseContextDC(hDC);
|
|
}
|
|
else
|
|
#endif // EDITOR
|
|
// Normal border drawing for Navigator
|
|
if( pCell->border_width > 0 ) {
|
|
Display3DBox(Rect, ResolveDarkLineColor(), ResolveLightLineColor(), pCell->border_width);
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID CALLBACK EXPORT LineDDAProcTabFocus(
|
|
int x, // x-coordinate of point being evaluated
|
|
int y, // y-coordinate of point being evaluated
|
|
LPARAM lpData // address of application-defined data
|
|
)
|
|
{
|
|
static BOOL flip = FALSE;
|
|
// HDC hdc = (HDC) lpData;
|
|
flip = ! flip;
|
|
#ifdef _WIN32
|
|
SetPixelV((HDC)lpData, x, y, flip? COLORREF(RGB(0,0,0)) : COLORREF(RGB(255,255,255)) );
|
|
#else
|
|
SetPixel((HDC)lpData, x, y, flip? COLORREF(RGB(0,0,0)) : COLORREF(RGB(255,255,255)) );
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
void CDCCX::DrawTabFocusLine( HDC hdc, BOOL supportPixel, int x, int y, int x2, int y2)
|
|
{
|
|
if( supportPixel ) {
|
|
// support SetPixel()
|
|
LineDDA( x, y, x2, y2, (LINEDDAPROC)LineDDAProcTabFocus, (LPARAM)hdc );
|
|
} else {
|
|
// SetPixel is not supported
|
|
#ifdef _WIN32
|
|
::MoveToEx(hdc, x, y, NULL);
|
|
#else
|
|
::MoveTo(hdc, x, y );
|
|
#endif
|
|
::LineTo(hdc, x2, y2);
|
|
}
|
|
|
|
}
|
|
|
|
// Monochrome brush with every other pixel set
|
|
struct CAlternateBrush {
|
|
HBRUSH hBrush;
|
|
|
|
CAlternateBrush();
|
|
~CAlternateBrush();
|
|
} alternateBrush;
|
|
|
|
CAlternateBrush::CAlternateBrush()
|
|
{
|
|
// Monochrome pattern brush we use for drawing horizontal and vertical alternate
|
|
// lines (lines with every other pixel set)
|
|
static const WORD gray50 [] = {0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55};
|
|
HBITMAP hBitmap = ::CreateBitmap(8, 8, 1, 1, gray50);
|
|
|
|
hBrush = ::CreatePatternBrush(hBitmap);
|
|
::DeleteObject(hBitmap);
|
|
}
|
|
|
|
CAlternateBrush::~CAlternateBrush()
|
|
{
|
|
::DeleteObject(hBrush);
|
|
}
|
|
|
|
void CDCCX::DrawTabFocusRect( HDC hdc, BOOL supportPixel, int left, int top, int right, int bottom)
|
|
{
|
|
RECT rect = {left, top, right, bottom};
|
|
DWORD dwOldTextColor, dwOldBkColor;
|
|
|
|
ASSERT(alternateBrush.hBrush);
|
|
|
|
dwOldTextColor = ::SetTextColor(hdc, RGB(0,0,0));
|
|
dwOldBkColor = ::SetBkColor(hdc, RGB(255,255,255));
|
|
|
|
::FrameRect(hdc, &rect, alternateBrush.hBrush);
|
|
|
|
::SetTextColor(hdc, dwOldTextColor);
|
|
::SetBkColor(hdc, dwOldBkColor);
|
|
}
|
|
|
|
//#ifndef NO_TAB_NAVIGATION
|
|
// see function lo_is_location_in_area() in file ns\lib\layout\laymap.c for area types.
|
|
void CDCCX::DrawMapAreaBorder( int baseX, int baseY, lo_MapAreaRec * theArea )
|
|
{
|
|
int centerX, centerY, radius;
|
|
int left, top, right, bottom;
|
|
int oldDrawingMode;
|
|
int ii;
|
|
HDC hdc = GetContextDC();
|
|
HPEN pTabFocusPen;
|
|
HPEN pOldPen;
|
|
HBRUSH hOldBrush;
|
|
BOOL supportPixel = ::GetDeviceCaps( hdc, RASTERCAPS ) & RC_BITBLT ;
|
|
|
|
if( ! supportPixel || theArea->type == AREA_SHAPE_CIRCLE ) {
|
|
// todo get color for hi-light
|
|
oldDrawingMode = SetROP2( hdc, R2_NOT); // R2_NOT reverse the screen color
|
|
pTabFocusPen = ::CreatePen(PS_DOT, 1, COLORREF( RGB(0,0,0)) );
|
|
pOldPen = (HPEN)::SelectObject(hdc, pTabFocusPen);
|
|
hOldBrush = (HBRUSH) ::SelectObject(hdc, ::GetStockObject(NULL_BRUSH));
|
|
}
|
|
|
|
switch( theArea->type )
|
|
{
|
|
case AREA_SHAPE_RECT:
|
|
if (theArea->coord_cnt >= 4)
|
|
{
|
|
left = (int)(baseX + theArea->coords[0]); // Pix2TwipsY()?
|
|
top = (int)(baseY + theArea->coords[1]);
|
|
right = (int)(baseX + theArea->coords[2]);
|
|
bottom = (int)(baseY + theArea->coords[3]);
|
|
DrawTabFocusRect(hdc, supportPixel, left, top, right, bottom);
|
|
if( supportPixel )
|
|
DrawTabFocusRect(hdc, supportPixel, left+1, top+1, right-1, bottom-1); // double line
|
|
}
|
|
break;
|
|
|
|
case AREA_SHAPE_CIRCLE:
|
|
if ( theArea->coord_cnt >= 3)
|
|
{
|
|
centerX = (int)theArea->coords[0] + baseX;
|
|
centerY = (int)theArea->coords[1] + baseY;
|
|
radius = (int)theArea->coords[2];
|
|
|
|
left = centerX - radius ;
|
|
top = centerY - radius ;
|
|
right = centerX + radius ;
|
|
bottom = centerY + radius ;
|
|
//todo the NULL_BRUSH may cause problems on some platforms(win3.1, win95).
|
|
::Ellipse(hdc, left, top, right, bottom);
|
|
::Ellipse(hdc, left+1, top+1, right-1, bottom-1); // double line
|
|
}
|
|
break;
|
|
|
|
case AREA_SHAPE_POLY:
|
|
if (theArea->coord_cnt >= 6)
|
|
{
|
|
for( ii=0; ii<= theArea->coord_cnt-4; ii+=2) {
|
|
DrawTabFocusLine( hdc, supportPixel,
|
|
(int)theArea->coords[ii] + baseX, (int)theArea->coords[ii+1] + baseY,
|
|
(int)theArea->coords[ii+2] + baseX, (int)theArea->coords[ii+3] + baseY);
|
|
}
|
|
// make it close
|
|
// work around: for 6 edges, theArea->coord_cnt is 13 !!
|
|
// Cannot use theArea->coord_cnt-2 for last x.
|
|
// use ii, which stoped at the last point.
|
|
DrawTabFocusLine( hdc, supportPixel,
|
|
(int)theArea->coords[ii] + baseX, (int)theArea->coords[ii+1] + baseY,
|
|
(int)theArea->coords[0] + baseX, (int)theArea->coords[1] + baseY);
|
|
|
|
}
|
|
break;
|
|
|
|
case AREA_SHAPE_DEFAULT:
|
|
// TODO ??????
|
|
break;
|
|
|
|
case AREA_SHAPE_UNKNOWN:
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if( ! supportPixel || theArea->type == AREA_SHAPE_CIRCLE ) {
|
|
::SelectObject(hdc, hOldBrush);
|
|
::SelectObject(hdc, pOldPen);
|
|
VERIFY(::DeleteObject(pTabFocusPen));
|
|
::SetROP2( hdc, oldDrawingMode );
|
|
}
|
|
|
|
ReleaseContextDC(hdc);
|
|
|
|
}
|
|
//#endif /* NO_TAB_NAVIGATION */
|
|
|
|
|
|
|
|
void CDCCX::DisplaySubtext(MWContext *pContext, int iLocation, LO_TextStruct *pText, int32 lStartPos, int32 lEndPos, XP_Bool iClear)
|
|
{
|
|
// Figure the coordinates of where to draw the text.
|
|
LTRB Rect;
|
|
if(ResolveElement(Rect, pText, iLocation, lStartPos, lEndPos, iClear) == TRUE) {
|
|
SafeSixteen(Rect);
|
|
|
|
HDC hdc = GetContextDC();
|
|
|
|
// cache the attribute pointer
|
|
LO_TextAttr * attr = pText->text_attr;
|
|
|
|
BOOL display_background_color = !attr->no_background;
|
|
|
|
// Determine the color.
|
|
COLORREF rgbColor = ResolveTextColor(attr);
|
|
|
|
// If the color is the same as the background color, then we are selecting.
|
|
// Go into opaque mode.
|
|
COLORREF rgbOldBackgroundColor;
|
|
|
|
// what color does layout think our background color is?
|
|
COLORREF textBackColor = RGB(attr->bg.red, attr->bg.green, attr->bg.blue);
|
|
|
|
//IMPORTANT! Note that we will get called to draw a sub-part of a text line
|
|
// with LO_ELE_SELECTED flag set and the selected start-end is
|
|
// outside of range to be drawn, thus we are really drawing the UNSELECTED
|
|
// portion of the text. So be sure to test that drawing and selectd start positions match
|
|
|
|
// [ = lStartPos
|
|
// ] = lEndPos
|
|
// ( = sel_start
|
|
// ) = sel_end
|
|
// selection calls one of these two:
|
|
// subtext [ ( ) ]
|
|
// subtext [ ] ( )
|
|
// drawtext calls subtext three times: [ ] [( )] [ ]
|
|
|
|
BOOL bSelected = (pText->ele_attrmask & LO_ELE_SELECTED) &&
|
|
(lStartPos >= (int32)pText->sel_start) &&
|
|
((int32)pText->sel_end >= lEndPos) ;
|
|
|
|
#if 0
|
|
XP_TRACE(("DisplaySubtext args: lStartPos(%d) lEndPos(%d)"
|
|
" iClear(%d) element: selected(%d) sel_start(%d) sel_end(%d) bSelected(%d)\n",
|
|
lStartPos, lEndPos,
|
|
iClear,
|
|
(pText->ele_attrmask & LO_ELE_SELECTED),
|
|
(int32)pText->sel_start, (int32)pText->sel_end, bSelected
|
|
));
|
|
#endif
|
|
if (bSelected) {
|
|
// Note that we do NOT have the "real" text color if selected,
|
|
// making it impossible to preview new colors in Character Properties dialog
|
|
wfe_GetSelectionColors(m_rgbBackgroundColor, &rgbColor, &textBackColor);
|
|
display_background_color = TRUE;
|
|
}
|
|
|
|
if(display_background_color)
|
|
{
|
|
rgbOldBackgroundColor = ::SetBkColor(hdc, textBackColor);
|
|
::SetBkMode(hdc, OPAQUE);
|
|
}
|
|
|
|
// Select the font.
|
|
CyaFont *pMyFont;
|
|
SelectNetscapeFontWithCache( hdc, attr, pMyFont);
|
|
|
|
// Set the text color.
|
|
COLORREF rgbOldColor = ::SetTextColor(hdc, rgbColor);
|
|
|
|
// Originally, we drew just the substring of characters
|
|
// that we were asked to. But this did not handle kerning
|
|
// correctly, since kerned characters could intrude into the
|
|
// area of the substring. Worse, when selecting, the reverse-
|
|
// video characters were drawn outside their boundaries, which
|
|
// caused thin vertical strips of selection to remain when the
|
|
// selection was erased.
|
|
//
|
|
// Now we draw the whole string, clipped to the bounds of the
|
|
// substring. -- jhp
|
|
|
|
LTRB fullRect;
|
|
ResolveElement(fullRect, pText->x, pText->y, pText->x_offset,
|
|
pText->y_offset, pText->width, pText->height);
|
|
SafeSixteen(fullRect);
|
|
// Output
|
|
|
|
int iOldDC = ::SaveDC(hdc);
|
|
::IntersectClipRect(hdc, (int)Rect.left, (int)Rect.top, (int)Rect.right, (int)Rect.bottom);
|
|
CIntlWin::TextOutWithCyaFont(
|
|
pMyFont,
|
|
INTL_GetCSIWinCSID(LO_GetDocumentCharacterSetInfo(pContext)),
|
|
hdc,
|
|
CASTINT(fullRect.left),
|
|
CASTINT(fullRect.top),
|
|
(const char *)pText->text,
|
|
CASTINT(pText->text_len));
|
|
|
|
::RestoreDC(hdc, iOldDC);
|
|
|
|
::SetTextColor(hdc, rgbOldColor);
|
|
|
|
|
|
// Handle strike, under_line, Spell and INLINEINPUT manually
|
|
DrawTextPostDecoration(hdc, attr, &Rect, rgbColor );
|
|
|
|
// Normalize our selection if present.
|
|
if (display_background_color) {
|
|
::SetBkColor(hdc, rgbOldBackgroundColor);
|
|
::SetBkMode(hdc, TRANSPARENT);
|
|
}
|
|
|
|
ReleaseNetscapeFontWithCache( hdc, pMyFont );
|
|
|
|
ReleaseContextDC(hdc);
|
|
}
|
|
} // void CDCCX::DisplaySubtext()
|
|
|
|
#define TABLE_HAS_BORDER(pTable) \
|
|
((pTable)->border_top_width > 0 || (pTable)->border_right_width > 0 || \
|
|
(pTable)->border_bottom_width > 0 || (pTable)->border_left_width > 0)
|
|
|
|
void CDCCX::DisplayTable(MWContext *pContext, int iLocation, LO_TableStruct *pTable) {
|
|
LTRB Rect;
|
|
int32 iSelectionBorder = 0;
|
|
BOOL bHaveBorder = TABLE_HAS_BORDER(pTable);
|
|
BOOL bSelected = pTable->ele_attrmask & LO_ELE_SELECTED;
|
|
|
|
if(ResolveElement(Rect, pTable->x, pTable->y, pTable->x_offset,
|
|
pTable->y_offset, pTable->width, pTable->height) == TRUE) {
|
|
SafeSixteen(Rect);
|
|
LTRB TableRect = Rect;
|
|
|
|
#ifdef EDITOR
|
|
if( EDT_IS_EDITOR(pContext) && bSelected )
|
|
{
|
|
// Adjust the top or bottom of the rect if table is selected
|
|
// so the selection encloses area with the caption
|
|
XP_Rect xpRect;
|
|
xpRect.left = Rect.left;
|
|
xpRect.top = Rect.top;
|
|
xpRect.right = Rect.right;
|
|
xpRect.bottom = Rect.bottom;
|
|
if( EDT_AdjustTableRectForCaption(pTable, &xpRect) )
|
|
{
|
|
// Note: we don't change the left and right
|
|
Rect.top = xpRect.top;
|
|
Rect.bottom = xpRect.bottom;
|
|
}
|
|
// We use the larger rect including caption if selected
|
|
TableRect = Rect;
|
|
}
|
|
#endif
|
|
//TRACE0("DisplayTable\n");
|
|
|
|
if( bHaveBorder ) {
|
|
iSelectionBorder = DisplayTableBorder(Rect, pTable);
|
|
}
|
|
#ifdef EDITOR
|
|
else if( EDT_IS_EDITOR(pContext) )
|
|
{
|
|
if( 0 == pTable->inter_cell_space )
|
|
{
|
|
// When no cell spacing, Table border is on top of cell borders,
|
|
// so increase by 1 pixel so we always have a distinquishable table border
|
|
TableRect.Inflate(1);
|
|
iSelectionBorder = 1;
|
|
}
|
|
EditorDisplayZeroWidthBorder(TableRect, bSelected);
|
|
}
|
|
|
|
// Show extra selection if border was not wide enough for clear selection feedback
|
|
if( EDT_IS_EDITOR(pContext) && bSelected && iSelectionBorder < ED_SELECTION_BORDER )
|
|
{
|
|
// If directly-drawn selection border is too narrow (or none),
|
|
// add Inverse-Video highlighting to the maximum thickness allowed
|
|
// Decrease size by amount of solid border used,
|
|
if( iSelectionBorder )
|
|
TableRect.Inflate(-(iSelectionBorder));
|
|
|
|
DisplaySelectionFeedback(LO_ELE_SELECTED, TableRect);
|
|
}
|
|
#endif //EDITOR
|
|
}
|
|
}
|
|
|
|
// handle strike , under_line, Spell and INLINEINPUT after text is drawn.
|
|
void CDCCX::DrawTextPostDecoration( HDC hdc, LO_TextAttr * attr, LTRB *pRect, COLORREF rgbColor )
|
|
{
|
|
#ifdef font_do_it // font handles underline, strikeOut
|
|
// Handle strike manually
|
|
if(attr->attrmask & LO_ATTR_STRIKEOUT) {
|
|
HPEN cpStrike = ::CreatePen(PS_SOLID, CASTINT(pRect->Height() / 10), rgbColor);
|
|
HPEN pOldPen = (HPEN)::SelectObject(hdc, cpStrike);
|
|
::MoveToEx(hdc, CASTINT(pRect->left), CASTINT(pRect->top + pRect->Height() / 2), NULL);
|
|
::LineTo(hdc, CASTINT(pRect->right), CASTINT(pRect->top + pRect->Height() / 2));
|
|
::SelectObject(hdc, pOldPen);
|
|
VERIFY(::DeleteObject(cpStrike));
|
|
}
|
|
|
|
// because netscape font module doesn't support under_list, it is handled manually
|
|
BOOL bUnderline = FALSE;
|
|
if(attr->attrmask & LO_ATTR_ANCHOR) {
|
|
/*
|
|
* if (prefInfo.m_bUnderlineAnchors)
|
|
* bUnderline = TRUE;
|
|
*/
|
|
}
|
|
if(attr->attrmask & LO_ATTR_UNDERLINE) {
|
|
bUnderline = TRUE;
|
|
}
|
|
if( bUnderline ) {
|
|
HPEN cpStrike = ::CreatePen(PS_SOLID, CASTINT(pRect->Height() / 10), rgbColor);
|
|
HPEN pOldPen = (HPEN)::SelectObject(hdc, cpStrike);
|
|
::MoveToEx(hdc, CASTINT(pRect->left), CASTINT(pRect->top + pRect->Height()-1 ), NULL);
|
|
::LineTo(hdc, CASTINT(pRect->right), CASTINT(pRect->top + pRect->Height()-1 ));
|
|
::SelectObject(hdc, pOldPen);
|
|
VERIFY(::DeleteObject(cpStrike));
|
|
}
|
|
#endif // font handles underline, strikeOut
|
|
// Handle Spell and INLINEINPUT manually
|
|
if(attr->attrmask & (LO_ATTR_SPELL | LO_ATTR_INLINEINPUT) ) {
|
|
HPEN cpStrike = ::CreatePen(PS_DOT, CASTINT(pRect->Height() / 10),
|
|
RGB(attr->attrmask & LO_ATTR_SPELL ? 255 : 0,
|
|
0,
|
|
attr->attrmask & LO_ATTR_SPELL ? 255 : 0 ) );
|
|
HPEN pOldPen = (HPEN)::SelectObject(hdc, cpStrike);
|
|
::MoveToEx(hdc, CASTINT(pRect->left), CASTINT(pRect->top + pRect->Height()-1 ), NULL);
|
|
::LineTo(hdc, CASTINT(pRect->right), CASTINT(pRect->top + pRect->Height()-1 ));
|
|
::SelectObject(hdc, pOldPen);
|
|
VERIFY(::DeleteObject(cpStrike));
|
|
}
|
|
|
|
} // DrawTextPostDecoration()
|
|
|
|
//TODO add uint32 drawFalg to the interface, check all caller to pass in the drawFlag,
|
|
// C++ default mechanism doesn't work for calling from C.
|
|
void CDCCX::DisplayText(MWContext *pContext, int iLocation, LO_TextStruct *pText, XP_Bool iClear)
|
|
{
|
|
DisplayText(pContext, iLocation, pText, iClear, 0); // use default if calling grom C.
|
|
}
|
|
|
|
/* cannot use default drawFlag = 0, if this function is called from C */
|
|
// an old interface gateway for caller in C.
|
|
void CDCCX::DisplayText(MWContext *pContext, int iLocation, LO_TextStruct *pText, XP_Bool iClear, uint32 drawFlag )
|
|
{
|
|
// Figure out the coordinates of where to draw the text.
|
|
LTRB Rect;
|
|
if(ResolveElement(Rect, pText->x, pText->y, pText->x_offset,
|
|
pText->y_offset, pText->width, pText->height) == TRUE) {
|
|
SafeSixteen(Rect);
|
|
|
|
// cache the attribute pointer
|
|
LO_TextAttr * attr = pText->text_attr;
|
|
|
|
if (attr) // dmb 11/21/96 - w/o this line, we crash on blinking things like the phonebook.
|
|
{
|
|
BOOL display_background_color = !attr->no_background;
|
|
HDC hdc;
|
|
hdc = GetContextDC();
|
|
|
|
// Determine the color.
|
|
COLORREF rgbColor = ResolveTextColor(attr);
|
|
|
|
// what does layout think the background color is?
|
|
COLORREF textBackColor = RGB(attr->bg.red, attr->bg.green, attr->bg.blue);
|
|
|
|
// If the text is the same color as the background we are selecting text
|
|
// and need to go into OPAQUE mode so the text will show up on the screen
|
|
COLORREF rgbOldBackgroundColor;
|
|
if (pText->ele_attrmask & LO_ELE_SELECTED) {
|
|
display_background_color = TRUE;
|
|
wfe_GetSelectionColors(m_rgbBackgroundColor, &rgbColor, &textBackColor);
|
|
}
|
|
|
|
if(display_background_color)
|
|
{
|
|
rgbOldBackgroundColor = ::SetBkColor(hdc, textBackColor);
|
|
::SetBkMode(hdc, OPAQUE);
|
|
}
|
|
else {
|
|
::SetBkMode(hdc, TRANSPARENT);
|
|
}
|
|
|
|
// Select the font.
|
|
// CNetscapeFont *pFont;
|
|
// HFONT pOldFont = SelectFont(hdc, attr, pFont);
|
|
|
|
// Set the text color.
|
|
COLORREF rgbOldColor = ::SetTextColor(hdc, rgbColor);
|
|
|
|
// #ifndef NO_TAB_NAVIGATION
|
|
// draw a focus box if pText is current TabFocus
|
|
if( drawFlag & FE_DRAW_TAB_FOCUS ) {
|
|
HPEN pTabFocusPen;
|
|
HPEN pOldPen;
|
|
BOOL supportPixel = ::GetDeviceCaps( hdc, RASTERCAPS ) & RC_BITBLT ;
|
|
if( ! supportPixel ) {
|
|
pTabFocusPen = ::CreatePen(PS_DOT, 1, rgbColor);
|
|
pOldPen = (HPEN)::SelectObject(hdc, pTabFocusPen);
|
|
}
|
|
|
|
DrawTabFocusRect(hdc, supportPixel, CASTINT(Rect.left), CASTINT(Rect.top),
|
|
CASTINT(Rect.right), CASTINT(Rect.bottom));
|
|
|
|
if( ! supportPixel ) {
|
|
::SelectObject(hdc, pOldPen);
|
|
VERIFY(::DeleteObject(pTabFocusPen));
|
|
}
|
|
}
|
|
// #endif /* NO_TAB_NAVIGATION */
|
|
|
|
CyaFont *pMyFont;
|
|
SelectNetscapeFontWithCache( hdc, attr, pMyFont);
|
|
|
|
#ifdef DEBUG_aliu
|
|
ASSERT( pMyFont );
|
|
#endif
|
|
|
|
if( pMyFont ) {
|
|
CIntlWin::TextOutWithCyaFont(
|
|
pMyFont,
|
|
INTL_GetCSIWinCSID(LO_GetDocumentCharacterSetInfo(pContext)),
|
|
hdc,
|
|
CASTINT(Rect.left),
|
|
CASTINT(Rect.top),
|
|
(char *)pText->text,
|
|
CASTINT(pText->text_len)
|
|
);
|
|
|
|
}
|
|
::SetTextColor(hdc, rgbOldColor);
|
|
|
|
// Handle strike, under_line, Spell and INLINEINPUT manually
|
|
DrawTextPostDecoration(hdc, attr, &Rect, rgbColor );
|
|
|
|
#if 0
|
|
moved into DrawTextPostDecoration()
|
|
// Handle Spell and INLINEINPUT manually
|
|
if(attr->attrmask & (LO_ATTR_SPELL | LO_ATTR_INLINEINPUT) ) {
|
|
HPEN cpStrike = ::CreatePen(PS_DOT, CASTINT(Rect.Height() / 10),
|
|
RGB(attr->attrmask & LO_ATTR_SPELL ? 255 : 0,
|
|
0,
|
|
attr->attrmask & LO_ATTR_INLINEINPUT ? 255 : 0 ) );
|
|
HPEN pOldPen = (HPEN)::SelectObject(hdc, cpStrike);
|
|
::MoveToEx(hdc, CASTINT(Rect.left), CASTINT(Rect.top + Rect.Height()-1 ), NULL);
|
|
::LineTo(hdc, CASTINT(Rect.right), CASTINT(Rect.top + Rect.Height()-1 ));
|
|
::SelectObject(hdc, pOldPen);
|
|
VERIFY(::DeleteObject(cpStrike));
|
|
}
|
|
#endif
|
|
|
|
// Normalize our selection if present.
|
|
if (display_background_color) {
|
|
::SetBkColor(hdc, rgbOldBackgroundColor);
|
|
::SetBkMode(hdc, TRANSPARENT);
|
|
}
|
|
|
|
// ReleaseFont(hdc, pOldFont);
|
|
ReleaseNetscapeFontWithCache(hdc, pMyFont);
|
|
|
|
ReleaseContextDC(hdc);
|
|
}
|
|
}
|
|
} // void CDCCX::DisplayText()
|
|
|
|
#ifndef MOZ_NGLAYOUT
|
|
|
|
void CDCCX::FreeEmbedElement(MWContext *pContext, LO_EmbedStruct *pEmbed) {
|
|
// We have our OLE document handle this.
|
|
GetDocument()->FreeEmbedElement(pContext, pEmbed);
|
|
}
|
|
|
|
void CDCCX::GetEmbedSize(MWContext *pContext, LO_EmbedStruct *pEmbed, NET_ReloadMethod bReload)
|
|
{
|
|
// We have our OLE document handle this.
|
|
GetDocument()->GetEmbedSize(pContext, pEmbed, bReload);
|
|
}
|
|
#endif /* MOZ_NGLAYOUT */
|
|
|
|
#ifdef LAYERS
|
|
void CDCCX::GetTextFrame(MWContext *pContext, LO_TextStruct *pText,
|
|
int32 lStartPos, int32 lEndPos, XP_Rect *frame)
|
|
{
|
|
frame->left = pText->x + pText->x_offset;
|
|
frame->top = pText->y + pText->y_offset;
|
|
|
|
HDC pDC = GetContextDC();
|
|
|
|
CyaFont *pMyFont;
|
|
SelectNetscapeFontWithCache( pDC, pText->text_attr, pMyFont );
|
|
CSize sz;
|
|
ResolveTextExtent(pDC, (const char *)pText->text, CASTINT(lStartPos), &sz, pMyFont);
|
|
frame->left += sz.cx;
|
|
ResolveTextExtent(pDC, (const char *)pText->text + lStartPos, CASTINT(lEndPos - lStartPos + 1), &sz, pMyFont);
|
|
frame->right = frame->left + sz.cx;
|
|
|
|
frame->bottom = frame->top + sz.cy;
|
|
|
|
ReleaseNetscapeFontWithCache( pDC, pMyFont );
|
|
|
|
ReleaseContextDC(pDC);
|
|
}
|
|
#endif /* LAYERS */
|
|
|
|
int CDCCX::GetTextInfo(MWContext *pContext, LO_TextStruct *pText, LO_TextInfo *pTextInfo) {
|
|
#ifdef MOZ_NGLAYOUT
|
|
XP_ASSERT(0);
|
|
return FALSE;
|
|
#else
|
|
HDC hdc = GetAttribDC();
|
|
|
|
// Determine and select the font.
|
|
CyaFont *pMyFont;
|
|
SelectNetscapeFontWithCache( hdc, pText->text_attr, pMyFont );
|
|
|
|
// Get the information regarding the size of the font for layout.
|
|
SIZE sExtent;
|
|
ResolveTextExtent(
|
|
INTL_GetCSIWinCSID(LO_GetDocumentCharacterSetInfo(pContext))
|
|
, hdc, (const char *)pText->text, pText->text_len, &sExtent, pMyFont);
|
|
|
|
pTextInfo->max_width = sExtent.cx;
|
|
|
|
pTextInfo->ascent = pMyFont->GetAscent();
|
|
pTextInfo->descent = pMyFont->GetDescent();
|
|
pTextInfo->lbearing = pTextInfo->rbearing = 0;
|
|
|
|
ReleaseNetscapeFontWithCache( hdc, pMyFont );
|
|
ReleaseContextDC(hdc);
|
|
return(TRUE);
|
|
#endif /* MOZ_NGLAYOUT */
|
|
}
|
|
|
|
BOOL CDCCX::ResolveTextExtent(int16 wincsid, HDC pDC, LPCTSTR pString, int iLength, LPSIZE pSize, CyaFont *pMyFont)
|
|
{
|
|
// Always measure it because the bytes * mean width algorithm
|
|
// won't work for many code point. Expecially UTF8 which 3 byte
|
|
// could be one character which takes 1 or 2 columns.
|
|
return CIntlWin::GetTextExtentPointWithCyaFont(pMyFont, wincsid, pDC, pString, iLength, pSize);
|
|
#if 0
|
|
BOOL bRetval;
|
|
|
|
// if(pMyFont->GetMeanWidth() == 0 ) {
|
|
if( ! pMyFont->IsFixedFont() ) {
|
|
bRetval = CIntlWin::GetTextExtentPointWithCyaFont(pMyFont, wincsid, pDC, pString, iLength, pSize);
|
|
return(bRetval);
|
|
}
|
|
else {
|
|
// fixed size.
|
|
pSize->cx = (int) ((long)pMyFont->GetMeanWidth() * (long)iLength);
|
|
pSize->cy = pMyFont->GetHeight();
|
|
bRetval = TRUE;
|
|
}
|
|
return(bRetval);
|
|
#endif
|
|
}
|
|
|
|
#ifdef TRANSPARENT_APPLET
|
|
//
|
|
// This function is called only when applet are windowless and force a
|
|
// paint on the java side
|
|
//
|
|
void CDCCX::DrawJavaApp(MWContext *pContext, int iLocation, LO_JavaAppStruct *pJava)
|
|
{
|
|
#if defined(OJI) || defined(JAVA)
|
|
|
|
RECT rect;
|
|
HDC hDC = GetContextDC();
|
|
NPEvent event;
|
|
FE_Region clip;
|
|
|
|
#ifdef LAYERS
|
|
clip = GetDrawingClip();
|
|
if (clip)
|
|
{
|
|
XP_Rect xprect;
|
|
|
|
FE_GetRegionBoundingBox(clip, &xprect);
|
|
rect.left = CASTINT(xprect.left);
|
|
rect.top = CASTINT(xprect.top);
|
|
rect.right = CASTINT(xprect.right);
|
|
rect.bottom = CASTINT(xprect.bottom);
|
|
}
|
|
#endif /* LAYERS */
|
|
|
|
event.event = WM_PAINT;
|
|
event.wParam = (uint32)hDC;
|
|
event.lParam = (uint32)▭
|
|
|
|
#if defined(OJI)
|
|
// XXX help
|
|
#elif defined(JAVA)
|
|
LJ_HandleEvent(pContext, pJava, (void *)&event);
|
|
#endif
|
|
|
|
ReleaseContextDC(hDC);
|
|
#endif
|
|
}
|
|
|
|
#endif
|