mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2257 lines
55 KiB
2257 lines
55 KiB
/*
|
|
Enhanced NCSA Mosaic from Spyglass
|
|
"Guitar"
|
|
|
|
Copyright 1994 Spyglass, Inc.
|
|
All Rights Reserved
|
|
|
|
Author(s):
|
|
Albert Lee [email protected]
|
|
*/
|
|
|
|
|
|
#include "all.h"
|
|
#include "blob.h"
|
|
|
|
#ifdef FEATURE_IMAGE_VIEWER
|
|
#include "winview.h"
|
|
|
|
#ifdef FEATURE_IMG_INLINE
|
|
|
|
#include <string.h>
|
|
|
|
#include "htmlutil.h"
|
|
#include "safestrm.h"
|
|
#include "decoder.h"
|
|
#include "mci.h"
|
|
#include "blob.h"
|
|
#include "wc_html.h"
|
|
|
|
#ifdef FEATURE_VRML
|
|
#include "vrml.h"
|
|
#endif
|
|
|
|
|
|
#define PUTC(c) (*target->isa->put_character)(target, c)
|
|
#define PUTS(s) (*target->isa->put_string)(target, s)
|
|
#define START(e) (*target->isa->start_element)(target, e, 0, 0)
|
|
#define END(e) (*target->isa->end_element)(target, e)
|
|
#define FREE_TARGET (*target->isa->free)(target)
|
|
struct _HTStructured
|
|
{
|
|
CONST HTStructuredClass *isa;
|
|
/* ... */
|
|
};
|
|
#endif
|
|
|
|
#ifndef FEATURE_IMG_INLINE
|
|
|
|
DCL_WinProc(Viewer_DlgProc);
|
|
|
|
static BOOL bInitialized = FALSE;
|
|
static struct hash_table gViewerCache;
|
|
static TCHAR Viewer_achClassName[MAX_WC_CLASSNAME];
|
|
|
|
static void SetClientWidth(HWND hwnd, int width)
|
|
{
|
|
RECT rect, clientrect;
|
|
|
|
GetWindowRect(hwnd, &rect);
|
|
GetClientRect(hwnd, &clientrect);
|
|
|
|
SetWindowPos(hwnd, NULL, 0, 0,
|
|
width + (rect.right - rect.left) - clientrect.right,
|
|
rect.bottom - rect.top,
|
|
SWP_NOMOVE | SWP_NOZORDER);
|
|
}
|
|
|
|
static void SetClientHeight(HWND hwnd, int height)
|
|
{
|
|
RECT rect, clientrect;
|
|
|
|
GetWindowRect(hwnd, &rect);
|
|
GetClientRect(hwnd, &clientrect);
|
|
|
|
SetWindowPos(hwnd, NULL, 0, 0,
|
|
rect.right - rect.left,
|
|
height + (rect.bottom - rect.top) - clientrect.bottom,
|
|
SWP_NOMOVE | SWP_NOZORDER);
|
|
}
|
|
|
|
static void CreateWindowsBitmap(HWND hwnd, struct ViewerInfo *pViewerInfo)
|
|
{
|
|
HDC hDC;
|
|
HPALETTE hOld;
|
|
|
|
hDC = GetDC(hwnd);
|
|
|
|
switch(pViewerInfo->pbmi->bmiHeader.biBitCount)
|
|
{
|
|
case 8:
|
|
if (wg.eColorMode == 8)
|
|
{
|
|
hOld = SelectPalette(hDC, hPalGuitar, FALSE);
|
|
RealizePalette(hDC);
|
|
}
|
|
|
|
pViewerInfo->hBitmap = CreateDIBitmap(hDC, (const BITMAPINFOHEADER *) pViewerInfo->pbmi,
|
|
CBM_INIT, pViewerInfo->gw, pViewerInfo->pbmi, DIB_PAL_COLORS);
|
|
|
|
if (wg.eColorMode == 8)
|
|
SelectPalette(hDC, hOld, FALSE);
|
|
break;
|
|
|
|
default:
|
|
pViewerInfo->hBitmap = CreateDIBitmap(hDC, (const BITMAPINFOHEADER *) pViewerInfo->pbmi,
|
|
CBM_INIT, pViewerInfo->gw, pViewerInfo->pbmi, DIB_RGB_COLORS);
|
|
break;
|
|
}
|
|
|
|
ReleaseDC(hwnd, hDC);
|
|
}
|
|
|
|
static void Viewer_DoImageFile(struct ViewerInfo *pvi, const char *pszURL)
|
|
{
|
|
int ndx, newleft, newtop, bottom, right;
|
|
void *pImage;
|
|
FILE *fp;
|
|
long imagesize, imagewidth, imageheight, transparent;
|
|
long clientwidth, clientheight;
|
|
unsigned char *pDIB;
|
|
LOGPALETTE *lp;
|
|
HPALETTE hPalette = NULL;
|
|
PBITMAPINFO pbmi = NULL;
|
|
RECT rect;
|
|
int scrollwidth, scrollheight, captionheight;
|
|
int borderheight, borderwidth, screenwidth, screenheight;
|
|
HWND hDlg;
|
|
struct Mwin *tw;
|
|
BOOL bMoveWindow;
|
|
|
|
ndx = Hash_FindOrAdd(&gViewerCache, (char *) pszURL, NULL, pvi);
|
|
|
|
// read the image file into memory
|
|
|
|
fp = fopen(pvi->fsOrig, "rb");
|
|
if (!fp)
|
|
return;
|
|
|
|
fseek(fp, 0, SEEK_END);
|
|
imagesize = ftell(fp);
|
|
|
|
pImage = GTR_MALLOC(imagesize);
|
|
|
|
fseek(fp, 0, SEEK_SET);
|
|
fread(pImage, 1, imagesize, fp);
|
|
fclose(fp);
|
|
|
|
// Create the bitmap
|
|
|
|
switch(pvi->format)
|
|
{
|
|
case VIEWER_GIF:
|
|
lp = GTR_MALLOC(sizeof(LOGPALETTE) + sizeof(PALETTEENTRY) * 256);
|
|
lp->palVersion = 0x300;
|
|
lp->palNumEntries = 256;
|
|
#ifdef FEATURE_IMG_THREADS
|
|
pDIB = ReadGIFData(pImage, &imagewidth, &imageheight, lp->palPalEntry, &transparent);
|
|
#else
|
|
pDIB = ReadGIF(pImage, &imagewidth, &imageheight, lp->palPalEntry, &transparent);
|
|
#endif
|
|
if ( pDIB )
|
|
{
|
|
pbmi = (BITMAPINFO *) pDIB;
|
|
|
|
hPalette = CreatePalette(lp);
|
|
|
|
GTR_FREE(lp);
|
|
|
|
// Dither if necessary
|
|
|
|
switch(wg.eColorMode)
|
|
{
|
|
case 8:
|
|
pbmi = BIT_Make_DIB_PAL_Header(imagewidth, imageheight, pDIB, hPalette, transparent);
|
|
break;
|
|
|
|
default:
|
|
pbmi = BIT_Make_DIB_RGB_Header_Screen(imagewidth, imageheight, pDIB, hPalette, transparent, 0);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case VIEWER_JFIF:
|
|
|
|
switch(wg.eColorMode)
|
|
{
|
|
case 4:
|
|
#ifdef FEATURE_IMG_THREADS
|
|
pDIB = ReadJPEG_Dithered_VGA(NULL, pImage, imagesize, &imagewidth, &imageheight);
|
|
#else
|
|
pDIB = ReadJPEG_Dithered_VGA(pImage, imagesize, &imagewidth, &imageheight);
|
|
#endif
|
|
pbmi = BIT_Make_DIB_RGB_Header_VGA(imagewidth, imageheight, pDIB);
|
|
break;
|
|
|
|
case 8:
|
|
#ifdef FEATURE_IMG_THREADS
|
|
pDIB = ReadJPEG_Dithered(NULL, pImage, imagesize, &imagewidth, &imageheight);
|
|
#else
|
|
pDIB = ReadJPEG_Dithered(pImage, imagesize, &imagewidth, &imageheight);
|
|
#endif
|
|
pbmi = BIT_Make_DIB_PAL_Header_Prematched(imagewidth, imageheight, pDIB);
|
|
break;
|
|
|
|
default:
|
|
#ifdef FEATURE_IMG_THREADS
|
|
pDIB = ReadJPEG_RGB(NULL, pImage, imagesize, &imagewidth, &imageheight);
|
|
#else
|
|
pDIB = ReadJPEG_RGB(pImage, imagesize, &imagewidth, &imageheight);
|
|
#endif
|
|
pbmi = BIT_Make_DIB_RGB_Header_24BIT(imagewidth, imageheight, pDIB);
|
|
break;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
GTR_FREE(pImage);
|
|
if (hPalette)
|
|
DeleteObject(hPalette);
|
|
|
|
if (!pbmi)
|
|
{
|
|
ERR_ReportError(pvi->original_tw, errInvalidImageFile, "", "");
|
|
return;
|
|
}
|
|
|
|
// Create the window
|
|
|
|
pvi->gw = pDIB;
|
|
pvi->nWidth = (short) imagewidth;
|
|
pvi->nHeight = (short) imageheight;
|
|
pvi->bInitialized = FALSE;
|
|
pvi->horz = 0;
|
|
pvi->vert = 0;
|
|
pvi->pbmi = pbmi;
|
|
GTR_strncpy(pvi->szURL, pszURL, MAX_URL_STRING);
|
|
|
|
/* Do NOT change the initial creation size here. We create an
|
|
arbitrarily large window so that Windows can reduce the window
|
|
size if necessary. Growing the window to fit an image is
|
|
very buggy (reducing the window is not) */
|
|
|
|
hDlg = CreateWindow(Viewer_achClassName, "",
|
|
WS_OVERLAPPEDWINDOW | WS_HSCROLL | WS_VSCROLL,
|
|
CW_USEDEFAULT, CW_USEDEFAULT, 1500, 1500, wg.hWndHidden, NULL,
|
|
wg.hInstance, NULL);
|
|
|
|
if (!hDlg)
|
|
return;
|
|
|
|
pvi->hwnd = hDlg;
|
|
SetWindowLong(hDlg, 0, (LONG) pvi);
|
|
|
|
pvi->tw->hWndFrame = hDlg;
|
|
|
|
CreateWindowsBitmap(hDlg, pvi);
|
|
|
|
SetWindowText(hDlg, (char *) MB_GetWindowNameFromURL((unsigned char *) pszURL));
|
|
|
|
// Set up some variables
|
|
|
|
// Always keep around the scrollbars (it's MUCH easier that way) since it is
|
|
// consistent with the Mac image viewer implementation.
|
|
// Remember that scrollbars are always present.
|
|
|
|
scrollwidth = GetSystemMetrics(SM_CXVSCROLL);
|
|
scrollheight = GetSystemMetrics(SM_CYHSCROLL);
|
|
borderheight = GetSystemMetrics(SM_CYFRAME);
|
|
borderwidth = GetSystemMetrics(SM_CXFRAME);
|
|
captionheight = GetSystemMetrics(SM_CYCAPTION) - GetSystemMetrics(SM_CYBORDER);
|
|
screenwidth = GetSystemMetrics(SM_CXFULLSCREEN);
|
|
screenheight = GetSystemMetrics(SM_CYFULLSCREEN);
|
|
|
|
XX_DMsg(DBG_MM, ("Viewer: image width = %d\n", imagewidth));
|
|
XX_DMsg(DBG_MM, ("Viewer: image height = %d\n", imageheight));
|
|
XX_DMsg(DBG_MM, ("Viewer: client width = %d\n", clientwidth));
|
|
XX_DMsg(DBG_MM, ("Viewer: client height = %d\n", clientheight));
|
|
XX_DMsg(DBG_MM, ("Viewer: scroll width = %d\n", scrollwidth));
|
|
XX_DMsg(DBG_MM, ("Viewer: scroll height = %d\n", scrollheight));
|
|
|
|
// Move the window to be cascaded from the most recently active window
|
|
|
|
tw = TW_FindTopmostWindow();
|
|
if (tw)
|
|
{
|
|
GetWindowRect(tw->hWndFrame, &rect);
|
|
newleft = rect.left + GetSystemMetrics(SM_CXSIZE) + borderwidth;
|
|
newtop = rect.top + GetSystemMetrics(SM_CYSIZE) + borderheight;
|
|
|
|
SetWindowPos(hDlg, NULL, newleft, newtop, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
|
|
}
|
|
|
|
// Resize the window to fit the image
|
|
|
|
pvi->bInitialized = TRUE;
|
|
|
|
GetClientRect(hDlg, &rect);
|
|
|
|
// Reduce the rectangle size by the scrollbar size
|
|
|
|
MapWindowPoints(hDlg, NULL, (LPPOINT) &rect, 2);
|
|
newleft = rect.left;
|
|
newtop = rect.top;
|
|
|
|
right = rect.left + imagewidth + scrollwidth + 2 * borderwidth - 1;
|
|
bottom = rect.top + imageheight + scrollheight + 2 * borderheight + captionheight - 2;
|
|
bMoveWindow = FALSE;
|
|
|
|
if (right > screenwidth)
|
|
{
|
|
newleft = max(0, newleft - (right - screenwidth));
|
|
bMoveWindow = TRUE;
|
|
}
|
|
|
|
if (bottom > screenheight)
|
|
{
|
|
newtop = max(0, newtop - (bottom - screenheight));
|
|
bMoveWindow = TRUE;
|
|
}
|
|
|
|
if (bMoveWindow)
|
|
SetWindowPos(hDlg, NULL, newleft, newtop, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
|
|
|
|
if (newleft > 0)
|
|
{
|
|
EnableScrollBar(hDlg, SB_HORZ, ESB_DISABLE_BOTH);
|
|
SetClientWidth(hDlg, imagewidth);
|
|
}
|
|
else
|
|
SetClientWidth(hDlg, screenwidth - 2 * borderwidth);
|
|
|
|
UpdateWindow(hDlg);
|
|
if (newtop > 0)
|
|
{
|
|
EnableScrollBar(hDlg, SB_VERT, ESB_DISABLE_BOTH);
|
|
SetClientHeight(hDlg, imageheight);
|
|
}
|
|
else
|
|
SetClientHeight(hDlg, screenheight - 2 * borderheight - captionheight + 2);
|
|
|
|
ShowWindow(hDlg, SW_SHOW);
|
|
}
|
|
|
|
BOOL Viewer_ShowCachedFile(const char *pszURL)
|
|
{
|
|
char *pURL;
|
|
struct ViewerInfo *pViewerInfo;
|
|
|
|
if (!bInitialized)
|
|
return FALSE;
|
|
|
|
// Check if a window with the given URL exists
|
|
|
|
if (Hash_Find(&gViewerCache, (char *) pszURL, &pURL, &pViewerInfo) != -1)
|
|
{
|
|
if (IsWindow(pViewerInfo->hwnd))
|
|
{
|
|
/* If the window exists then check its enabled status. If it is
|
|
not enabled, it means that the error dialog is up. In this
|
|
case, let the error dialog become active. */
|
|
|
|
if (IsWindowEnabled(pViewerInfo->hwnd))
|
|
TW_RestoreWindow(pViewerInfo->hwnd);
|
|
else
|
|
TW_EnableModalChild(pViewerInfo->hwnd);
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static void Viewer_Callback(void *param,
|
|
const char *szURL,
|
|
DCACHETIME dctExpires,
|
|
DCACHETIME dctLastModif,
|
|
BOOL bAbort)
|
|
{
|
|
struct ViewerInfo *pvi;
|
|
|
|
pvi = (struct ViewerInfo *)param;
|
|
if (bAbort)
|
|
{
|
|
GTR_FREE(pvi->fsOrig);
|
|
GTR_FREE(pvi->tw);
|
|
GTR_FREE(pvi);
|
|
return;
|
|
}
|
|
GHist_Add((char *) szURL, NULL, time(NULL), TRUE);
|
|
|
|
switch (pvi->format)
|
|
{
|
|
case VIEWER_GIF:
|
|
case VIEWER_JFIF:
|
|
pvi->fDCached = ( gPrefs.bEnableDiskCache
|
|
&& FUpdateBuiltinDCache(
|
|
pvi_.format == VIEWER_GIF ? WWW_GIF : WWW_JPEG,
|
|
szURL,
|
|
&pvi->fsOrig,
|
|
dctExpires,
|
|
dctLastModif, TRUE, pvi->tw);
|
|
Viewer_DoImageFile(pvi, szURL);
|
|
ResetCIFEntryCurDoc(szURL);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void Viewer_RegisterClass(void)
|
|
{
|
|
WNDCLASS wc;
|
|
ATOM a;
|
|
|
|
sprintf(Viewer_achClassName, "%s_Viewer", vv_Application);
|
|
|
|
wc.style = CS_HREDRAW | CS_VREDRAW;
|
|
wc.lpfnWndProc = Viewer_DlgProc;
|
|
wc.cbClsExtra = 0;
|
|
wc.cbWndExtra = sizeof(LPVOID);
|
|
wc.hInstance = wg.hInstance;
|
|
wc.hIcon = LoadIcon(wg.hInstance, MAKEINTRESOURCE(RES_ICO_FRAME));
|
|
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
wc.hbrBackground = (HBRUSH) (COLOR_APPWORKSPACE + 1);
|
|
wc.lpszMenuName = MAKEINTRESOURCE(RES_MENU_IMAGE_VIEWER);
|
|
wc.lpszClassName = Viewer_achClassName;
|
|
|
|
a = RegisterClass(&wc);
|
|
}
|
|
#endif /* FEATURE_IMG_INLINE */
|
|
|
|
#ifdef FEATURE_IMG_INLINE
|
|
|
|
struct _HTStream
|
|
{
|
|
CONST HTStreamClass *isa;
|
|
HTRequest *request;
|
|
int count;
|
|
int expected_length;
|
|
struct Mwin *tw;
|
|
FILE * fpDc;
|
|
char * pszDcFile;
|
|
HTFormat format_inDc;
|
|
BOOL fDCache;
|
|
};
|
|
|
|
|
|
PRIVATE int HTNULL_init(struct Mwin *tw, int nState, void **ppInfo);
|
|
PRIVATE void HTNULL_write_dcache(HTStream * me, CONST char *s, int cb);
|
|
|
|
|
|
PRIVATE BOOL HTNULL_put_character(HTStream * me, char c)
|
|
{
|
|
if (me->expected_length)
|
|
WAIT_SetTherm(me->tw, me->count);
|
|
return TRUE;
|
|
}
|
|
|
|
PRIVATE BOOL HTNULL_put_string(HTStream * me, CONST char *s)
|
|
{
|
|
/* Should never get called */
|
|
return FALSE;
|
|
}
|
|
|
|
PRIVATE BOOL HTNULL_write(HTStream * me, CONST char *s, int l, BOOL fDCache)
|
|
{
|
|
if (fDCache && me->isa->write_dcache)
|
|
(me->isa->write_dcache)(me, s, l);
|
|
|
|
me->count += l;
|
|
if (me->expected_length)
|
|
WAIT_SetTherm(me->tw, me->count);
|
|
return TRUE;
|
|
}
|
|
|
|
PRIVATE void HTNULL_free(HTStream * me, DCACHETIME dctExpires, DCACHETIME dctLastModif)
|
|
{
|
|
if (me->fDCache)
|
|
UpdateStreamDCache(me, dctExpires, dctLastModif, /*fAbort=*/FALSE, me->tw);
|
|
GTR_FREE(me);
|
|
}
|
|
|
|
PRIVATE void HTNULL_abort(HTStream * me, HTError e)
|
|
{
|
|
DCACHETIME dct={0,0};
|
|
|
|
if (me->fDCache)
|
|
UpdateStreamDCache(me, dct, dct, /*fAbort=*/TRUE, me->tw);
|
|
GTR_FREE(me);
|
|
}
|
|
|
|
|
|
/* devnull stream
|
|
** ----------
|
|
*/
|
|
PRIVATE HTStreamClass HTNULLClass =
|
|
{
|
|
"NULL",
|
|
NULL,
|
|
NULL,
|
|
HTNULL_init,
|
|
HTNULL_free,
|
|
HTNULL_abort,
|
|
HTNULL_put_character, HTNULL_put_string,
|
|
HTNULL_write,
|
|
NULL,
|
|
HTNULL_write_dcache
|
|
};
|
|
|
|
|
|
/* Image creation
|
|
*/
|
|
PRIVATE HTStream *Image_NULL(struct Mwin *tw, HTRequest * request, void *param, HTFormat input_format, HTFormat output_format, HTStream * output_stream)
|
|
{
|
|
HTStream *me = (HTStream *) GTR_MALLOC(sizeof(*me));
|
|
|
|
HTLoadStatusStrings(&HTNULLClass,RES_STRING_HTGIF_NO,RES_STRING_HTGIF_YES);
|
|
if (!me)
|
|
return NULL;
|
|
|
|
me->isa = &HTNULLClass;
|
|
me->request = request;
|
|
me->expected_length = request->content_length;
|
|
if (me->expected_length)
|
|
{
|
|
WAIT_SetRange(tw, 0, 100, me->expected_length);
|
|
}
|
|
me->count = 0;
|
|
me->tw = tw;
|
|
return me;
|
|
}
|
|
|
|
PRIVATE int HTNULL_init(struct Mwin *tw, int nState, void **ppInfo)
|
|
{
|
|
struct Params_InitStream *pParams;
|
|
|
|
pParams = (struct Params_InitStream *) *ppInfo;
|
|
|
|
switch (nState)
|
|
{
|
|
case STATE_INIT:
|
|
pParams->me->fDCache = pParams->fDCache;
|
|
if (pParams->fDCache)
|
|
{
|
|
AssertDiskCacheEnabled();
|
|
#ifdef FEATURE_INTL
|
|
SetFileDCache(tw->w3doc, pParams->request->destination->szActualURL,
|
|
pParams->request->content_encoding,
|
|
&pParams->me->fpDc,
|
|
&pParams->me->pszDcFile,
|
|
pParams->atomMIMEType);
|
|
#else
|
|
SetFileDCache( pParams->request->destination->szActualURL,
|
|
pParams->request->content_encoding,
|
|
&pParams->me->fpDc,
|
|
&pParams->me->pszDcFile,
|
|
pParams->atomMIMEType);
|
|
#endif
|
|
pParams->me->format_inDc = pParams->atomMIMEType;
|
|
}
|
|
else
|
|
{
|
|
pParams->me->fpDc = NULL;
|
|
pParams->me->pszDcFile = NULL;
|
|
pParams->me->format_inDc = 0;
|
|
}
|
|
|
|
*pParams->pResult = 1;
|
|
return STATE_DONE;
|
|
|
|
case STATE_ABORT:
|
|
if (pParams->fDCache)
|
|
{
|
|
AssertDiskCacheEnabled();
|
|
AbortFileDCache(&pParams->me->fpDc, &pParams->me->pszDcFile);
|
|
pParams->me->fDCache = FALSE; // So HTXBM_free knows.
|
|
}
|
|
*pParams->pResult = -1;
|
|
return STATE_DONE;
|
|
}
|
|
}
|
|
|
|
PRIVATE void HTNULL_write_dcache(HTStream * me, CONST char *s, int cb)
|
|
{
|
|
AssertDiskCacheEnabled();
|
|
if (me->fpDc)
|
|
CbWriteDCache(s, 1, cb, &me->fpDc, &me->pszDcFile, NULL, 0, me->tw);
|
|
// CbWriteDCache(s, 1, cb, &me->fpDc, &me->pszDcFile, me->request->destination->szActualURL, 0);
|
|
}
|
|
|
|
|
|
/* Paste in an IMAGE
|
|
** ------------------
|
|
**
|
|
** On entry,
|
|
** HT is in append mode.
|
|
** text points to the text to be put into the file, 0 terminated.
|
|
** addr points to the hypertext refernce address 0 terminated.
|
|
*/
|
|
static void write_image(HTStructured *target, CONST char *addr)
|
|
{
|
|
|
|
BOOL present[HTML_IMG_ATTRIBUTES];
|
|
CONST char *value[HTML_IMG_ATTRIBUTES];
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < HTML_IMG_ATTRIBUTES; i++)
|
|
present[i] = 0;
|
|
present[HTML_IMG_SRC] = YES;
|
|
value[HTML_IMG_SRC] = addr;
|
|
|
|
(*target->isa->start_element) (target, HTML_IMG, present, value);
|
|
|
|
END(HTML_IMG);
|
|
}
|
|
|
|
static struct ImageInfo *pGetImage(struct _www *w3doc)
|
|
{
|
|
struct ImageInfo *pImg = NULL;
|
|
struct _element *aElements = w3doc->aElements;
|
|
int i;
|
|
|
|
if (aElements != NULL)
|
|
{
|
|
for (i = 0 ; i >= 0; i = aElements[i].next)
|
|
if (aElements[i].type == ELE_IMAGE)
|
|
{
|
|
pImg = aElements[i].myImage;
|
|
break;
|
|
}
|
|
}
|
|
return pImg;
|
|
}
|
|
|
|
// pGetPel - grabs the first VRML Pel from w3doc
|
|
// in: w3doc - pointer to w3doc
|
|
// out: piElement - pointer to element index of pel that blob is from
|
|
// (returns): pointer to blob or NULL if it did not find it
|
|
//
|
|
static struct _element *pGetPel(struct _www *w3doc, int *piElement)
|
|
{
|
|
struct _element *aElements = w3doc->aElements;
|
|
int i;
|
|
|
|
ASSERT(piElement);
|
|
|
|
*piElement = -1;
|
|
if (aElements != NULL)
|
|
{
|
|
for (i = 0 ; i >= 0; i = aElements[i].next)
|
|
if (aElements[i].type == ELE_IMAGE && aElements[i].pblob)
|
|
{
|
|
*piElement = i;
|
|
return (&aElements[i]);
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifdef FEATURE_VRML
|
|
|
|
/* Paste in an IMAGE tag containing a VRML attribute
|
|
** ------------------
|
|
**
|
|
** On entry,
|
|
** HT is in append mode.
|
|
** text points to the text to be put into the file, 0 terminated.
|
|
** addr points to the hypertext refernce address 0 terminated.
|
|
*/
|
|
static void write_vrml_image(HTStructured *target, CONST char *addr)
|
|
{
|
|
BOOL present[HTML_IMG_ATTRIBUTES];
|
|
CONST char *value[HTML_IMG_ATTRIBUTES];
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < HTML_IMG_ATTRIBUTES; i++)
|
|
present[i] = 0;
|
|
|
|
present[HTML_IMG_SRC] = NO;
|
|
value[HTML_IMG_SRC] = 0;
|
|
|
|
present[HTML_IMG_VRML] = YES;
|
|
value[HTML_IMG_VRML] = addr;
|
|
|
|
present[HTML_IMG_WIDTH] = YES;
|
|
value[HTML_IMG_WIDTH] = "100%";
|
|
|
|
present[HTML_IMG_HEIGHT] = YES;
|
|
value[HTML_IMG_HEIGHT] = "100%";
|
|
|
|
(*target->isa->start_element) (target, HTML_IMG, present, value);
|
|
|
|
END(HTML_IMG);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
HTStream *VRML_Present(struct Mwin *tw, HTRequest *request, void *param, HTFormat input_format, HTFormat output_format, HTStream *output_stream)
|
|
{
|
|
HTStructured *target;
|
|
struct _www *prevdoc;
|
|
struct _element *pel;
|
|
PBLOBstuff pblob;
|
|
|
|
|
|
if (input_format != HTAtom_for("x-world/x-vrml"))
|
|
return NULL;
|
|
|
|
prevdoc = tw->w3doc;
|
|
target = HTML_new(tw, request, NULL, WWW_HTML, output_format, output_stream);
|
|
if (target == NULL) return NULL;
|
|
|
|
write_vrml_image(target,request->destination->szRequestedURL);
|
|
tw->w3doc->flags |= W3DOC_FLAG_OVERRIDE_TOP_MARGIN | W3DOC_FLAG_OVERRIDE_LEFT_MARGIN |
|
|
W3DOC_FLAG_FULL_PANE_VRML;
|
|
tw->w3doc->top_margin = 0;
|
|
tw->w3doc->left_margin = 0;
|
|
|
|
(*target->isa->free)(target);
|
|
|
|
{
|
|
BGBLOBPARAMS *pBGBlobParams;
|
|
int iElement;
|
|
|
|
// make sure we have a W3DOC to work with, and its not our previous w3doc
|
|
if (tw->w3doc == NULL || tw->w3doc == prevdoc )
|
|
return NULL;
|
|
|
|
// now get the blob stucture along with the associated element index for the pel
|
|
pel = pGetPel(tw->w3doc, &iElement);
|
|
|
|
if (pel == NULL )
|
|
return NULL; // not around..
|
|
|
|
pblob = pel->pblob;
|
|
|
|
// Flag this element as special loading for first time only
|
|
if ( iElement >= 0 )
|
|
tw->w3doc->aElements[iElement].lFlags |= ELEFLAG_FULL_PANE_VRML_FIRST_LOAD;
|
|
|
|
Image_UnblockMaster(tw);
|
|
|
|
if (PROT_FILE == ProtocolIdentify(pblob->szURL) )
|
|
{
|
|
pblob->dwFlags |= BLOB_FLAGS_LOADED;
|
|
ASSERT(pblob->szURL[0] == 'f' || pblob->szURL[0] == 'F');
|
|
BlobStoreFileName(pblob, pblob->szURL+5);
|
|
|
|
BackgroundVRMLFile_Callback(tw, pel);
|
|
request->iFlags |= HTREQ_NULL_STREAM_IS_OK;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
// now construct a Blob Param structure
|
|
pBGBlobParams = BGBLOBPARAMSConstruct();
|
|
|
|
if ( pBGBlobParams == NULL )
|
|
return NULL;
|
|
|
|
// now set the blob so we know its loading, and its needs to be called
|
|
// when its finished downloading
|
|
pblob->dwFlags |= BLOB_FLAGS_FIXUP | BLOB_FLAGS_LOADING;
|
|
|
|
// now store the index of the element the blob is from
|
|
// and its tw structure for the window
|
|
pBGBlobParams->iIndex = iElement;
|
|
pBGBlobParams->tw = tw;
|
|
|
|
// now stuff it away so it can be retreived from the request structure
|
|
request->context = (void *) pBGBlobParams;
|
|
}
|
|
|
|
return GTR_DownloadBackgroundBlob(tw, request, param, input_format, output_format, output_stream);
|
|
}
|
|
#endif
|
|
|
|
HTStream *Viewer_Present(struct Mwin *tw, HTRequest *request, void *param, HTFormat input_format, HTFormat output_format, HTStream *output_stream)
|
|
{
|
|
#ifndef FEATURE_IMG_INLINE
|
|
struct ViewerInfo *pvi;
|
|
char path[_MAX_PATH + 1];
|
|
#endif
|
|
HTStream *me;
|
|
enum viewer_formats format;
|
|
#ifdef FEATURE_IMG_INLINE
|
|
HTStructured *target;
|
|
struct _www *prevdoc;
|
|
struct ImageInfo *pImg;
|
|
char *szRequestedURL;
|
|
#endif
|
|
|
|
if (input_format == HTAtom_for("image/gif"))
|
|
format = VIEWER_GIF;
|
|
else if (input_format == HTAtom_for("image/jpeg"))
|
|
format = VIEWER_JFIF;
|
|
#ifdef FEATURE_IMG_INLINE
|
|
else if (input_format == HTAtom_for("image/x-xbitmap"))
|
|
format = VIEWER_XBM;
|
|
#endif
|
|
else
|
|
format = VIEWER_INVALID;
|
|
|
|
if (format == VIEWER_INVALID)
|
|
{
|
|
/* This shouldn't happen unless our conversions are set
|
|
incorrectly in htinit.c. */
|
|
return NULL;
|
|
}
|
|
|
|
#ifdef FEATURE_IMG_INLINE
|
|
prevdoc = tw->w3doc;
|
|
target = HTML_new(tw, request, NULL, WWW_HTML, output_format, output_stream);
|
|
if (target == NULL) return NULL;
|
|
|
|
write_image(target,request->destination->szRequestedURL);
|
|
|
|
(*target->isa->free)(target);
|
|
if (tw->w3doc == NULL || tw->w3doc == prevdoc) return NULL;
|
|
|
|
pImg = pGetImage(tw->w3doc);
|
|
if (pImg == NULL) return NULL;
|
|
|
|
// NOTE: with FILE:, the HTParse code can modify the requested url through simplification
|
|
// and/or addition of driver or UNC spec.
|
|
szRequestedURL = GTR_strdup(pImg->srcURL);
|
|
if (szRequestedURL == NULL) return NULL;
|
|
GTR_FREE(request->destination->szRequestedURL);
|
|
request->destination->szRequestedURL = szRequestedURL;
|
|
|
|
tw->w3doc->bIsImage = TRUE;
|
|
|
|
if ((!(pImg->flags & IMG_LOADING)) && (pImg->flags & (IMG_ERROR|IMG_MISSING|IMG_NOTLOADED)))
|
|
{
|
|
pImg->decoderObject = pDC_ForceDecoder(tw);
|
|
if (pImg->decoderObject == NULL) return NULL;
|
|
pImg->flags &= ~(IMG_ERROR|IMG_MISSING);
|
|
pImg->flags |= IMG_LOADING|IMG_SEIZE|IMG_NOTLOADED;
|
|
request->cbRequestID = cbDC_GetRequestID(pImg->decoderObject);
|
|
if (format == VIEWER_GIF)
|
|
me = Image_GIF(tw,request,param,input_format,output_format,output_stream);
|
|
else if (format == VIEWER_JFIF)
|
|
me = Image_JPEG(tw,request,param,input_format,output_format,output_stream);
|
|
else
|
|
me = Image_XBM(tw,request,param,input_format,output_format,output_stream);
|
|
Image_UnblockMaster(tw);
|
|
}
|
|
else
|
|
{
|
|
Image_UnblockMaster(tw);
|
|
me = Image_NULL(tw,request,param,input_format,output_format,output_stream);
|
|
}
|
|
#else
|
|
pvi = (struct ViewerInfo *) GTR_MALLOC(sizeof(struct ViewerInfo));
|
|
memset(pvi, 0, sizeof(struct ViewerInfo));
|
|
pvi->tw = GTR_MALLOC(sizeof(struct Mwin));
|
|
pvi->original_tw = tw;
|
|
|
|
pvi->format = format;
|
|
|
|
if (request->szLocalFileName)
|
|
{
|
|
request->savefile = NULL;
|
|
request->nosavedlg = TRUE;
|
|
strcpy(pvi->fsOrig, request->szLocalFileName);
|
|
pvi->bNoDeleteFile = TRUE;
|
|
}
|
|
else
|
|
{
|
|
/* For external images being read from disk cache, the cache filename
|
|
* is already saved in request->savefile in HTLoadDCache_Async.
|
|
*/
|
|
|
|
//
|
|
// BUGBUG should be reviewed by deepak, s200fc3 merge could have affected this code
|
|
//
|
|
if (!request->fImgFromDCache)
|
|
{
|
|
// Get a temporary file name to pass to SaveLocally
|
|
pvi->fsOrig = GTR_MALLOC(_MAX_PATH + 1);
|
|
path[0] = 0;
|
|
PREF_GetTempPath(_MAX_PATH, path);
|
|
GetTempFileName(path, "A", 0, pvi->fsOrig);
|
|
request->savefile = pvi->fsOrig;
|
|
}
|
|
else
|
|
pvi->fsOrig = request->savefile;
|
|
pvi->bNoDeleteFile = FALSE;
|
|
}
|
|
|
|
request->nosavedlg = TRUE;
|
|
|
|
me = HTSaveWithCallback(tw, request, pvi, input_format, Viewer_Callback);
|
|
#endif
|
|
return me;
|
|
}
|
|
|
|
#ifndef FEATURE_IMG_INLINE
|
|
|
|
void Viewer_RedisplayImage(HWND hwnd, HDC hDC, struct ViewerInfo *pViewerInfo)
|
|
{
|
|
BOOL bReleaseDC = FALSE;
|
|
HPALETTE hOldPal;
|
|
|
|
if (!hDC)
|
|
{
|
|
hDC = GetDC(pViewerInfo->hwnd);
|
|
bReleaseDC = TRUE;
|
|
}
|
|
|
|
switch(wg.eColorMode)
|
|
{
|
|
case 8:
|
|
hOldPal = SelectPalette(hDC, hPalGuitar, FALSE);
|
|
|
|
SetDIBitsToDevice(hDC, -pViewerInfo->horz, -pViewerInfo->vert, pViewerInfo->nWidth,
|
|
pViewerInfo->nHeight, 0, 0, 0, pViewerInfo->nHeight, pViewerInfo->gw, pViewerInfo->pbmi, DIB_PAL_COLORS);
|
|
|
|
SelectObject(hDC, hOldPal);
|
|
break;
|
|
|
|
default:
|
|
SetDIBitsToDevice(hDC, -pViewerInfo->horz, -pViewerInfo->vert, pViewerInfo->nWidth, pViewerInfo->nHeight,
|
|
0, 0, 0, pViewerInfo->nHeight, pViewerInfo->gw, pViewerInfo->pbmi, DIB_RGB_COLORS);
|
|
}
|
|
|
|
if (bReleaseDC)
|
|
ReleaseDC(pViewerInfo->hwnd, hDC);
|
|
}
|
|
|
|
void Viewer_HorzScroll(struct ViewerInfo *pViewerInfo, int code, int pos)
|
|
{
|
|
int minpos, maxpos;
|
|
RECT rect;
|
|
|
|
GetClientRect(pViewerInfo->hwnd, &rect);
|
|
GetScrollRange(pViewerInfo->hwnd, SB_HORZ, &minpos, &maxpos);
|
|
|
|
if (rect.right >= pViewerInfo->nWidth)
|
|
return;
|
|
|
|
switch (code)
|
|
{
|
|
case SB_LINEUP:
|
|
if (pViewerInfo->horz == minpos)
|
|
return;
|
|
pViewerInfo->horz -=
|
|
max((int) (VIEWER_LINESCROLL_AMOUNT * (pViewerInfo->nWidth - rect.right)), 1);
|
|
pViewerInfo->horz = max(pViewerInfo->horz, minpos);
|
|
SetScrollPos(pViewerInfo->hwnd, SB_HORZ, pViewerInfo->horz, TRUE);
|
|
Viewer_RedisplayImage(pViewerInfo->hwnd, NULL, pViewerInfo);
|
|
break;
|
|
|
|
case SB_LINEDOWN:
|
|
if (pViewerInfo->horz == maxpos)
|
|
return;
|
|
pViewerInfo->horz +=
|
|
max((int) (VIEWER_LINESCROLL_AMOUNT * (pViewerInfo->nWidth - rect.right)), 1);
|
|
pViewerInfo->horz = min(pViewerInfo->horz, maxpos);
|
|
SetScrollPos(pViewerInfo->hwnd, SB_HORZ, pViewerInfo->horz, TRUE);
|
|
Viewer_RedisplayImage(pViewerInfo->hwnd, NULL, pViewerInfo);
|
|
break;
|
|
|
|
case SB_PAGEUP:
|
|
if (pViewerInfo->horz == minpos)
|
|
return;
|
|
pViewerInfo->horz -=
|
|
max((int) (VIEWER_PAGESCROLL_AMOUNT * (pViewerInfo->nWidth - rect.right)), 1);
|
|
pViewerInfo->horz = max(pViewerInfo->horz, minpos);
|
|
SetScrollPos(pViewerInfo->hwnd, SB_HORZ, pViewerInfo->horz, TRUE);
|
|
Viewer_RedisplayImage(pViewerInfo->hwnd, NULL, pViewerInfo);
|
|
break;
|
|
|
|
case SB_PAGEDOWN:
|
|
if (pViewerInfo->horz == maxpos)
|
|
return;
|
|
pViewerInfo->horz +=
|
|
max((int) (VIEWER_PAGESCROLL_AMOUNT * (pViewerInfo->nWidth - rect.right)), 1);
|
|
pViewerInfo->horz = min(pViewerInfo->horz, maxpos);
|
|
SetScrollPos(pViewerInfo->hwnd, SB_HORZ, pViewerInfo->horz, TRUE);
|
|
Viewer_RedisplayImage(pViewerInfo->hwnd, NULL, pViewerInfo);
|
|
break;
|
|
|
|
case SB_THUMBPOSITION:
|
|
pViewerInfo->horz = pos;
|
|
SetScrollPos(pViewerInfo->hwnd, SB_HORZ, pViewerInfo->horz, TRUE);
|
|
Viewer_RedisplayImage(pViewerInfo->hwnd, NULL, pViewerInfo);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void Viewer_VertScroll(struct ViewerInfo *pViewerInfo, int code, int pos)
|
|
{
|
|
int minpos, maxpos;
|
|
RECT rect;
|
|
|
|
GetClientRect(pViewerInfo->hwnd, &rect);
|
|
GetScrollRange(pViewerInfo->hwnd, SB_VERT, &minpos, &maxpos);
|
|
|
|
if (rect.bottom >= pViewerInfo->nHeight)
|
|
return;
|
|
|
|
switch (code)
|
|
{
|
|
case SB_LINEUP:
|
|
if (pViewerInfo->vert == minpos)
|
|
return;
|
|
pViewerInfo->vert -=
|
|
max((int) (VIEWER_LINESCROLL_AMOUNT * (pViewerInfo->nHeight - rect.bottom)), 1);
|
|
pViewerInfo->vert = max(pViewerInfo->vert, minpos);
|
|
SetScrollPos(pViewerInfo->hwnd, SB_VERT, pViewerInfo->vert, TRUE);
|
|
Viewer_RedisplayImage(pViewerInfo->hwnd, NULL, pViewerInfo);
|
|
break;
|
|
|
|
case SB_LINEDOWN:
|
|
if (pViewerInfo->vert == maxpos)
|
|
return;
|
|
pViewerInfo->vert +=
|
|
max((int) (VIEWER_LINESCROLL_AMOUNT * (pViewerInfo->nHeight - rect.bottom)), 1);
|
|
pViewerInfo->vert = min(pViewerInfo->vert, maxpos);
|
|
SetScrollPos(pViewerInfo->hwnd, SB_VERT, pViewerInfo->vert, TRUE);
|
|
Viewer_RedisplayImage(pViewerInfo->hwnd, NULL, pViewerInfo);
|
|
break;
|
|
|
|
case SB_PAGEUP:
|
|
if (pViewerInfo->vert == minpos)
|
|
return;
|
|
pViewerInfo->vert -=
|
|
max((int) (VIEWER_PAGESCROLL_AMOUNT * (pViewerInfo->nHeight - rect.bottom)), 1);
|
|
pViewerInfo->vert = max(pViewerInfo->vert, minpos);
|
|
SetScrollPos(pViewerInfo->hwnd, SB_VERT, pViewerInfo->vert, TRUE);
|
|
Viewer_RedisplayImage(pViewerInfo->hwnd, NULL, pViewerInfo);
|
|
break;
|
|
|
|
case SB_PAGEDOWN:
|
|
if (pViewerInfo->vert == maxpos)
|
|
return;
|
|
pViewerInfo->vert +=
|
|
max((int) (VIEWER_PAGESCROLL_AMOUNT * (pViewerInfo->nHeight - rect.bottom)), 1);
|
|
pViewerInfo->vert = min(pViewerInfo->vert, maxpos);
|
|
SetScrollPos(pViewerInfo->hwnd, SB_VERT, pViewerInfo->vert, TRUE);
|
|
Viewer_RedisplayImage(pViewerInfo->hwnd, NULL, pViewerInfo);
|
|
break;
|
|
|
|
case SB_THUMBPOSITION:
|
|
pViewerInfo->vert = pos;
|
|
SetScrollPos(pViewerInfo->hwnd, SB_VERT, pViewerInfo->vert, TRUE);
|
|
Viewer_RedisplayImage(pViewerInfo->hwnd, NULL, pViewerInfo);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void Viewer_RestrictSize(struct ViewerInfo *pViewerInfo, LPMINMAXINFO pInfo)
|
|
{
|
|
int borderwidth, borderheight, captionheight, scrollwidth, scrollheight;
|
|
|
|
if (!pViewerInfo->bInitialized)
|
|
return;
|
|
|
|
// Do not allow the user to size the window bigger than the actual image
|
|
|
|
borderwidth = GetSystemMetrics(SM_CXFRAME);
|
|
borderheight = GetSystemMetrics(SM_CYFRAME);
|
|
captionheight = GetSystemMetrics(SM_CYCAPTION) - GetSystemMetrics(SM_CYBORDER);
|
|
scrollwidth = GetSystemMetrics(SM_CXVSCROLL);
|
|
scrollheight = GetSystemMetrics(SM_CYHSCROLL) + GetSystemMetrics(SM_CYMENU) +
|
|
GetSystemMetrics(SM_CYBORDER);
|
|
|
|
pInfo->ptMaxSize.x = pViewerInfo->nWidth + 2 * borderwidth + scrollwidth - 1;
|
|
pInfo->ptMaxSize.y = pViewerInfo->nHeight + 2 * borderheight + captionheight + scrollheight - 1;
|
|
|
|
pInfo->ptMaxSize.x = min(pInfo->ptMaxSize.x,
|
|
GetSystemMetrics(SM_CXFULLSCREEN) + 2 * borderwidth);
|
|
pInfo->ptMaxSize.y = min(pInfo->ptMaxSize.y,
|
|
GetSystemMetrics(SM_CYFULLSCREEN) + captionheight + 2 * borderheight);
|
|
|
|
pInfo->ptMaxTrackSize.x = pInfo->ptMaxSize.x;
|
|
pInfo->ptMaxTrackSize.y = pInfo->ptMaxSize.y;
|
|
pInfo->ptMinTrackSize.x = 100;
|
|
pInfo->ptMinTrackSize.y = 100;
|
|
}
|
|
|
|
void Viewer_ReadjustScrollbars(struct ViewerInfo *pViewerInfo)
|
|
{
|
|
RECT rect;
|
|
|
|
if (!pViewerInfo || !pViewerInfo->bInitialized)
|
|
return;
|
|
|
|
GetClientRect(pViewerInfo->hwnd, &rect);
|
|
|
|
// Take a look at where the scrollbar is, and adjust the display accordingly
|
|
|
|
if (pViewerInfo->nWidth - pViewerInfo->horz < rect.right)
|
|
{
|
|
// Make the image flush to the right. The thumb is all the way on the right.
|
|
|
|
pViewerInfo->horz = pViewerInfo->nWidth - rect.right;
|
|
}
|
|
|
|
if (pViewerInfo->nHeight - pViewerInfo->vert < rect.bottom)
|
|
{
|
|
// Make the image flush to the bottom. The thumb is all the way on the bottom.
|
|
|
|
pViewerInfo->vert = pViewerInfo->nHeight - rect.bottom;
|
|
}
|
|
|
|
// Adjust the scrolling range
|
|
|
|
if (pViewerInfo->nWidth <= rect.right)
|
|
{
|
|
pViewerInfo->horz = 0;
|
|
SetScrollPos(pViewerInfo->hwnd, SB_HORZ, 0, TRUE);
|
|
EnableScrollBar(pViewerInfo->hwnd, SB_HORZ, ESB_DISABLE_BOTH);
|
|
}
|
|
else
|
|
{
|
|
EnableScrollBar(pViewerInfo->hwnd, SB_HORZ, ESB_ENABLE_BOTH);
|
|
SetScrollRange(pViewerInfo->hwnd, SB_HORZ, 0, pViewerInfo->nWidth - rect.right, TRUE);
|
|
SetScrollPos(pViewerInfo->hwnd, SB_HORZ, pViewerInfo->horz, TRUE);
|
|
}
|
|
|
|
if (pViewerInfo->nHeight <= rect.bottom)
|
|
{
|
|
pViewerInfo->vert = 0;
|
|
SetScrollPos(pViewerInfo->hwnd, SB_VERT, 0, TRUE);
|
|
EnableScrollBar(pViewerInfo->hwnd, SB_VERT, ESB_DISABLE_BOTH);
|
|
}
|
|
else
|
|
{
|
|
EnableScrollBar(pViewerInfo->hwnd, SB_VERT, ESB_ENABLE_BOTH);
|
|
SetScrollRange(pViewerInfo->hwnd, SB_VERT, 0, pViewerInfo->nHeight - rect.bottom, TRUE);
|
|
SetScrollPos(pViewerInfo->hwnd, SB_VERT, pViewerInfo->vert, TRUE);
|
|
}
|
|
}
|
|
|
|
void Viewer_SaveAsBitmap(char *tempFile, struct ViewerInfo *pViewerInfo)
|
|
{
|
|
BITMAPFILEHEADER bf;
|
|
int adjustedwidth;
|
|
FILE *fp;
|
|
|
|
adjustedwidth = pViewerInfo->pbmi->bmiHeader.biWidth * (pViewerInfo->pbmi->bmiHeader.biBitCount / 8);
|
|
if (adjustedwidth % 4)
|
|
adjustedwidth += (4 - (adjustedwidth % 4));
|
|
|
|
memcpy(&bf.bfType, "BM", 2);
|
|
bf.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) +
|
|
pViewerInfo->pbmi->bmiHeader.biHeight * adjustedwidth;
|
|
|
|
bf.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
|
|
|
|
if (pViewerInfo->pbmi->bmiHeader.biBitCount == 8)
|
|
{
|
|
bf.bfSize += (256 * sizeof(RGBQUAD));
|
|
bf.bfOffBits += (256 * sizeof(RGBQUAD));
|
|
}
|
|
|
|
bf.bfReserved1 = 0;
|
|
bf.bfReserved2 = 0;
|
|
|
|
// Ok, now save
|
|
|
|
fp = fopen(tempFile, "wb");
|
|
if (!fp)
|
|
{
|
|
ERR_ReportError(pViewerInfo->tw, errCantSaveFile, tempFile, "");
|
|
return;
|
|
}
|
|
|
|
fwrite(&bf, sizeof(bf), 1, fp);
|
|
|
|
if (pViewerInfo->pbmi->bmiHeader.biBitCount == 8)
|
|
{
|
|
PALETTEENTRY pal[256];
|
|
RGBQUAD rgb[256];
|
|
int index;
|
|
|
|
// Retrieve the currently realized palette since we use indices for 256-color images.
|
|
// Indices cannot be saved in the bitmap file - actual RGB values must be saved instead.
|
|
|
|
GetPaletteEntries(hPalGuitar, 0, 256, pal);
|
|
|
|
// Convert PALETTEENTRY to RGBQUAD
|
|
|
|
memset(&rgb, 0, sizeof(rgb));
|
|
|
|
for (index = 0; index < 256; index++)
|
|
{
|
|
rgb[index].rgbRed = pal[index].peRed;
|
|
rgb[index].rgbBlue = pal[index].peBlue;
|
|
rgb[index].rgbGreen = pal[index].peGreen;
|
|
}
|
|
|
|
fwrite(pViewerInfo->pbmi, 1, sizeof(BITMAPINFOHEADER), fp);
|
|
fwrite(rgb, sizeof(RGBQUAD), 256, fp);
|
|
}
|
|
else
|
|
fwrite(pViewerInfo->pbmi, 1, sizeof(BITMAPINFOHEADER), fp);
|
|
|
|
fwrite(pViewerInfo->gw, 1, pViewerInfo->pbmi->bmiHeader.biHeight * adjustedwidth, fp);
|
|
|
|
fclose(fp);
|
|
}
|
|
|
|
void Viewer_Print(struct ViewerInfo *pViewerInfo)
|
|
{
|
|
DOCINFO di;
|
|
HDC hDCPrinter;
|
|
int nHorzRes, nVertRes, nLogPixelsX, nLogPixelsY;
|
|
int cpxLeftMargin, cpxRightMargin, cpxDrawingArea; /* CountPixelsX... & CountPixelsY... */
|
|
int cpyTopMargin, cpyBottomMargin, cpyDrawingArea;
|
|
int nWidth;
|
|
int nHeight;
|
|
PBITMAPINFO pbmi;
|
|
|
|
hDCPrinter = PRINT_GetPrinterDC(pViewerInfo->tw, pViewerInfo->hwnd);
|
|
|
|
nHorzRes = GetDeviceCaps(hDCPrinter, HORZRES);
|
|
nVertRes = GetDeviceCaps(hDCPrinter, VERTRES);
|
|
nLogPixelsX = GetDeviceCaps(hDCPrinter, LOGPIXELSX);
|
|
nLogPixelsY = GetDeviceCaps(hDCPrinter, LOGPIXELSY);
|
|
|
|
cpxLeftMargin = (int) (gPrefs.page.marginleft * nLogPixelsX);
|
|
cpxRightMargin = nHorzRes - (int) (gPrefs.page.marginright * nLogPixelsX);
|
|
cpxDrawingArea = cpxRightMargin - cpxLeftMargin;
|
|
if (cpxDrawingArea < 0)
|
|
{
|
|
cpxLeftMargin = 0;
|
|
cpxRightMargin = nHorzRes;
|
|
cpxDrawingArea = nHorzRes;
|
|
}
|
|
|
|
cpyTopMargin = (int) (gPrefs.page.margintop * nLogPixelsY);
|
|
cpyBottomMargin = nVertRes - (int) (gPrefs.page.marginbottom * nLogPixelsY);
|
|
cpyDrawingArea = cpyBottomMargin - cpyTopMargin;
|
|
if (cpyDrawingArea < 0)
|
|
{
|
|
cpyTopMargin = 0;
|
|
cpyBottomMargin = nVertRes;
|
|
cpyDrawingArea = nVertRes;
|
|
}
|
|
|
|
/* tell the print queue manager that we're comming */
|
|
|
|
di.cbSize = sizeof(DOCINFO);
|
|
di.lpszDocName = pViewerInfo->szURL;
|
|
di.lpszOutput = NULL;
|
|
StartDoc(hDCPrinter, &di);
|
|
|
|
StartPage(hDCPrinter);
|
|
|
|
nWidth = (int) (pViewerInfo->nWidth * (nLogPixelsX / 72.0));
|
|
nHeight = (int) (pViewerInfo->nHeight * (nLogPixelsY / 72.0));
|
|
|
|
switch (wg.eColorMode)
|
|
{
|
|
case 8:
|
|
pbmi = BIT_Make_DIB_RGB_Header_Printer(pViewerInfo->nWidth, pViewerInfo->nHeight,
|
|
pViewerInfo->gw, hPalGuitar, BACKGROUND_COLOR_INDEX, 0);
|
|
if (pbmi)
|
|
{
|
|
(void) StretchDIBits(hDCPrinter, cpxLeftMargin, cpyTopMargin, nWidth, nHeight, 0, 0, pViewerInfo->nWidth, pViewerInfo->nHeight,
|
|
pViewerInfo->gw, pbmi, DIB_RGB_COLORS, SRCCOPY);
|
|
GTR_FREE(pbmi);
|
|
}
|
|
break;
|
|
default:
|
|
(void) StretchDIBits(hDCPrinter, cpxLeftMargin, cpyTopMargin, nWidth, nHeight, 0, 0, pViewerInfo->nWidth, pViewerInfo->nHeight,
|
|
pViewerInfo->gw, pViewerInfo->pbmi, DIB_RGB_COLORS, SRCCOPY);
|
|
break;
|
|
}
|
|
|
|
EndPage(hDCPrinter);
|
|
|
|
/* tell the print queue manager that we're finished */
|
|
|
|
EndDoc(hDCPrinter);
|
|
DeleteDC(hDCPrinter);
|
|
wg.lppdPrintDlg->hDC = NULL;
|
|
}
|
|
|
|
void Viewer_SaveAsOriginal(char *tempFile, struct ViewerInfo *pViewerInfo)
|
|
{
|
|
FILE *fpRead = NULL;
|
|
FILE *fpWrite = NULL;
|
|
char *pMem;
|
|
long cbWrite;
|
|
long cbRead;
|
|
BOOL bHaveError = FALSE;
|
|
#define BUFFSIZE 8192
|
|
|
|
// Simply copy the original file to the new file name
|
|
|
|
fpRead = fopen(pViewerInfo->fsOrig, "rb");
|
|
if (!fpRead)
|
|
{
|
|
bHaveError = TRUE;
|
|
goto exitPoint;
|
|
}
|
|
|
|
fpWrite = fopen(tempFile, "wb");
|
|
if (!fpWrite)
|
|
{
|
|
bHaveError = TRUE;
|
|
goto exitPoint;
|
|
}
|
|
|
|
pMem = GTR_MALLOC(BUFFSIZE);
|
|
if (pMem)
|
|
{
|
|
while (1)
|
|
{
|
|
cbRead = fread(pMem, 1, BUFFSIZE, fpRead);
|
|
if (cbRead > 0)
|
|
{
|
|
cbWrite = fwrite(pMem, 1, cbRead, fpWrite);
|
|
if (cbWrite == 0)
|
|
{
|
|
bHaveError = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (ferror(fpRead))
|
|
bHaveError = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
GTR_FREE(pMem);
|
|
}
|
|
else
|
|
{
|
|
bHaveError = TRUE;
|
|
}
|
|
|
|
exitPoint:
|
|
if (fpWrite)
|
|
{
|
|
if (fclose(fpWrite))
|
|
bHaveError = TRUE;
|
|
}
|
|
if (fpRead)
|
|
fclose(fpRead);
|
|
if (bHaveError)
|
|
ERR_ReportError(pViewerInfo->tw, errCantSaveFile, tempFile, "");
|
|
}
|
|
|
|
BOOL Viewer_HandleMenu(struct ViewerInfo *pViewerInfo, int menuID)
|
|
{
|
|
char tempFile[_MAX_PATH + 1];
|
|
char path[_MAX_PATH + 1];
|
|
char baseFile[_MAX_PATH + 1];
|
|
char *pExtension;
|
|
int filter;
|
|
HWND hwnd;
|
|
|
|
#ifdef FEATURE_HIDDEN_NOT_HIDDEN
|
|
if ((menuID >= RES_MENU_CHILD__FIRST__) && (menuID <= RES_MENU_CHILD__LAST__))
|
|
{
|
|
TW_ActivateWindowFromList(menuID, -1, NULL);
|
|
return TRUE;
|
|
}
|
|
#endif // FEATURE_HIDDEN_NOT_HIDDEN
|
|
|
|
// Return TRUE if we handled the menu here
|
|
|
|
switch(menuID)
|
|
{
|
|
case RES_MENU_ITEM_COPY:
|
|
OpenClipboard(pViewerInfo->hwnd);
|
|
EmptyClipboard();
|
|
|
|
// We need different clipboard copying code for 8-bit and 24-bit screens.
|
|
// For 8-bit, we must pass the handle to the actual bitmap because the palette
|
|
// we use is indexed, instead of containing true RGB values. Windows can't seem to
|
|
// handle this type of DIB for the clipboard. For 24-bit, we compose the DIB and pass
|
|
// the DIB to Windows.
|
|
|
|
pbmi = pViewerInfo->pbmi;
|
|
|
|
if (wg.eColorMode == 8)
|
|
SetClipboardData(CF_BITMAP, pViewerInfo->hBitmap);
|
|
else
|
|
{
|
|
newwidth = pViewerInfo->nWidth * (pbmi->bmiHeader.biBitCount / 8);
|
|
if (newwidth % 4)
|
|
newwidth += (4 - newwidth % 4);
|
|
|
|
hData = GlobalAlloc(GHND, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD) * (pbmi->bmiHeader.biBitCount == 8) +
|
|
newwidth * pViewerInfo->nHeight);
|
|
|
|
pMem = GlobalLock(hData);
|
|
|
|
memcpy(pMem, pbmi, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD) * (pbmi->bmiHeader.biBitCount == 8));
|
|
pMem += sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD) * (pbmi->bmiHeader.biBitCount == 8);
|
|
memcpy(pMem, pViewerInfo->gw, newwidth * pViewerInfo->nHeight);
|
|
|
|
GlobalUnlock(hData);
|
|
SetClipboardData(CF_DIB, hData);
|
|
|
|
// hData is now owned by the system
|
|
}
|
|
|
|
CloseClipboard();
|
|
|
|
return TRUE;
|
|
|
|
case RES_MENU_ITEM_SAVEAS:
|
|
path[0] = 0;
|
|
PREF_GetTempPath(_MAX_PATH, path);
|
|
|
|
switch(pViewerInfo->format)
|
|
{
|
|
case VIEWER_GIF:
|
|
x_get_good_filename(baseFile, _MAX_PATH - strlen(path), pViewerInfo->szURL, HTAtom_for("image/gif"));
|
|
strcpy(tempFile, baseFile);
|
|
|
|
// Lose the extension
|
|
|
|
pExtension = strchr(tempFile, '.');
|
|
if (pExtension)
|
|
*pExtension = '\0';
|
|
|
|
if ((filter = DlgSaveAs_RunDialog(pViewerInfo->hwnd, NULL, tempFile, 4, RES_STRING_SAVEAS)) < 0)
|
|
return TRUE;
|
|
|
|
if (!strstr(tempFile, ".GIF") && !strstr(tempFile, ".BMP"))
|
|
{
|
|
if (filter == 1)
|
|
strcat(tempFile, ".GIF");
|
|
else if (filter == 2)
|
|
strcat(tempFile, ".BMP");
|
|
}
|
|
break;
|
|
|
|
case VIEWER_JFIF:
|
|
x_get_good_filename(baseFile, _MAX_PATH - strlen(path), pViewerInfo->szURL, HTAtom_for("image/jpeg"));
|
|
strcpy(tempFile, baseFile);
|
|
|
|
// Lose the extension
|
|
|
|
pExtension = strchr(tempFile, '.');
|
|
if (pExtension)
|
|
*pExtension = '\0';
|
|
|
|
if ((filter = DlgSaveAs_RunDialog(pViewerInfo->hwnd, NULL, tempFile, 5, RES_STRING_SAVEAS)) < 0)
|
|
return TRUE;
|
|
|
|
if (!strstr(tempFile, ".JPG") && !strstr(tempFile, ".BMP"))
|
|
{
|
|
if (filter == 1)
|
|
strcat(tempFile, ".JPG");
|
|
else if (filter == 2)
|
|
strcat(tempFile, ".BMP");
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return FALSE;
|
|
}
|
|
|
|
// Copy the temporary file to the one the user specified. If the name is the same,
|
|
// then don't copy. This is handled automatically because a file cannot be opened
|
|
// for reading only and writing only at the same time.
|
|
|
|
if (_stricmp(pViewerInfo->fsOrig, tempFile) == 0)
|
|
{
|
|
|
|
}
|
|
|
|
// If the file name ends in BMP then save the file as a bitmap
|
|
|
|
if (strstr(tempFile, ".BMP"))
|
|
Viewer_SaveAsBitmap(tempFile, pViewerInfo);
|
|
else if (pViewerInfo->format == VIEWER_JFIF && strstr(tempFile, ".JPG"))
|
|
Viewer_SaveAsOriginal(tempFile, pViewerInfo);
|
|
else if (pViewerInfo->format == VIEWER_GIF && strstr(tempFile, ".GIF"))
|
|
Viewer_SaveAsOriginal(tempFile, pViewerInfo);
|
|
else
|
|
{
|
|
ERR_ReportError(pViewerInfo->tw, errCantSaveFile, tempFile, "");
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
case RES_MENU_ITEM_PRINT:
|
|
Viewer_Print(pViewerInfo);
|
|
return TRUE;
|
|
|
|
case RES_MENU_ITEM_PRINTSETUP:
|
|
DlgPrnt_RunDialog(pViewerInfo->tw, pViewerInfo->hwnd, FALSE);
|
|
return TRUE;
|
|
|
|
case RES_MENU_ITEM_PAGESETUP:
|
|
DlgPage_RunDialog(pViewerInfo->hwnd, &gPrefs.page);
|
|
return TRUE;
|
|
|
|
case RES_MENU_ITEM_CLOSE:
|
|
PostMessage(pViewerInfo->hwnd, WM_CLOSE, 0, 0);
|
|
return TRUE;
|
|
|
|
case RES_MENU_ITEM_EXIT:
|
|
PostMessage(wg.hWndHidden, WM_CLOSE, 0, 0);
|
|
return TRUE;
|
|
|
|
#ifdef FEATURE_HIDDEN_NOT_HIDDEN
|
|
case RES_MENU_CHILD_MOREWINDOWS:
|
|
DlgSelectWindow_RunDialog(pViewerInfo->hwnd);
|
|
return TRUE;
|
|
#endif // FEATURE_HIDDEN_NOT_HIDDEN
|
|
|
|
case RES_MENU_ITEM_GLOBALHISTORY:
|
|
DlgHOT_RunDialog(TRUE);
|
|
return TRUE;
|
|
|
|
case RES_MENU_ITEM_HOTLIST:
|
|
DlgHOT_RunDialog(FALSE);
|
|
return TRUE;
|
|
|
|
case RES_MENU_ITEM_ADDCURRENTTOHOTLIST:
|
|
// For an image viewer, URL and title are the same
|
|
|
|
if (!HotList_Add(pViewerInfo->szURL, pViewerInfo->szURL))
|
|
ERR_ReportError(pViewerInfo->tw, errHotListItemNotAdded, NULL, NULL);
|
|
|
|
return TRUE;
|
|
|
|
#ifdef OLD_HELP
|
|
case RES_MENU_ITEM_HELPPAGE:
|
|
tw = TW_FindTopmostWindow();
|
|
OpenHelpWindow(tw->hWndFrame);
|
|
SetForegroundWindow(tw->hWndFrame);
|
|
if (IsIconic(tw->hWndFrame))
|
|
ShowWindow(tw->hWndFrame, SW_RESTORE);
|
|
return TRUE;
|
|
#endif
|
|
|
|
#ifdef OLD_ABOUT_BOX
|
|
case RES_MENU_ITEM_ABOUTBOX:
|
|
DlgAbout_RunDialog(pViewerInfo->hwnd);
|
|
return TRUE;
|
|
#endif
|
|
|
|
#ifdef FEATURE_WINDOWS_MENU
|
|
case RES_MENU_ITEM_NEWWINDOW:
|
|
GTR_NewWindow(NULL, NULL, 0, 0, 0, NULL, NULL);
|
|
return TRUE;
|
|
|
|
case RES_MENU_ITEM_CASCADEWINDOWS:
|
|
TW_CascadeWindows();
|
|
return TRUE;
|
|
|
|
case RES_MENU_ITEM_TILEWINDOWS:
|
|
TW_TileWindows();
|
|
return TRUE;
|
|
|
|
case RES_MENU_ITEM_SWITCHWINDOW:
|
|
hwnd = TW_GetNextWindow(pViewerInfo->hwnd);
|
|
if (hwnd)
|
|
TW_RestoreWindow(hwnd);
|
|
return TRUE;
|
|
#endif
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
void Viewer_CleanUp()
|
|
{
|
|
int count, i;
|
|
struct ViewerInfo *p;
|
|
|
|
if (!bInitialized)
|
|
return;
|
|
|
|
// Destroy all open windows
|
|
|
|
count = Hash_Count(&gViewerCache);
|
|
for (i = 0; i < count; i++)
|
|
{
|
|
Hash_GetIndexedEntry(&gViewerCache, i, NULL, NULL, &p);
|
|
DestroyWindow(p->hwnd);
|
|
}
|
|
|
|
Hash_FreeContents(&gViewerCache);
|
|
}
|
|
|
|
HWND Viewer_GetNextWindow(BOOL bStart)
|
|
{
|
|
static int current_index = 0;
|
|
struct ViewerInfo *p;
|
|
|
|
if (bStart)
|
|
current_index = 0;
|
|
|
|
if (current_index >= Hash_Count(&gViewerCache))
|
|
return NULL;
|
|
|
|
if (!bStart)
|
|
current_index++;
|
|
|
|
if (current_index >= Hash_Count(&gViewerCache))
|
|
return NULL;
|
|
|
|
Hash_GetIndexedEntry(&gViewerCache, current_index, NULL, NULL, &p);
|
|
return (p->hwnd);
|
|
}
|
|
|
|
BOOL Viewer_IsWindow(HWND hwnd)
|
|
{
|
|
char szClass[MAX_WC_CLASSNAME];
|
|
|
|
GetClassName(hwnd, szClass, sizeof(szClass));
|
|
return (strcmp(szClass, Viewer_achClassName) == 0);
|
|
}
|
|
|
|
void Viewer_PaintIcon(struct ViewerInfo *pViewerInfo, HDC hDC)
|
|
{
|
|
HICON hIcon;
|
|
|
|
DefWindowProc(pViewerInfo->hwnd, WM_ICONERASEBKGND, (WPARAM) hDC, 0);
|
|
hIcon = LoadIcon(wg.hInstance, MAKEINTRESOURCE(RES_ICO_FRAME));
|
|
DrawIcon(hDC, 0, 0, hIcon);
|
|
}
|
|
|
|
static VOID Viewer_OnSize(HWND hWnd, UINT state, int cx, int cy)
|
|
{
|
|
struct ViewerInfo *p;
|
|
|
|
p = (struct ViewerInfo *) GetWindowLong(hWnd, 0);
|
|
|
|
if (p)
|
|
{
|
|
Viewer_ReadjustScrollbars(p);
|
|
InvalidateRect(hWnd, NULL, FALSE);
|
|
}
|
|
}
|
|
|
|
static VOID Viewer_OnCommand(HWND hWnd, int wId, HWND hWndCtl, UINT wNotifyCode)
|
|
{
|
|
struct ViewerInfo *p;
|
|
|
|
p = (struct ViewerInfo *) GetWindowLong(hWnd, 0);
|
|
if (p)
|
|
Viewer_HandleMenu(p, wId);
|
|
}
|
|
|
|
static void Viewer_OnVScroll(HWND hWnd, HWND hWndCtl, UINT code, int pos)
|
|
{
|
|
struct ViewerInfo *p;
|
|
|
|
p = (struct ViewerInfo *) GetWindowLong(hWnd, 0);
|
|
Viewer_VertScroll(p, code, pos);
|
|
}
|
|
|
|
static void Viewer_OnHScroll(HWND hWnd, HWND hWndCtl, UINT code, int pos)
|
|
{
|
|
struct ViewerInfo *p;
|
|
|
|
p = (struct ViewerInfo *) GetWindowLong(hWnd, 0);
|
|
Viewer_HorzScroll(p, code, pos);
|
|
}
|
|
|
|
static void Viewer_OnPaint(HWND hwnd)
|
|
{
|
|
PAINTSTRUCT ps;
|
|
HDC hdc;
|
|
struct ViewerInfo *p;
|
|
|
|
p = (struct ViewerInfo *) GetWindowLong(hwnd, 0);
|
|
|
|
hdc = BeginPaint(hwnd, &ps);
|
|
|
|
if (IsIconic(hwnd))
|
|
Viewer_PaintIcon(p, hdc);
|
|
else
|
|
Viewer_RedisplayImage(hwnd, hdc, p);
|
|
|
|
EndPaint(hwnd, &ps);
|
|
}
|
|
|
|
DCL_WinProc(Viewer_DlgProc)
|
|
{
|
|
struct ViewerInfo *p;
|
|
int ndx;
|
|
HICON hIcon;
|
|
HMENU hMenu;
|
|
|
|
switch (uMsg)
|
|
{
|
|
HANDLE_MSG(hWnd, WM_SIZE, Viewer_OnSize);
|
|
HANDLE_MSG(hWnd, WM_COMMAND, Viewer_OnCommand);
|
|
HANDLE_MSG(hWnd, WM_VSCROLL, Viewer_OnVScroll);
|
|
HANDLE_MSG(hWnd, WM_HSCROLL, Viewer_OnHScroll);
|
|
HANDLE_MSG(hWnd, WM_PAINT, Viewer_OnPaint);
|
|
|
|
case WM_KEYDOWN:
|
|
switch((int) wParam)
|
|
{
|
|
case VK_LEFT:
|
|
SendMessage(hWnd, WM_HSCROLL, (WPARAM) SB_LINEUP, 0);
|
|
return 0;
|
|
case VK_RIGHT:
|
|
SendMessage(hWnd, WM_HSCROLL, (WPARAM) SB_LINEDOWN, 0);
|
|
return 0;
|
|
case VK_UP:
|
|
SendMessage(hWnd, WM_VSCROLL, (WPARAM) SB_LINEUP, 0);
|
|
return 0;
|
|
case VK_DOWN:
|
|
SendMessage(hWnd, WM_VSCROLL, (WPARAM) SB_LINEDOWN, 0);
|
|
return 0;
|
|
case VK_PRIOR:
|
|
SendMessage(hWnd, WM_VSCROLL, (WPARAM) SB_PAGEUP, 0);
|
|
return 0;
|
|
case VK_NEXT:
|
|
SendMessage(hWnd, WM_VSCROLL, (WPARAM) SB_PAGEDOWN, 0);
|
|
return 0;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
//case WM_GETMINMAXINFO:
|
|
// p = (struct ViewerInfo *) GetWindowLong(hWnd, 0);
|
|
// Viewer_RestrictSize(p, (LPMINMAXINFO) lParam);
|
|
// return FALSE;
|
|
|
|
case WM_ERASEBKGND:
|
|
if (IsIconic(hWnd))
|
|
return 0;
|
|
break;
|
|
|
|
case WM_QUERYDRAGICON:
|
|
hIcon = LoadIcon(wg.hInstance, MAKEINTRESOURCE(RES_ICO_FRAME));
|
|
return (LONG) hIcon;
|
|
|
|
|
|
#ifdef FEATURE_HIDDEN_NOT_HIDDEN
|
|
case WM_INITMENU:
|
|
hMenu = GetMenu(hWnd);
|
|
TW_CreateWindowList(hWnd, hMenu, NULL);
|
|
break;
|
|
#endif // FEATURE_HIDDEN_NOT_HIDDEN
|
|
|
|
case WM_SETCURSOR:
|
|
/* If the window is currently disabled, we need to give the activation
|
|
to the window which disabled this window */
|
|
|
|
if ((!IsWindowEnabled(hWnd)) &&
|
|
((GetKeyState(VK_LBUTTON) & 0x8000) || (GetKeyState(VK_RBUTTON) & 0x8000)))
|
|
{
|
|
TW_EnableModalChild(hWnd);
|
|
}
|
|
break;
|
|
|
|
case WM_ENABLE:
|
|
if (wParam && !IsWindowEnabled(hWnd))
|
|
{
|
|
if (!TW_EnableModalChild(hWnd))
|
|
break;
|
|
else
|
|
return 0;
|
|
}
|
|
break;
|
|
|
|
case WM_CLOSE:
|
|
DestroyWindow(hWnd);
|
|
return 0;
|
|
|
|
case WM_DESTROY:
|
|
// Remove the item from the cached list
|
|
|
|
p = (struct ViewerInfo *) GetWindowLong(hWnd, 0);
|
|
ndx = Hash_FindByData(&gViewerCache, NULL, NULL, p);
|
|
Hash_DeleteIndexedEntry(&gViewerCache, ndx);
|
|
|
|
if (p->fsOrig && !p->bNoDeleteFile && !p->fDCached)
|
|
{
|
|
remove(p->fsOrig);
|
|
}
|
|
|
|
if (p->hBitmap)
|
|
DeleteObject(p->hBitmap);
|
|
|
|
if (p->gw)
|
|
GTR_FREE(p->gw);
|
|
|
|
if (p->fsOrig)
|
|
{
|
|
GTR_FREE(p->fsOrig);
|
|
}
|
|
GTR_FREE(p->tw);
|
|
GTR_FREE(p);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return DefWindowProc(hWnd, uMsg, wParam, lParam);
|
|
}
|
|
#endif
|
|
#ifdef FEATURE_IMG_INLINE
|
|
|
|
void Viewer_SaveAsBitmap(char *tempFile, PCImageInfo pImg, struct Mwin *tw)
|
|
{
|
|
BITMAPFILEHEADER bf;
|
|
int adjustedwidth;
|
|
FILE *fp;
|
|
int cbColors;
|
|
|
|
if (pImg->data == NULL || pImg->pbmi == NULL)
|
|
{
|
|
ERR_ReportError(tw, errCantSaveFile, tempFile, "");
|
|
return;
|
|
}
|
|
|
|
if (pImg->pbmi->bmiHeader.biBitCount == 1)
|
|
{
|
|
adjustedwidth = pImg->pbmi->bmiHeader.biWidth;
|
|
if (adjustedwidth % 32)
|
|
adjustedwidth += (32 - (adjustedwidth % 32));
|
|
adjustedwidth /= 8;
|
|
}
|
|
else
|
|
{
|
|
adjustedwidth = pImg->pbmi->bmiHeader.biWidth * (pImg->pbmi->bmiHeader.biBitCount / 8);
|
|
if (adjustedwidth % 4)
|
|
adjustedwidth += (4 - (adjustedwidth % 4));
|
|
}
|
|
memcpy(&bf.bfType, "BM", 2);
|
|
bf.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) +
|
|
pImg->pbmi->bmiHeader.biHeight * adjustedwidth;
|
|
|
|
bf.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
|
|
|
|
if (pImg->pbmi->bmiHeader.biBitCount == 8)
|
|
{
|
|
bf.bfSize += (256 * sizeof(RGBQUAD));
|
|
bf.bfOffBits += (256 * sizeof(RGBQUAD));
|
|
}
|
|
else if (pImg->pbmi->bmiHeader.biBitCount == 1)
|
|
{
|
|
bf.bfSize += (2 * sizeof(RGBQUAD));
|
|
bf.bfOffBits += (2 * sizeof(RGBQUAD));
|
|
}
|
|
|
|
bf.bfReserved1 = 0;
|
|
bf.bfReserved2 = 0;
|
|
|
|
// Ok, now save
|
|
|
|
fp = fopen(tempFile, "wb");
|
|
if (!fp)
|
|
{
|
|
ERR_ReportError(tw, errCantSaveFile, tempFile, "");
|
|
return;
|
|
}
|
|
|
|
fwrite(&bf, sizeof(bf), 1, fp);
|
|
|
|
cbColors = 1 << pImg->pbmi->bmiHeader.biBitCount;
|
|
if (cbColors == 256 || cbColors == 2)
|
|
{
|
|
PALETTEENTRY pal[256];
|
|
RGBQUAD rgb[256];
|
|
RGBQUAD *prgb = rgb;
|
|
int index;
|
|
|
|
// Retrieve the currently realized palette since we use indices for 256-color images.
|
|
// Indices cannot be saved in the bitmap file - actual RGB values must be saved instead.
|
|
|
|
if (wg.eColorMode != 8)
|
|
{
|
|
prgb = (RGBQUAD *)(&pImg->pbmi->bmiColors);
|
|
}
|
|
else
|
|
{
|
|
GetPaletteEntries(hPalGuitar, 0, 256, pal);
|
|
|
|
// Convert PALETTEENTRY to RGBQUAD
|
|
|
|
memset(&rgb, 0, sizeof(rgb));
|
|
|
|
if (cbColors == 2)
|
|
{
|
|
rgb[0].rgbRed = pal[BACKGROUND_COLOR_INDEX].peRed;
|
|
rgb[0].rgbBlue = pal[BACKGROUND_COLOR_INDEX].peBlue;
|
|
rgb[0].rgbGreen = pal[BACKGROUND_COLOR_INDEX].peGreen;
|
|
rgb[1].rgbRed = pal[FOREGROUND_COLOR_INDEX].peRed;
|
|
rgb[1].rgbBlue = pal[FOREGROUND_COLOR_INDEX].peBlue;
|
|
rgb[1].rgbGreen = pal[FOREGROUND_COLOR_INDEX].peGreen;
|
|
}
|
|
else
|
|
{
|
|
for (index = 0; index < cbColors; index++)
|
|
{
|
|
rgb[index].rgbRed = pal[index].peRed;
|
|
rgb[index].rgbBlue = pal[index].peBlue;
|
|
rgb[index].rgbGreen = pal[index].peGreen;
|
|
}
|
|
}
|
|
}
|
|
fwrite(pImg->pbmi, 1, sizeof(BITMAPINFOHEADER), fp);
|
|
fwrite(prgb, sizeof(RGBQUAD), cbColors, fp);
|
|
}
|
|
else
|
|
fwrite(pImg->pbmi, 1, sizeof(BITMAPINFOHEADER), fp);
|
|
|
|
fwrite(pImg->data, 1, pImg->pbmi->bmiHeader.biHeight * adjustedwidth, fp);
|
|
|
|
fclose(fp);
|
|
|
|
TRACE_OUT(("Viewer_SaveAsBitmap(): Saved bitmap to %s.",
|
|
tempFile));
|
|
}
|
|
|
|
|
|
void Viewer_SaveAsOriginal(char *tempFile, struct Mwin *tw, char *pCachePath)
|
|
{
|
|
FILE *fpRead = NULL;
|
|
FILE *fpWrite = NULL;
|
|
char *pMem;
|
|
long cbWrite;
|
|
long cbRead;
|
|
BOOL bHaveError = FALSE;
|
|
#define BUFFSIZE 8192
|
|
|
|
// Simply copy the original file to the new file name
|
|
|
|
fpRead = fopen(pCachePath, "rb");
|
|
if (!fpRead)
|
|
{
|
|
bHaveError = TRUE;
|
|
goto exitPoint;
|
|
}
|
|
|
|
fpWrite = fopen(tempFile, "wb");
|
|
if (!fpWrite)
|
|
{
|
|
bHaveError = TRUE;
|
|
goto exitPoint;
|
|
}
|
|
|
|
pMem = GTR_MALLOC(BUFFSIZE);
|
|
if (pMem)
|
|
{
|
|
while (1)
|
|
{
|
|
cbRead = fread(pMem, 1, BUFFSIZE, fpRead);
|
|
if (cbRead > 0)
|
|
{
|
|
cbWrite = fwrite(pMem, 1, cbRead, fpWrite);
|
|
if (cbWrite == 0)
|
|
{
|
|
bHaveError = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (ferror(fpRead))
|
|
bHaveError = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
GTR_FREE(pMem);
|
|
}
|
|
else
|
|
{
|
|
bHaveError = TRUE;
|
|
}
|
|
|
|
exitPoint:
|
|
if (fpWrite)
|
|
{
|
|
if (fclose(fpWrite))
|
|
bHaveError = TRUE;
|
|
}
|
|
if (fpRead)
|
|
fclose(fpRead);
|
|
if (bHaveError)
|
|
ERR_ReportError(tw, errCantSaveFile, tempFile, "");
|
|
}
|
|
|
|
static BOOL ImageSaveAs(struct Mwin *tw, PCImageInfo pImg, int iElem, PCSTR pcszURL,
|
|
PSTR szPath, UINT ucPathBufLen, DWORD dwFlags)
|
|
{
|
|
char tempFile[_MAX_PATH + 1];
|
|
char path[_MAX_PATH + 1];
|
|
char baseFile[_MAX_PATH + 1];
|
|
char *pExtension;
|
|
int filter;
|
|
char *pPath = NULL;
|
|
BOOL bResult = FALSE;
|
|
int inFilter;
|
|
const char *pDesiredExt = NULL;
|
|
int cbMimeAtom;
|
|
BOOL bIsAVI = FALSE;
|
|
struct _element *pel;
|
|
|
|
ASSERT(IS_VALID_STRUCT_PTR(tw, CMWIN));
|
|
ASSERT(IS_VALID_STRUCT_PTR(pImg, CImageInfo));
|
|
//ASSERT(IS_VALID_STRING_PTR(pcszURL, CSTR));
|
|
ASSERT(IS_FLAG_CLEAR(dwFlags, SAI_FL_RETURN_PATH) ||
|
|
IS_VALID_WRITE_BUFFER_PTR(szPath, STR, ucPathBufLen));
|
|
ASSERT(FLAGS_ARE_VALID(dwFlags, ALL_SAI_FLAGS));
|
|
|
|
ASSERT(tw->w3doc != NULL);
|
|
|
|
|
|
pel = NULL; // default case
|
|
|
|
// grab our Pel in order to figure out whether we have an AVI
|
|
if ( iElem >= 0 )
|
|
{
|
|
pel = &(tw->w3doc->aElements[iElem]);
|
|
}
|
|
|
|
// Do we have an AVI?
|
|
if ( pel && MCI_IS_LOADED(pel->pmo) && pel->pblob && pel->pblob->szURL)
|
|
{
|
|
pPath = PszGetDCachePath(pel->pblob->szURL, NULL, NULL);
|
|
bIsAVI = TRUE;
|
|
}
|
|
|
|
// If its not really there, ie no file
|
|
// then see if there is an image
|
|
if ( pPath == NULL && !bIsAVI &&
|
|
(pImg->actualURL || pImg->srcURL) )
|
|
{
|
|
pPath = pImage_GetDCachePath(pImg);
|
|
bIsAVI = FALSE;
|
|
}
|
|
else
|
|
{
|
|
// use the AVI URL
|
|
pcszURL = pel->pblob->szURL;
|
|
}
|
|
|
|
if (pPath == NULL && !_strnicmp("file:",pcszURL,5))
|
|
pPath = GTR_strdup(pcszURL+5);
|
|
|
|
path[0] = 0;
|
|
PREF_GetTempPath(_MAX_PATH, path);
|
|
|
|
if (bIsAVI)
|
|
{
|
|
pDesiredExt = ".AVI";
|
|
inFilter = 2;
|
|
}
|
|
else if (pImg->flags & IMG_JPEG)
|
|
{
|
|
cbMimeAtom = HTAtom_for("image/jpeg");
|
|
if (pPath)
|
|
{
|
|
inFilter = 5;
|
|
pDesiredExt = ".JPG";
|
|
}
|
|
else
|
|
inFilter = 9;
|
|
}
|
|
else if (pImg->flags & IMG_BW)
|
|
{
|
|
cbMimeAtom = HTAtom_for("image/x-xbitmap");
|
|
if (pPath)
|
|
{
|
|
inFilter = 10;
|
|
pDesiredExt = ".XBM";
|
|
}
|
|
else
|
|
inFilter = 9;
|
|
}
|
|
else
|
|
{
|
|
cbMimeAtom = HTAtom_for("image/gif");
|
|
if (pPath)
|
|
{
|
|
inFilter = 4;
|
|
pDesiredExt = ".GIF";
|
|
}
|
|
else
|
|
inFilter = 9;
|
|
}
|
|
|
|
if (IS_FLAG_SET(dwFlags, SAI_FL_SAVE_BITMAP))
|
|
{
|
|
/* Only allow save to bitmap. */
|
|
inFilter = 9;
|
|
pDesiredExt = NULL;
|
|
}
|
|
|
|
x_get_good_filename(baseFile, _MAX_PATH - strlen(path), pcszURL, cbMimeAtom);
|
|
strcpy( tempFile, baseFile );
|
|
|
|
// Lose the extension
|
|
|
|
/*
|
|
* BUGBUG: (DavidDi 4/10/95) What if path contains a period? We truncate
|
|
* tempFile there instead of at the baseFile extension.
|
|
*/
|
|
// don't remove the extension if its an AVI,
|
|
// otherwise remove the extension
|
|
if ( ! bIsAVI )
|
|
{
|
|
pExtension = strchr(tempFile, '.');
|
|
if (pExtension)
|
|
*pExtension = '\0';
|
|
}
|
|
|
|
if ((filter = DlgSaveAs_RunDialog(GetParent(tw->win), path, tempFile, inFilter, RES_STRING_SAVEAS)) < 0)
|
|
goto exitTrue;
|
|
|
|
CharUpperBuff(tempFile, strlen(tempFile));
|
|
|
|
/*
|
|
* BUGBUG: (DavidDi 4/10/95) What if path contains ".BMP" somewhere other
|
|
* than the file extension? We treat the file as a bitmap even if it is
|
|
* not.
|
|
*/
|
|
if (pDesiredExt)
|
|
{
|
|
if (!strstr(tempFile, pDesiredExt) && !strstr(tempFile, ".BMP"))
|
|
{
|
|
if (filter == 1)
|
|
strcat(tempFile, pDesiredExt);
|
|
else if (filter == 2)
|
|
strcat(tempFile, ".BMP");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!strstr(tempFile, ".BMP"))
|
|
strcat(tempFile, ".BMP");
|
|
}
|
|
|
|
// If the file name ends in BMP then save the file as a bitmap
|
|
|
|
if (strstr(tempFile, ".BMP"))
|
|
Viewer_SaveAsBitmap(tempFile, pImg, tw);
|
|
else if (
|
|
pPath &&
|
|
( bIsAVI ||
|
|
(((pImg->flags & IMG_JPEG) && strstr(tempFile, ".JPG")) ||
|
|
((pImg->flags & IMG_BW) && strstr(tempFile, ".XBM")) ||
|
|
((!(pImg->flags & (IMG_JPEG|IMG_BW))) && strstr(tempFile, ".GIF")))
|
|
)
|
|
)
|
|
Viewer_SaveAsOriginal(tempFile, tw, pPath);
|
|
else
|
|
{
|
|
ERR_ReportError(tw, errCantSaveFile, tempFile, "");
|
|
goto exitPoint;
|
|
}
|
|
|
|
TRACE_OUT(("bSaveAsImageHTML(): Saved image to %s.",
|
|
tempFile));
|
|
|
|
if (IS_FLAG_SET(dwFlags, SAI_FL_RETURN_PATH))
|
|
MyLStrCpyN(szPath, tempFile, ucPathBufLen);
|
|
|
|
exitTrue:
|
|
bResult = TRUE;
|
|
exitPoint:
|
|
if (pPath) GTR_FREE(pPath);
|
|
return bResult;
|
|
}
|
|
|
|
// Saves an inline image.
|
|
BOOL SaveElementAsImage(struct Mwin *tw, int iElem, PSTR szPath,
|
|
UINT ucPathBufLen, DWORD dwFlags)
|
|
{
|
|
BOOL bResult = FALSE;
|
|
|
|
ASSERT(IS_VALID_STRUCT_PTR(tw, CMWIN));
|
|
ASSERT(IsValidElementIndex(tw, iElem));
|
|
ASSERT(IS_FLAG_CLEAR(dwFlags, SAI_FL_RETURN_PATH) ||
|
|
IS_VALID_WRITE_BUFFER_PTR(szPath, STR, ucPathBufLen));
|
|
ASSERT(FLAGS_ARE_VALID(dwFlags, ALL_SAI_FLAGS));
|
|
|
|
if (EVAL(tw->w3doc != NULL))
|
|
{
|
|
PCImageInfo pcimginfo;
|
|
|
|
pcimginfo = tw->w3doc->aElements[iElem].myImage;
|
|
|
|
if (pcimginfo)
|
|
bResult = ImageSaveAs(tw, pcimginfo, iElem, pcimginfo->actualURL, szPath,
|
|
ucPathBufLen, dwFlags);
|
|
}
|
|
|
|
return(bResult);
|
|
}
|
|
|
|
// Saves an HTML document that is just a wrapper for an image as an image.
|
|
BOOL bSaveAsImageHTML(struct Mwin *tw)
|
|
{
|
|
BOOL bResult = FALSE;
|
|
|
|
ASSERT(IS_VALID_STRUCT_PTR(tw, CMWIN));
|
|
|
|
if (EVAL(tw->w3doc != NULL))
|
|
{
|
|
PCImageInfo pcimginfo;
|
|
|
|
pcimginfo = pGetImage(tw->w3doc);
|
|
|
|
if (pcimginfo)
|
|
bResult = ImageSaveAs(tw, pcimginfo, -1, tw->w3doc->szActualURL, NULL, 0,
|
|
0);
|
|
}
|
|
|
|
return(bResult);
|
|
}
|
|
|
|
|
|
|
|
// SaveElementAsAnything - attempts to save a link,
|
|
// with a forced binary download, this is used by
|
|
// the Context Menu "Save As.."
|
|
VOID SaveElementAsAnything(struct Mwin *tw, int iElem )
|
|
{
|
|
|
|
if (EVAL(tw->w3doc != NULL))
|
|
{
|
|
char buf[MAX_URL_STRING];
|
|
struct _element *pel = &(tw->w3doc->aElements[iElem]);
|
|
|
|
XX_Assert((pel->hrefLen <= MAX_URL_STRING), ("String overflow"));
|
|
GTR_strncpy(buf, &tw->w3doc->pool[pel->hrefOffset], pel->hrefLen);
|
|
buf[pel->hrefLen] = 0;
|
|
|
|
// "I don't care" since we don't care about the actual format,
|
|
// we just want a forced binary download.
|
|
GTR_DownLoad(tw, buf, tw->w3doc->szActualURL, WWW_FORCEDOWNLOAD);
|
|
}
|
|
}
|
|
|
|
#endif /* FEATURE_IMG_INLINE */
|
|
#endif /* FEATURE_IMAGE_VIEWER */
|
|
|