mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
309 lines
8.1 KiB
C++
309 lines
8.1 KiB
C++
/* ***** BEGIN LICENSE BLOCK *****
|
|
*
|
|
* Copyright (c) 2008, Mozilla Corporation
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
*
|
|
* * Redistributions of source code must retain the above copyright notice, this
|
|
* list of conditions and the following disclaimer.
|
|
* * Redistributions in binary form must reproduce the above copyright notice,
|
|
* this list of conditions and the following disclaimer in the documentation
|
|
* and/or other materials provided with the distribution.
|
|
* * Neither the name of the Mozilla Corporation nor the names of its
|
|
* contributors may be used to endorse or promote products derived from this
|
|
* software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
* Contributor(s):
|
|
* Josh Aas <josh@mozilla.com>
|
|
* Jim Mathies <jmathies@mozilla.com>
|
|
*
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
#include "nptest_platform.h"
|
|
|
|
#include <windows.h>
|
|
#include <unknwn.h>
|
|
#include <gdiplus.h>
|
|
using namespace Gdiplus;
|
|
|
|
#pragma comment(lib, "gdiplus.lib")
|
|
|
|
void SetSubclass(HWND hWnd, InstanceData* instanceData);
|
|
void ClearSubclass(HWND hWnd);
|
|
Color GetColorsFromRGBA(PRUint32 rgba);
|
|
LRESULT CALLBACK PluginWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
|
|
|
bool
|
|
pluginSupportsWindowMode()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
pluginSupportsWindowlessMode()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
NPError
|
|
pluginInstanceInit(InstanceData* instanceData)
|
|
{
|
|
return NPERR_NO_ERROR;
|
|
}
|
|
|
|
void
|
|
pluginInstanceShutdown(InstanceData* instanceData)
|
|
{
|
|
}
|
|
|
|
void
|
|
pluginDoSetWindow(InstanceData* instanceData, NPWindow* newWindow)
|
|
{
|
|
instanceData->window = *newWindow;
|
|
}
|
|
|
|
void
|
|
pluginWidgetInit(InstanceData* instanceData, void* oldWindow)
|
|
{
|
|
HWND hWnd = (HWND)instanceData->window.window;
|
|
if (oldWindow) {
|
|
HWND hWndOld = (HWND)oldWindow;
|
|
ClearSubclass(hWndOld);
|
|
}
|
|
SetSubclass(hWnd, instanceData);
|
|
}
|
|
|
|
void
|
|
pluginDraw(InstanceData* instanceData)
|
|
{
|
|
NPP npp = instanceData->npp;
|
|
if (!npp)
|
|
return;
|
|
|
|
const char* uaString = NPN_UserAgent(npp);
|
|
if (!uaString)
|
|
return;
|
|
|
|
HDC hdc = NULL;
|
|
PAINTSTRUCT ps;
|
|
|
|
if (instanceData->hasWidget)
|
|
hdc = ::BeginPaint((HWND)instanceData->window.window, &ps);
|
|
else
|
|
hdc = (HDC)instanceData->window.window;
|
|
|
|
if (hdc == NULL)
|
|
return;
|
|
|
|
// Push the browser's hdc on the resource stack. If this test plugin is windowless,
|
|
// we share the drawing surface with the rest of the browser.
|
|
int savedDCID = SaveDC(hdc);
|
|
|
|
// Reset the clipping region
|
|
SelectClipRgn(hdc, NULL);
|
|
|
|
// Initialize GDI+.
|
|
GdiplusStartupInput gdiplusStartupInput;
|
|
ULONG_PTR gdiplusToken;
|
|
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
|
|
|
|
// When we have a widget, window.x/y are meaningless since our widget
|
|
// is always positioned correctly and we just draw into it at 0,0.
|
|
int x = instanceData->hasWidget ? 0 : instanceData->window.x;
|
|
int y = instanceData->hasWidget ? 0 : instanceData->window.y;
|
|
int width = instanceData->window.width;
|
|
int height = instanceData->window.height;
|
|
|
|
// Calculate the rectangle coordinates from the instanceData information
|
|
Rect rect(x, y, width, height);
|
|
|
|
// Create a layout rect for the text
|
|
RectF boundRect((float)x, (float)y, (float)width, (float)height);
|
|
boundRect.Inflate(-10.0, -10.0);
|
|
|
|
switch(instanceData->scriptableObject->drawMode) {
|
|
case DM_DEFAULT:
|
|
{
|
|
Graphics graphics(hdc);
|
|
|
|
// Fill in the background and border
|
|
Pen blackPen(Color(255, 0, 0, 0), 1);
|
|
SolidBrush grayBrush(Color(255, 192, 192, 192));
|
|
|
|
graphics.FillRectangle(&grayBrush, rect);
|
|
graphics.DrawRectangle(&blackPen, rect);
|
|
|
|
// Load a nice font
|
|
FontFamily fontFamily(L"Helvetica");
|
|
Font font(&fontFamily, 20, FontStyleBold, UnitPoint);
|
|
StringFormat stringFormat;
|
|
SolidBrush solidBrush(Color(255, 0, 0, 0));
|
|
|
|
// Center the text string
|
|
stringFormat.SetAlignment(StringAlignmentCenter);
|
|
stringFormat.SetLineAlignment(StringAlignmentCenter);
|
|
|
|
// Request anti-aliased text
|
|
graphics.SetTextRenderingHint(TextRenderingHintAntiAlias);
|
|
|
|
WCHAR wBuf[1024];
|
|
memset(&wBuf, 0, sizeof(wBuf));
|
|
MultiByteToWideChar(CP_ACP, 0, uaString, -1, wBuf, 1024);
|
|
|
|
// Draw the string
|
|
graphics.DrawString(wBuf, -1, &font, boundRect, &stringFormat, &solidBrush);
|
|
}
|
|
break;
|
|
|
|
case DM_SOLID_COLOR:
|
|
{
|
|
// Fill the plugin window with a solid color specified by the params
|
|
Graphics graphics(hdc);
|
|
SolidBrush brush(GetColorsFromRGBA(instanceData->scriptableObject->drawColor));
|
|
graphics.FillRectangle(&brush, rect.X, rect.Y, rect.Width, rect.Height);
|
|
}
|
|
break;
|
|
}
|
|
|
|
// Shutdown GDI+
|
|
GdiplusShutdown(gdiplusToken);
|
|
|
|
// Pop our hdc changes off the resource stack
|
|
RestoreDC(hdc, savedDCID);
|
|
|
|
if (instanceData->hasWidget)
|
|
::EndPaint((HWND)instanceData->window.window, &ps);
|
|
}
|
|
|
|
/* script interface */
|
|
|
|
int32_t
|
|
pluginGetEdge(InstanceData* instanceData, RectEdge edge)
|
|
{
|
|
if (!instanceData || !instanceData->hasWidget)
|
|
return NPTEST_INT32_ERROR;
|
|
|
|
HWND hWnd = GetAncestor((HWND)instanceData->window.window, GA_ROOT);
|
|
|
|
if (!hWnd)
|
|
return NPTEST_INT32_ERROR;
|
|
|
|
RECT rect = {0};
|
|
GetClientRect((HWND)instanceData->window.window, &rect);
|
|
MapWindowPoints((HWND)instanceData->window.window, hWnd, (LPPOINT)&rect, 2);
|
|
|
|
switch (edge) {
|
|
case EDGE_LEFT:
|
|
return rect.left;
|
|
case EDGE_TOP:
|
|
return rect.top;
|
|
case EDGE_RIGHT:
|
|
return rect.right;
|
|
case EDGE_BOTTOM:
|
|
return rect.bottom;
|
|
}
|
|
|
|
return NPTEST_INT32_ERROR;
|
|
}
|
|
|
|
int32_t
|
|
pluginGetClipRegionRectCount(InstanceData* instanceData)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
int32_t
|
|
pluginGetClipRegionRectEdge(InstanceData* instanceData,
|
|
int32_t rectIndex, RectEdge edge)
|
|
{
|
|
return pluginGetEdge(instanceData, edge);
|
|
}
|
|
|
|
/* windowless plugin events */
|
|
|
|
int16_t
|
|
pluginHandleEvent(InstanceData* instanceData, void* event)
|
|
{
|
|
NPEvent * pe = (NPEvent*) event;
|
|
|
|
if (pe == NULL || instanceData == NULL ||
|
|
instanceData->window.type != NPWindowTypeDrawable)
|
|
return 0;
|
|
|
|
switch((UINT)pe->event) {
|
|
case WM_PAINT:
|
|
pluginDraw(instanceData);
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* windowed plugin events */
|
|
|
|
LRESULT CALLBACK PluginWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
WNDPROC wndProc = (WNDPROC)GetProp(hWnd, "MozillaWndProc");
|
|
if (!wndProc)
|
|
return 0;
|
|
InstanceData* pInstance = (InstanceData*)GetProp(hWnd, "InstanceData");
|
|
if (!pInstance)
|
|
return 0;
|
|
|
|
if (uMsg == WM_PAINT) {
|
|
pluginDraw(pInstance);
|
|
return 0;
|
|
}
|
|
|
|
if (uMsg == WM_CLOSE) {
|
|
ClearSubclass((HWND)pInstance->window.window);
|
|
}
|
|
|
|
return CallWindowProc(wndProc, hWnd, uMsg, wParam, lParam);
|
|
}
|
|
|
|
void
|
|
ClearSubclass(HWND hWnd)
|
|
{
|
|
if (GetProp(hWnd, "MozillaWndProc")) {
|
|
::SetWindowLong(hWnd, GWL_WNDPROC, (long)GetProp(hWnd, "MozillaWndProc"));
|
|
RemoveProp(hWnd, "MozillaWndProc");
|
|
RemoveProp(hWnd, "InstanceData");
|
|
}
|
|
}
|
|
|
|
void
|
|
SetSubclass(HWND hWnd, InstanceData* instanceData)
|
|
{
|
|
// Subclass the plugin window so we can handle our own windows events.
|
|
SetProp(hWnd, "InstanceData", (HANDLE)instanceData);
|
|
WNDPROC origProc = (WNDPROC)::SetWindowLong(hWnd, GWL_WNDPROC, (long)PluginWndProc);
|
|
SetProp(hWnd, "MozillaWndProc", (HANDLE)origProc);
|
|
}
|
|
|
|
/* utils */
|
|
|
|
Color
|
|
GetColorsFromRGBA(PRUint32 rgba)
|
|
{
|
|
BYTE r, g, b, a;
|
|
b = (rgba & 0xFF);
|
|
g = ((rgba & 0xFF00) >> 8);
|
|
r = ((rgba & 0xFF0000) >> 16);
|
|
a = ((rgba & 0xFF000000) >> 24);
|
|
return Color(a, r, g, b);
|
|
}
|