📄 npwebwko.c
字号:
/* -*- Mode: C; tab-width: 4; -*- */
/* npwebwko.c
* WebWKO - a Win32 browser plug-in that displays WKO image files
* By Daniel Vollmer, based on WebBMP by Jason Summers
*/
#define PRGNAME "WebWKO Plug-in"
#define VERS "1.0.0"
/* Note: Depending on your compiler, npwin.cpp may need to be altered by
* wrapping the g_pNavigatorFuncs definition with 'extern "C"' as such:
*
* extern "C" {
* NPNetscapeFuncs* g_pNavigatorFuncs = 0;
* }
*
*/
#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <process.h>
#include <time.h>
#include "npupp.h"
#include "npapi.h"
#include "resource.h"
#include "../wavelet/bit.h"
#include "../wavelet/wavelet.h"
#include "../wavelet/mchannel.h"
#define ST_NOTLOADED 0
#define ST_LOADED 1
#define DELAY_PER_3K 2
#define INITIAL_UPDATE_BITS 1024
#define INVALID_THREAD (NULL)
/*IE插件事件数据类型定义 */
typedef struct plugininstance_struct
{
NPWindow* fWindow;
uint16 fMode;
HWND fhWnd;
WNDPROC fDefaultWindowProc;
NPP instance;
char url[2048]; //数据流的url源
int status; //是否完成了图象的装载
//若完成,取值ST_LOADED;否则取值ST_NOTLOADED。
int streamend; //传输数据流的大小,如果为0表示数据流大小未知
int valid; //图象属性是否有效
unsigned int last_bits_drawn;
time_t last_time_drawn;
unsigned int update_bits;
BITMAPINFO bi; //解码BMP后的图象文件头信息
HBITMAP dib; //BMP图象数据
unsigned int *dib_bits;
int wvh_is_yuv;
t_wv_header wvh;
CRITICAL_SECTION bitmap_lock;
CRITICAL_SECTION lpbits_lock;
HANDLE decode_thread, last_thread;
unsigned char *lpbits; //指向图象数据流的指针
unsigned int bits_read; //数据数据流的比特位数量
int bytes_alloc; //相应计算机字节内存分配的大小
} PluginInstance;
/* global variables */
extern NPNetscapeFuncs* g_pNavigatorFuncs;
const char* gInstanceLookupString = "pdata";
HMODULE hInst;
HMENU hmenuContext=NULL;
/* forward declarations of functions */
LRESULT CALLBACK DlgProcAbout(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK PluginWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
void UpdateBitmap(PluginInstance *This);
void PaintBitmap(PluginInstance *This, HDC hdc, RECT *rect);
void ContextMenu(PluginInstance *This, int x, int y, HWND hwnd);
/* ----------------------------------------------------------------------- */
BOOL APIENTRY DllMain(HANDLE hModule, DWORD reason, LPVOID lpReserved)
{
switch(reason) {
case DLL_PROCESS_ATTACH:
hInst=hModule;
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
void warn(PluginInstance *This, char *fmt, ...)
{
va_list ap;
char buf[2048];
HWND hwnd;
va_start(ap, fmt);
vsprintf(buf,fmt, ap);
va_end(ap);
if (This)
hwnd=This->fhWnd;
else
hwnd=NULL;
MessageBox(hwnd,buf,"WebWKO Plug-in",MB_OK|MB_ICONWARNING);
}
/* if enough of the image is loaded, extract its width, height, etc. */
void GetImageInfo(PluginInstance *This)
{
t_bit_file *bf;
/*********
1 bit: is yuv
24 bits:magic number
4 bits: header version
4 bits: bitstream version
1 bit: have non-pow2 dimensions
16 bit: width - 1
16 bit: height - 1
4 bits: num channels - 1
4 bits: pow2 width
4 bits: pow2 height
4 bits: num blocks - 1
5 bits: size min block
-----------------
55 bits (dimension bit 0) or 87 bits (dimension bit 1)
**********/
if (!This->lpbits || This->bits_read < 87)
return;
bf = bit_open(This->lpbits, "rm", This->bits_read);
if (bf)
{
t_wv_header hdr;
This->wvh_is_yuv = bit_read(1, bf);
if (wv_read_header(&hdr, bf) != NULL)
{
This->wvh = hdr;
if (This->wvh.width >= 1 && This->wvh.height >= 1 && This->wvh.size_min_block > 0)
{
This->bi.bmiHeader.biSize = sizeof This->bi.bmiHeader;
This->bi.bmiHeader.biWidth = This->wvh.owidth;
This->bi.bmiHeader.biHeight = This->wvh.oheight;
This->bi.bmiHeader.biPlanes = 1;
This->bi.bmiHeader.biBitCount = 32;
This->bi.bmiHeader.biCompression = BI_RGB;
This->bi.bmiHeader.biSizeImage = This->wvh.owidth * This->wvh.oheight * 4;
This->bi.bmiHeader.biXPelsPerMeter = This->bi.bmiHeader.biYPelsPerMeter = 0;
This->bi.bmiHeader.biClrUsed = This->bi.bmiHeader.biClrImportant = 0;
This->valid = 1;
}
}
bit_close(bf, NULL);
}
}
/* ----------------------------------------------------------------------- */
/* Global initialization */
NPError NPP_Initialize(void)
{
hmenuContext = LoadMenu(hInst,"CONTEXTMENU");
return NPERR_NO_ERROR;
}
/* Global shutdown */
void NPP_Shutdown(void)
{
if (hmenuContext)
DestroyMenu(hmenuContext);
}
/* Once-per-instance initialization */
NPError NPP_New(NPMIMEType pluginType,NPP instance,uint16 mode,
int16 argc,char* argn[],char* argv[],NPSavedData* saved)
{
PluginInstance* This;
if (!instance)
return NPERR_INVALID_INSTANCE_ERROR;
instance->pdata = malloc(sizeof (PluginInstance));
This = (PluginInstance*)instance->pdata;
if (!This)
return NPERR_OUT_OF_MEMORY_ERROR;
memset(This, 0, sizeof *This);
/* record some info for later lookup */
This->fWindow = NULL;
This->fMode = mode;
This->fhWnd = NULL;
This->fDefaultWindowProc = NULL;
This->instance = instance; /* save the instance id for reverse lookups */
This->lpbits = NULL;
This->bits_read = 0;
This->bytes_alloc=0;
This->status=ST_NOTLOADED;
This->valid=0;
This->dib = NULL;
This->dib_bits = NULL;
This->decode_thread = This->last_thread = INVALID_THREAD;
InitializeCriticalSection(&This->bitmap_lock);
InitializeCriticalSection(&This->lpbits_lock);
return NPERR_NO_ERROR;
}
NPError NPP_Destroy(NPP instance, NPSavedData** save)
{
PluginInstance* This;
if (!instance)
return NPERR_INVALID_INSTANCE_ERROR;
This = (PluginInstance*)instance->pdata;
if (!This)
return NPERR_INVALID_INSTANCE_ERROR;
if (This->fhWnd)
{ // If we have a window, clean it up (un-subclass it)
SetWindowLong( This->fhWnd, GWL_WNDPROC, (LONG)This->fDefaultWindowProc);
This->fDefaultWindowProc = NULL;
This->fhWnd = NULL;
}
if (This->last_thread != INVALID_THREAD)
{
WaitForSingleObject(This->last_thread, INFINITE);
CloseHandle(This->last_thread);
This->last_thread = INVALID_THREAD;
}
DeleteCriticalSection(&This->bitmap_lock);
DeleteCriticalSection(&This->lpbits_lock);
if (This->lpbits)
{
free(This->lpbits);
This->lpbits = NULL;
This->bytes_alloc = 0;
This->bits_read = 0;
}
if (This->dib)
{
DeleteObject(This->dib);
This->dib = NULL;
}
if (This)
{
if (instance->pdata)
{
free(instance->pdata);
instance->pdata = NULL;
}
}
return NPERR_NO_ERROR;
}
jref NPP_GetJavaClass(void)
{
return NULL;
}
/* Browser is providing us with a window */
NPError NPP_SetWindow(NPP instance, NPWindow* window)
{
NPError result = NPERR_NO_ERROR;
PluginInstance* This;
if (!instance)
return NPERR_INVALID_INSTANCE_ERROR;
This = (PluginInstance*)instance->pdata;
/* if( This->fWindow != NULL ) -- from example in Netscape's API, but not really correct */
if (This->fhWnd)
{ /* If we already have a window... */
if ((!window) || (!window->window))
{
/* There is now no window to use. get rid of the old
* one and exit. */
SetWindowLong(This->fhWnd, GWL_WNDPROC, (LONG)This->fDefaultWindowProc);
This->fDefaultWindowProc = NULL;
This->fhWnd = NULL;
This->fWindow = window;
return NPERR_NO_ERROR;
}
else if (This->fhWnd == (HWND)window->window)
{
/* The new window is the same as the old one. Redraw and get out. */
This->fWindow = window;
InvalidateRect(This->fhWnd, NULL, FALSE);
return NPERR_NO_ERROR;
}
else
{
/* Unsubclass the old window, so that we can subclass the new
* one later. */
SetWindowLong(This->fhWnd, GWL_WNDPROC, (LONG)This->fDefaultWindowProc);
This->fDefaultWindowProc = NULL;
This->fhWnd = NULL;
}
}
else if ((!window) || (!window->window))
{
/* We can just get out of here if there is no current
* window and there is no new window to use. */
This->fWindow=window;
return NPERR_NO_ERROR;
}
/* Subclass the new window so that we can begin drawing and
* receiving window messages. */
This->fDefaultWindowProc = (WNDPROC)SetWindowLong((HWND)window->window, GWL_WNDPROC, (LONG)PluginWindowProc);
This->fhWnd = (HWND)window->window;
SetProp(This->fhWnd, gInstanceLookupString, (HANDLE)This);
This->fWindow = window;
InvalidateRect(This->fhWnd, NULL, FALSE);
// UpdateWindow(This->fhWnd);
return result;
}
NPError NPP_NewStream(NPP instance,NPMIMEType type,NPStream *stream,
NPBool seekable,uint16 *stype) {
PluginInstance* This;
if(instance == NULL)
return NPERR_INVALID_INSTANCE_ERROR;
This = (PluginInstance*)instance->pdata;
if(!This)
return NPERR_GENERIC_ERROR;
//保存数据流的url地址
strncpy(This->url, stream->url, 2048);
This->url[2047]='\0';
*stype = NP_NORMAL;
if (This->last_thread != INVALID_THREAD)
{
WaitForSingleObject(This->last_thread, INFINITE);
CloseHandle(This->last_thread);
This->last_thread = INVALID_THREAD;
}
if(This->lpbits)
{
free(This->lpbits);
This->lpbits = NULL;
This->bytes_alloc=0;
}
if (This->dib)
{
DeleteObject(This->dib);
This->dib = NULL;
This->dib_bits = NULL;
}
This->status=ST_NOTLOADED;
This->streamend = stream->end;
This->bits_read = 0;
This->last_bits_drawn = 0;
This->last_time_drawn = 0;
This->last_time_drawn = time(NULL);
This->update_bits = INITIAL_UPDATE_BITS;
This->valid = 0;
return NPERR_NO_ERROR;
}
int32 NPP_WriteReady(NPP instance, NPStream *stream)
{
/* Number of bytes ready to accept in NPP_Write() */
/* We can handle any amount, so just return some really big number. */
return (int32)0x0FFFFFFF;
// return (int32)INITIAL_UPDATE_BITS / 8;
}
int32 NPP_Write(NPP instance, NPStream *stream, int32 offset, int32 len, void *buffer)
{
PluginInstance* This;
int32 new_alloc;
//如果插件事件无效,返回无效值
if (!instance)
return -1;
//如果数据流为空,返回无效值
This = (PluginInstance*)instance->pdata;
if (!This)
return -1;
//创建新的数据空间
new_alloc = This->bytes_alloc;
if (!This->lpbits)
new_alloc = This->streamend > 0 ? This->streamend : offset + len;
new_alloc = max(new_alloc, offset + len);
if (new_alloc != This->bytes_alloc)
{
EnterCriticalSection(&This->lpbits_lock);
This->lpbits = realloc(This->lpbits, new_alloc);
This->bytes_alloc = new_alloc;
This->bits_read = (offset + len) * 8;
LeaveCriticalSection(&This->lpbits_lock);
if (!This->lpbits)
{
warn(This,"Out of memory");
return -1;
}
memset(This->lpbits + This->bytes_alloc, 0, new_alloc - This->bytes_alloc);
}
else
This->bits_read = (offset + len) * 8; // hopefully we read everything _before_ that, too...
memcpy(This->lpbits + offset, buffer, len);
if (!This->valid)
GetImageInfo(This);
if (This->fhWnd && This->valid && This->bits_read - This->last_bits_drawn >= This->update_bits)
{
//渐进显示
time_t ct;
int timeofs;
/*因为在IE的同一个图象区域显示不同的图象,都是以渐进传输显示的方式处理图象数据,
特别是当图象的尺寸与IE的显示区域不相同的时候,将影响渐进传输过程。为了防止这种
情况,必须确定最后一次数据更新后的时耗总量。*/
ct = time(NULL);
timeofs = ((This->wvh.width + This->wvh.height) * This->wvh.num_channels * DELAY_PER_3K) / (3 * 1024);
if (ct - This->last_time_drawn >= timeofs)
UpdateBitmap(This);
}
//函数返回有效的数据字节数,系统将处理其全部接收到的数据
return len;
}
NPError NPP_DestroyStream(NPP instance, NPStream *stream, NPError reason)
{
PluginInstance* This;
//如果插件事件无效,返回无效值
if (!instance)
return NPERR_INVALID_INSTANCE_ERROR;
This = (PluginInstance*)instance->pdata;
if (!This)
return NPERR_INVALID_INSTANCE_ERROR;
if (!This->valid)
GetImageInfo(This);
if (reason == NPRES_DONE)
{
This->status = This->valid ? ST_LOADED : ST_NOTLOADED;
if (!This->valid)
warn(This, "Invalid WKO image");
}
if (This->fhWnd && This->bits_read - This->last_bits_drawn > 0)
{
if (This->last_thread != INVALID_THREAD)
{
WaitForSingleObject(This->last_thread, INFINITE);
CloseHandle(This->last_thread);
This->last_thread = INVALID_THREAD;
}
// 如果数据流装载没有完成,同样更新IE窗口
UpdateBitmap(This);
}
//返回默认有效值
return NPERR_NO_ERROR;
}
/* This should not get called, since we aren't using the NP_ASFILE mode */
void NPP_StreamAsFile(NPP instance, NPStream *stream, const char* fname)
{
return;
}
/* Print embedded plug-in (via the browser's Print command) */
void NPP_Print(NPP instance, NPPrint* printInfo)
{
PluginInstance* This;
if (!instance)
return;
This = (PluginInstance*) instance->pdata;
if (!This)
return;
if (!This->valid)
return;
if(printInfo == NULL) {
/* Though it's not documented, if a Netscape user tries to print a full-page
* plugin, the browser will call NPP_Print with printInfo set to NULL.
* At this point you should print your plug-in in whatever manner you
* choose. */
/* PrintFullPage(); */ /* not implemented */
return;
}
if (printInfo->mode == NP_FULL) {
/* the plugin is full-page, and the browser is giving it a chance
* to print in the manner of its choosing */
void* platformPrint = printInfo->print.fullPrint.platformPrint;
NPBool printOne = printInfo->print.fullPrint.printOne;
/* Setting this to FALSE and returning *should* cause the browser to
* call NPP_Print again, this time with mode=NP_EMBED.
* However, that doesn't happen with any browser I've ever seen :-(.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -