Bug 485121. Support getting native geometry data from the test plugin on Mac and GTK2/X11. r=joshmoz,karl

--HG--
rename : layout/generic/test/test_character_movement.html => layout/generic/test/test_movement_by_characters.html
rename : layout/generic/test/test_word_movement.html => layout/generic/test/test_movement_by_words.html
This commit is contained in:
Robert O'Callahan 2009-04-06 12:04:02 +12:00
parent 97ea54af4c
commit 3ff534b70e
12 changed files with 723 additions and 24 deletions

View File

@ -44,10 +44,18 @@ relativesrcdir = layout/generic/test
include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk
_TEST_FILES = test_bug288789.html \
# in the list below, we make sure that the tests that require focus
# run before test_plugin_clipping, which can steal focus for its window.
_TEST_FILES = \
bug344830_testembed.svg \
frame_selection_underline.xhtml \
frame_selection_underline-ref.xhtml \
frame_selection_underline.css \
plugin_clipping_helper.xhtml \
test_backspace_delete.xul \
test_bug288789.html \
test_bug323656.html \
test_bug344830.html \
bug344830_testembed.svg \
test_bug382429.html \
test_bug384527.html \
test_bug385751.html \
@ -67,13 +75,11 @@ _TEST_FILES = test_bug288789.html \
test_bug468167.html \
test_bug469613.xul \
test_bug470212.html \
test_character_movement.html \
test_word_movement.html \
test_backspace_delete.xul \
test_movement_by_characters.html \
test_movement_by_words.html \
test_plugin_clipping.xhtml \
test_plugin_position.xhtml \
test_selection_underline.html \
frame_selection_underline.xhtml \
frame_selection_underline-ref.xhtml \
frame_selection_underline.css \
$(NULL)
libs:: $(_TEST_FILES)

View File

@ -0,0 +1,223 @@
<?xml version="1.0"?>
<?xml-stylesheet href="/tests/SimpleTest/test.css" type="text/css"?>
<html xmlns="http://www.w3.org/1999/xhtml" title="Test Plugin Clipping">
<head>
<script type="application/javascript" src="/MochiKit/packed.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<style>
embed { width:200px; height:200px; display:block; }
iframe { border:none; }
</style>
</head>
<body>
<!-- Use a XUL element here so we can get its boxObject.screenX/Y -->
<hbox style="height:10px; position:absolute; left:0; top:0; z-index:-100;" id="h1"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<hbox style="width:100px;"></hbox><hbox id="h2"/>
</hbox>
<!-- Non-clipped plugin -->
<embed id="p1" type="application/x-test" wmode="window"
style="position:absolute; left:300px; top:0"></embed>
<!-- Clipped to the top and left by the viewport -->
<embed id="p2" type="application/x-test" wmode="window"
style="position:absolute; left:-100px; top:-100px;"></embed>
<!-- Clipped by a scrollable DIV -->
<div style="overflow:auto; width:200px; height:200px;
position:absolute; left:100px; top:0;">
<div style="position:relative; left:-100px; top:-100px;">
<embed id="p3" type="application/x-test" wmode="window"></embed>
</div>
</div>
<!-- Clipped by a scrollable DIV *and* to the viewport -->
<div style="overflow:auto; width:200px; height:200px; position:absolute; top:100px; left:-100px;">
<div style="position:relative; top:-100px;">
<embed id="p4" type="application/x-test" wmode="window"></embed>
</div>
</div>
<!-- Clipped by an iframe -->
<iframe id="f1" style="position:absolute; left:200px; top:200px; width:200px; height:200px;"></iframe>
<script class="testbody" type="application/javascript">
<![CDATA[
var windowFrameX, windowFrameY;
var f1 = document.getElementById("f1");
f1.src = "data:text/html," +
"<embed style='position:absolute; left:-100px; top:-100px; width:200px; height:200px;'" +
"id='p5' type='application/x-test' wmode='window'></embed>";
// Import test API
var is = window.opener.is;
var ok = window.opener.ok;
var todo = window.opener.todo;
var SimpleTest = window.opener.SimpleTest;
function dumpRegion(rects) {
var s = [];
for (var i = 0; i < rects.length; ++i) {
var r = rects[i];
s.push("{" + r.join(",") + "}");
}
return s.join(", ");
}
function generateSpan(coords) {
coords.sort(function(a,b) { return a - b; });
var result = [coords[0]];
for (var i = 1; i < coords.length; ++i) {
if (coords[i] != coords[i - 1]) {
result.push(coords[i]);
}
}
return result;
}
function containsRect(r1, r2) {
return r1[0] <= r2[0] && r1[2] >= r2[2] &&
r1[1] <= r2[1] && r1[3] >= r2[3];
}
function subtractRect(r1, r2, rlist) {
var spanX = generateSpan([r1[0], r1[2], r2[0], r2[2]]);
var spanY = generateSpan([r1[1], r1[3], r2[1], r2[3]]);
for (var i = 1; i < spanX.length; ++i) {
for (var j = 1; j < spanY.length; ++j) {
var subrect = [spanX[i - 1], spanY[j - 1], spanX[i], spanY[j]];
if (containsRect(r1, subrect) && !containsRect(r2, subrect)) {
rlist.push(subrect);
}
}
}
}
function regionContainsRect(rs, r) {
var rectList = [r];
for (var i = 0; i < rs.length; ++i) {
var newList = [];
for (var j = 0; j < rectList.length; ++j) {
subtractRect(rs[i], rectList[j], newList);
}
if (newList.length == 0)
return true;
rectList = newList;
}
return false;
}
function regionContains(r1s, r2s) {
for (var i = 0; i < r2s.length; ++i) {
if (!regionContainsRect(r1s, r2s[i]))
return false;
}
return true;
}
function equalRegions(r1s, r2s) {
return regionContains(r1s, r2s) && regionContains(r2s, r1s);
}
// Checks that a plugin's clip region equals the specified rectangle list.
// The rectangles are given relative to the plugin's top-left. They are in
// [left, top, right, bottom] format.
function checkClipRegionWithDoc(doc, offsetX, offsetY, id, rects) {
var p = doc.getElementById(id);
var pX = p.getEdge(0);
var pY = p.getEdge(1);
var pWidth = p.getEdge(2) - pX;
var pHeight = p.getEdge(3) - pY;
var bounds = p.getBoundingClientRect();
// First, check regular area
is(pX, windowFrameX + bounds.left + offsetX, id + " plugin X");
is(pY, windowFrameY + bounds.top + offsetY, id + " plugin Y");
is(pWidth, bounds.width, id + " plugin width");
is(pHeight, bounds.height, id + " plugin height");
// Now check clip region. 'rects' is relative to the plugin's top-left.
var clipRects = [];
var n = p.getClipRegionRectCount();
for (var i = 0; i < n; ++i) {
// Convert the clip rect to be relative to the plugin's top-left.
clipRects[i] = [
p.getClipRegionRectEdge(i, 0) - pX,
p.getClipRegionRectEdge(i, 1) - pY,
p.getClipRegionRectEdge(i, 2) - pX,
p.getClipRegionRectEdge(i, 3) - pY
];
}
ok(equalRegions(clipRects, rects), "Matching regions: expected " +
dumpRegion(rects) + ", got " + dumpRegion(clipRects));
}
function checkClipRegion(id, rects) {
checkClipRegionWithDoc(document, 0, 0, id, rects);
}
function checkClipRegionForFrame(fid, id, rects) {
var f = document.getElementById(fid);
var bounds = f.getBoundingClientRect();
checkClipRegionWithDoc(f.contentDocument, bounds.left, bounds.top, id, rects);
}
function runTests2() {
var p = document.getElementById("p1");
if (p.getClipRegionRectEdge(0, 0) == p.getClipRegionRectEdge(0, 2)) {
// plugin hasn't been updated yet. wait.
setTimeout(runTests2, 100);
return;
}
checkClipRegion("p1", [[0, 0, 200, 200]]);
checkClipRegion("p2", [[100, 100, 200, 200]]);
checkClipRegion("p3", [[100, 100, 200, 200]]);
checkClipRegion("p4", [[100, 100, 200, 200]]);
checkClipRegionForFrame("f1", "p5", [[100, 100, 200, 200]]);
SimpleTest.finish();
window.close();
}
function runTests() {
var h1 = document.getElementById("h1");
var h2 = document.getElementById("h2");
var hwidth = h2.boxObject.screenX - h1.boxObject.screenX;
if (hwidth != 100) {
// Maybe it's a DPI issue
todo(false, "Unexpected DPI?");
SimpleTest.finish();
window.close();
return;
}
if (!document.getElementById("p1").identifierToStringTest) {
todo(false, "Test plugin not available");
SimpleTest.finish();
window.close();
return;
}
if (navigator.platform.indexOf("Win") >= 0) {
todo(false, "Windows does not support windowed plugins (yet)");
SimpleTest.finish();
window.close();
return;
}
var bounds = h1.getBoundingClientRect();
windowFrameX = h1.boxObject.screenX - bounds.left - window.screenX;
windowFrameY = h1.boxObject.screenY - bounds.top - window.screenY;
runTests2();
}
window.addEventListener("load", runTests, false);
]]>
</script>
</body>
</html>

View File

@ -0,0 +1,24 @@
<?xml version="1.0"?>
<?xml-stylesheet href="/tests/SimpleTest/test.css" type="text/css"?>
<html xmlns="http://www.w3.org/1999/xhtml" title="Test Plugin Clipping">
<head>
<script type="application/javascript" src="/MochiKit/packed.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
</head>
<body>
<script class="testbody" type="application/javascript">
<![CDATA[
function runTests() {
window.open("plugin_clipping_helper.xhtml", "", "width=620,height=320");
}
addLoadEvent(runTests);
SimpleTest.waitForExplicitFinish();
]]>
</script>
</body>
</html>

View File

@ -0,0 +1,75 @@
<?xml version="1.0"?>
<?xml-stylesheet href="/tests/SimpleTest/test.css" type="text/css"?>
<html xmlns="http://www.w3.org/1999/xhtml" title="Test Plugin Positioning">
<head>
<script type="application/javascript" src="/MochiKit/packed.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
</head>
<body>
<!-- Use a XUL element here so we can get its boxObject.screenX/Y -->
<hbox style="height:10px; position:absolute; left:0; top:0; z-index:-100;" id="h1"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<hbox style="width:100px;"></hbox><hbox id="h2"/>
</hbox>
<embed id="p" type="application/x-test" width="200" height="200" wmode="window"></embed>
<script class="testbody" type="application/javascript">
<![CDATA[
var windowFrameX, windowFrameY;
function checkGeometry(id) {
var p = document.getElementById(id);
var pX = p.getEdge(0);
var pY = p.getEdge(1);
var pWidth = p.getEdge(2) - pX;
var pHeight = p.getEdge(3) - pY;
var bounds = p.getBoundingClientRect();
is(pX, windowFrameX + bounds.left, id + " plugin X");
is(pY, windowFrameY + bounds.top, id + " plugin Y");
is(pWidth, bounds.width, id + " plugin width");
is(pHeight, bounds.height, id + " plugin height");
}
function runTests() {
var h1 = document.getElementById("h1");
var h2 = document.getElementById("h2");
var hwidth = h2.boxObject.screenX - h1.boxObject.screenX;
if (hwidth != 100) {
// Maybe it's a DPI issue
todo(false, "Unexpected DPI?");
SimpleTest.finish();
return;
}
if (!document.getElementById("p").identifierToStringTest) {
todo(false, "Test plugin not available");
SimpleTest.finish();
return;
}
if (navigator.platform.indexOf("Win") >= 0) {
todo(false, "Windows does not support windowed plugins (yet)");
SimpleTest.finish();
return;
}
var bounds = h1.getBoundingClientRect();
windowFrameX = h1.boxObject.screenX - bounds.left - window.screenX;
windowFrameY = h1.boxObject.screenY - bounds.top - window.screenY;
checkGeometry("p");
SimpleTest.finish();
}
addLoadEvent(runTests);
SimpleTest.waitForExplicitFinish();
]]>
</script>
</body>
</html>

View File

@ -52,3 +52,46 @@ The test plugin object supports the following scriptable method:
* hasWidget()
Returns true if the plugin has an associated widget. This will return true if
wmode="window" was specified and the platform supports windowed plugins.
== Plugin geometry ==
The test plugin supports the following scriptable methods:
* getEdge(edge)
Returns the integer screen pixel coordinate of an edge of the plugin's
area:
-- edge=0: returns left edge coordinate
-- edge=1: returns top edge coordinate
-- edge=2: returns right edge coordinate
-- edge=3: returns bottom edge coordinate
The coordinates are relative to the top-left corner of the top-level window
containing the plugin, including the window decorations. Therefore:
-- On Mac, they're relative to the top-left corner of the toplevel Cocoa
window.
-- On Windows, they're relative to the top-left corner of the toplevel HWND's
non-client area.
-- On GTK2, they're relative to the top-left corner of the toplevel window's
window manager frame.
This means they can be added to Gecko's window.screenX/screenY (if DPI is set
to 96) to get screen coordinates.
On the platforms that support window-mode plugins (Windows/GTK2), this only
works for window-mode plugins. It will throw an error for windowless plugins.
* getClipRegionRectCount()
Returns the number of rectangles in the plugin's clip region.
For plugins with widgets, the clip region is computed as the intersection of the
clip region for the widget (if the platform does not support clip regions
on native widgets, this would just be the widget's rectangle) with the
clip regions of all ancestor widgets which would clip this widget.
On the platforms that support window-mode plugins (Windows/GTK2), this only
works for window-mode plugins. It will throw an error for windowless plugins.
On Mac, all plugins have a clip region containing just a single clip
rectangle only. So if you request wmode="window" but the plugin reports
!hasWidget, you can assume that complex clip regions are not supported.
* getClipRegionRectEdge(i, edge)
Returns the integer screen pixel coordinate of an edge of a rectangle from the
plugin's clip region. If i is less than zero or greater than or equal to
getClipRegionRectCount(), this will throw an error. The coordinates are
the same as for getEdge. See getClipRegionRectCount() above for
notes on platform plugin limitations.

View File

@ -44,6 +44,8 @@
#define PLUGIN_DESCRIPTION "Plug-in for testing purposes."
#define PLUGIN_VERSION "1.0.0.0"
#define ARRAY_LENGTH(a) (sizeof(a)/sizeof(a[0]))
//
// static data
//
@ -55,12 +57,6 @@ static NPClass sNPClass;
// identifiers
//
#define IDENTIFIER_TO_STRING_TEST_METHOD 0
#define QUERY_PRIVATE_MODE_STATE_METHOD 1
#define LAST_REPORTED_PRIVATE_MODE_STATE_METHOD 2
#define HAS_WIDGET_METHOD 3
#define NUM_METHOD_IDENTIFIERS 4
typedef bool (* ScriptableFunction)
(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
@ -68,19 +64,28 @@ static bool identifierToStringTest(NPObject* npobj, const NPVariant* args, uint3
static bool queryPrivateModeState(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
static bool lastReportedPrivateModeState(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
static bool hasWidget(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
static bool getEdge(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
static bool getClipRegionRectCount(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
static bool getClipRegionRectEdge(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
static NPIdentifier sPluginMethodIdentifiers[NUM_METHOD_IDENTIFIERS];
static const NPUTF8* sPluginMethodIdentifierNames[NUM_METHOD_IDENTIFIERS] = {
static const NPUTF8* sPluginMethodIdentifierNames[] = {
"identifierToStringTest",
"queryPrivateModeState",
"lastReportedPrivateModeState",
"hasWidget",
"getEdge",
"getClipRegionRectCount",
"getClipRegionRectEdge",
};
static const ScriptableFunction sPluginMethodFunctions[NUM_METHOD_IDENTIFIERS] = {
static NPIdentifier sPluginMethodIdentifiers[ARRAY_LENGTH(sPluginMethodIdentifierNames)];
static const ScriptableFunction sPluginMethodFunctions[ARRAY_LENGTH(sPluginMethodIdentifierNames)] = {
identifierToStringTest,
queryPrivateModeState,
lastReportedPrivateModeState,
hasWidget,
getEdge,
getClipRegionRectCount,
getClipRegionRectEdge,
};
static bool sIdentifiersInitialized = false;
@ -88,14 +93,16 @@ static bool sIdentifiersInitialized = false;
static void initializeIdentifiers()
{
if (!sIdentifiersInitialized) {
NPN_GetStringIdentifiers(sPluginMethodIdentifierNames, NUM_METHOD_IDENTIFIERS, sPluginMethodIdentifiers);
NPN_GetStringIdentifiers(sPluginMethodIdentifierNames,
ARRAY_LENGTH(sPluginMethodIdentifierNames), sPluginMethodIdentifiers);
sIdentifiersInitialized = true;
}
}
static void clearIdentifiers()
{
memset(sPluginMethodIdentifierNames, 0, NUM_METHOD_IDENTIFIERS * sizeof(NPIdentifier));
memset(sPluginMethodIdentifiers, 0,
ARRAY_LENGTH(sPluginMethodIdentifiers) * sizeof(NPIdentifier));
sIdentifiersInitialized = false;
}
@ -325,7 +332,7 @@ NPP_SetWindow(NPP instance, NPWindow* window)
{
InstanceData* instanceData = (InstanceData*)(instance->pdata);
void* oldWindow = instanceData->window.window;
instanceData->window = *window;
pluginDoSetWindow(instanceData, window);
if (instanceData->hasWidget && oldWindow != instanceData->window.window) {
pluginWidgetInit(instanceData, oldWindow);
}
@ -403,7 +410,7 @@ NPP_SetValue(NPP instance, NPNVariable variable, void* value)
{
if (variable == NPNVprivateModeBool) {
InstanceData* instanceData = (InstanceData*)(instance->pdata);
instanceData->lastReportedPrivateModeState = *static_cast<NPBool*>(value);
instanceData->lastReportedPrivateModeState = bool(*static_cast<NPBool*>(value));
return NPERR_NO_ERROR;
}
return NPERR_GENERIC_ERROR;
@ -531,7 +538,7 @@ scriptableInvalidate(NPObject* npobj)
bool
scriptableHasMethod(NPObject* npobj, NPIdentifier name)
{
for (int i = 0; i < NUM_METHOD_IDENTIFIERS; i++) {
for (int i = 0; i < int(ARRAY_LENGTH(sPluginMethodIdentifiers)); i++) {
if (name == sPluginMethodIdentifiers[i])
return true;
}
@ -541,7 +548,7 @@ scriptableHasMethod(NPObject* npobj, NPIdentifier name)
bool
scriptableInvoke(NPObject* npobj, NPIdentifier name, const NPVariant* args, uint32_t argCount, NPVariant* result)
{
for (int i = 0; i < NUM_METHOD_IDENTIFIERS; i++) {
for (int i = 0; i < int(ARRAY_LENGTH(sPluginMethodIdentifiers)); i++) {
if (name == sPluginMethodIdentifiers[i])
return sPluginMethodFunctions[i](npobj, args, argCount, result);
}
@ -602,6 +609,7 @@ identifierToStringTest(NPObject* npobj, const NPVariant* args, uint32_t argCount
NPIdentifier identifier = variantToIdentifier(args[0]);
if (!identifier)
return false;
NPUTF8* utf8String = NPN_UTF8FromIdentifier(identifier);
if (!utf8String)
return false;
@ -612,6 +620,9 @@ identifierToStringTest(NPObject* npobj, const NPVariant* args, uint32_t argCount
static bool
queryPrivateModeState(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
{
if (argCount != 0)
return false;
NPBool pms = false;
NPN_GetValue(static_cast<TestNPObject*>(npobj)->npp, NPNVprivateModeBool, &pms);
BOOLEAN_TO_NPVARIANT(pms, *result);
@ -621,6 +632,9 @@ queryPrivateModeState(NPObject* npobj, const NPVariant* args, uint32_t argCount,
static bool
lastReportedPrivateModeState(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
{
if (argCount != 0)
return false;
InstanceData* id = static_cast<InstanceData*>(static_cast<TestNPObject*>(npobj)->npp->pdata);
BOOLEAN_TO_NPVARIANT(id->lastReportedPrivateModeState, *result);
return true;
@ -629,7 +643,67 @@ lastReportedPrivateModeState(NPObject* npobj, const NPVariant* args, uint32_t ar
static bool
hasWidget(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
{
if (argCount != 0)
return false;
InstanceData* id = static_cast<InstanceData*>(static_cast<TestNPObject*>(npobj)->npp->pdata);
BOOLEAN_TO_NPVARIANT(id->hasWidget, *result);
return true;
}
static bool
getEdge(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
{
if (argCount != 1)
return false;
if (!NPVARIANT_IS_INT32(args[0]))
return false;
int32_t edge = NPVARIANT_TO_INT32(args[0]);
if (edge < EDGE_LEFT || edge > EDGE_BOTTOM)
return false;
InstanceData* id = static_cast<InstanceData*>(static_cast<TestNPObject*>(npobj)->npp->pdata);
int32_t r = pluginGetEdge(id, RectEdge(edge));
if (r == NPTEST_INT32_ERROR)
return false;
INT32_TO_NPVARIANT(r, *result);
return true;
}
static bool
getClipRegionRectCount(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
{
if (argCount != 0)
return false;
InstanceData* id = static_cast<InstanceData*>(static_cast<TestNPObject*>(npobj)->npp->pdata);
int32_t r = pluginGetClipRegionRectCount(id);
if (r == NPTEST_INT32_ERROR)
return false;
INT32_TO_NPVARIANT(r, *result);
return true;
}
static bool
getClipRegionRectEdge(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result)
{
if (argCount != 2)
return false;
if (!NPVARIANT_IS_INT32(args[0]))
return false;
int32_t rectIndex = NPVARIANT_TO_INT32(args[0]);
if (rectIndex < 0)
return false;
if (!NPVARIANT_IS_INT32(args[1]))
return false;
int32_t edge = NPVARIANT_TO_INT32(args[1]);
if (edge < EDGE_LEFT || edge > EDGE_BOTTOM)
return false;
InstanceData* id = static_cast<InstanceData*>(static_cast<TestNPObject*>(npobj)->npp->pdata);
int32_t r = pluginGetClipRegionRectEdge(id, rectIndex, RectEdge(edge));
if (r == NPTEST_INT32_ERROR)
return false;
INT32_TO_NPVARIANT(r, *result);
return true;
}

View File

@ -40,6 +40,14 @@
#endif
#include <gtk/gtk.h>
/**
* XXX In various places in this file we use GDK APIs to inspect the
* window ancestors of the plugin. These APIs will not work properly if
* this plugin is used in a browser that does not use GDK for all its
* widgets. They would also fail for out-of-process plugins. These should
* be fixed to use raw X APIs instead.
*/
bool
pluginSupportsWindowMode()
{
@ -124,6 +132,8 @@ pluginDrawWindow(InstanceData* instanceData, GdkDrawable* gdkWindow)
return;
GdkGC* gdkContext = gdk_gc_new(gdkWindow);
if (!gdkContext)
return;
// draw a grey background for the plugin frame
GdkColor grey;
@ -159,6 +169,12 @@ ExposeWidget(GtkWidget* widget, GdkEventExpose* event,
return TRUE;
}
void
pluginDoSetWindow(InstanceData* instanceData, NPWindow* newWindow)
{
instanceData->window = *newWindow;
}
void
pluginWidgetInit(InstanceData* instanceData, void* oldWindow)
{
@ -208,3 +224,105 @@ pluginHandleEvent(InstanceData* instanceData, void* event)
#endif
return 0;
}
int32_t pluginGetEdge(InstanceData* instanceData, RectEdge edge)
{
if (!instanceData->hasWidget)
return NPTEST_INT32_ERROR;
GtkWidget* plug = static_cast<GtkWidget*>(instanceData->platformData);
if (!plug)
return NPTEST_INT32_ERROR;
GdkWindow* plugWnd = plug->window;
if (!plugWnd)
return NPTEST_INT32_ERROR;
// XXX This only works because Gecko uses GdkWindows everywhere!
GdkWindow* toplevelWnd = gdk_window_get_toplevel(plugWnd);
if (!toplevelWnd)
return NPTEST_INT32_ERROR;
gint plugScreenX, plugScreenY;
gdk_window_get_origin(plugWnd, &plugScreenX, &plugScreenY);
gint toplevelFrameX, toplevelFrameY;
gdk_window_get_root_origin(toplevelWnd, &toplevelFrameX, &toplevelFrameY);
gint width, height;
gdk_drawable_get_size(GDK_DRAWABLE(plugWnd), &width, &height);
switch (edge) {
case EDGE_LEFT:
return plugScreenX - toplevelFrameX;
case EDGE_TOP:
return plugScreenY - toplevelFrameY;
case EDGE_RIGHT:
return plugScreenX + width - toplevelFrameX;
case EDGE_BOTTOM:
return plugScreenY + height - toplevelFrameY;
}
return NPTEST_INT32_ERROR;
}
int32_t pluginGetClipRegionRectCount(InstanceData* instanceData)
{
if (!instanceData->hasWidget)
return NPTEST_INT32_ERROR;
// XXX later we'll want to support XShape and be able to return a
// complex region here
return 1;
}
int32_t pluginGetClipRegionRectEdge(InstanceData* instanceData,
int32_t rectIndex, RectEdge edge)
{
if (!instanceData->hasWidget)
return NPTEST_INT32_ERROR;
GtkWidget* plug = static_cast<GtkWidget*>(instanceData->platformData);
if (!plug)
return NPTEST_INT32_ERROR;
GdkWindow* plugWnd = plug->window;
if (!plugWnd)
return NPTEST_INT32_ERROR;
// XXX This only works because Gecko uses GdkWindows everywhere!
GdkWindow* toplevelWnd = gdk_window_get_toplevel(plugWnd);
if (!toplevelWnd)
return NPTEST_INT32_ERROR;
gint width, height;
gdk_drawable_get_size(GDK_DRAWABLE(plugWnd), &width, &height);
GdkRectangle rect = { 0, 0, width, height };
GdkWindow* wnd = plugWnd;
while (wnd != toplevelWnd) {
gint x, y;
gdk_window_get_position(wnd, &x, &y);
rect.x += x;
rect.y += y;
// XXX This only works because Gecko uses GdkWindows everywhere!
GdkWindow* parent = gdk_window_get_parent(wnd);
gint parentWidth, parentHeight;
gdk_drawable_get_size(GDK_DRAWABLE(parent), &parentWidth, &parentHeight);
GdkRectangle parentRect = { 0, 0, parentWidth, parentHeight };
gdk_rectangle_intersect(&rect, &parentRect, &rect);
wnd = parent;
}
gint toplevelFrameX, toplevelFrameY;
gdk_window_get_root_origin(toplevelWnd, &toplevelFrameX, &toplevelFrameY);
gint toplevelOriginX, toplevelOriginY;
gdk_window_get_origin(toplevelWnd, &toplevelOriginX, &toplevelOriginY);
rect.x += toplevelOriginX - toplevelFrameX;
rect.y += toplevelOriginY - toplevelFrameY;
switch (edge) {
case EDGE_LEFT:
return rect.x;
case EDGE_TOP:
return rect.y;
case EDGE_RIGHT:
return rect.x + rect.width;
case EDGE_BOTTOM:
return rect.y + rect.height;
}
return NPTEST_INT32_ERROR;
}

View File

@ -66,6 +66,30 @@ pluginInstanceShutdown(InstanceData* instanceData)
{
}
static bool
RectEquals(const NPRect& r1, const NPRect& r2)
{
return r1.left == r2.left && r1.top == r2.top &&
r1.right == r2.right && r1.bottom == r2.bottom;
}
void
pluginDoSetWindow(InstanceData* instanceData, NPWindow* newWindow)
{
// Ugh. Due to a terrible Gecko bug, we have to ignore position changes
// when the clip rect doesn't change; the position can be wrong
// when set by a path other than nsObjectFrame::FixUpPluginWindow.
int32_t oldX = instanceData->window.x;
int32_t oldY = instanceData->window.y;
bool clipChanged =
!RectEquals(instanceData->window.clipRect, newWindow->clipRect);
instanceData->window = *newWindow;
if (!clipChanged) {
instanceData->window.x = oldX;
instanceData->window.y = oldY;
}
}
void
pluginWidgetInit(InstanceData* instanceData, void* oldWindow)
{
@ -219,3 +243,48 @@ pluginHandleEvent(InstanceData* instanceData, void* event)
}
return 0;
}
int32_t pluginGetEdge(InstanceData* instanceData, RectEdge edge)
{
NPWindow* w = &instanceData->window;
switch (edge) {
case EDGE_LEFT:
return w->x;
case EDGE_TOP:
return w->y;
case EDGE_RIGHT:
return w->x + w->width;
case EDGE_BOTTOM:
return w->y + w->height;
}
return NPTEST_INT32_ERROR;
}
int32_t pluginGetClipRegionRectCount(InstanceData* instanceData)
{
return 1;
}
int32_t pluginGetClipRegionRectEdge(InstanceData* instanceData,
int32_t rectIndex, RectEdge edge)
{
if (rectIndex != 0)
return NPTEST_INT32_ERROR;
// We have to add the Cocoa titlebar height here since the clip rect
// is being returned relative to that
static const int COCOA_TITLEBAR_HEIGHT = 22;
NPWindow* w = &instanceData->window;
switch (edge) {
case EDGE_LEFT:
return w->clipRect.left;
case EDGE_TOP:
return w->clipRect.top + COCOA_TITLEBAR_HEIGHT;
case EDGE_RIGHT:
return w->clipRect.right;
case EDGE_BOTTOM:
return w->clipRect.bottom + COCOA_TITLEBAR_HEIGHT;
}
return NPTEST_INT32_ERROR;
}

View File

@ -59,6 +59,11 @@ NPError pluginInstanceInit(InstanceData* instanceData);
*/
void pluginInstanceShutdown(InstanceData* instanceData);
/**
* Set the instanceData's window to newWindow.
*/
void pluginDoSetWindow(InstanceData* instanceData, NPWindow* newWindow);
/**
* Initialize the window for a windowed plugin. oldWindow is the old
* native window value. This will never be called for windowless plugins.
@ -71,4 +76,41 @@ void pluginWidgetInit(InstanceData* instanceData, void* oldWindow);
*/
int16_t pluginHandleEvent(InstanceData* instanceData, void* event);
enum RectEdge {
EDGE_LEFT = 0,
EDGE_TOP = 1,
EDGE_RIGHT = 2,
EDGE_BOTTOM = 3
};
enum {
NPTEST_INT32_ERROR = 0x7FFFFFFF
};
/**
* Return the coordinate of the given edge of the plugin's area, relative
* to the top-left corner of the toplevel window containing the plugin,
* including window decorations. Only works for window-mode plugins
* and Mac plugins.
* Returns NPTEST_ERROR on error.
*/
int32_t pluginGetEdge(InstanceData* instanceData, RectEdge edge);
/**
* Return the number of rectangles in the plugin's clip region. Only
* works for window-mode plugins and Mac plugins.
* Returns NPTEST_ERROR on error.
*/
int32_t pluginGetClipRegionRectCount(InstanceData* instanceData);
/**
* Return the coordinate of the given edge of a rectangle in the plugin's
* clip region, relative to the top-left corner of the toplevel window
* containing the plugin, including window decorations. Only works for
* window-mode plugins and Mac plugins.
* Returns NPTEST_ERROR on error.
*/
int32_t pluginGetClipRegionRectEdge(InstanceData* instanceData,
int32_t rectIndex, RectEdge edge);
#endif // nptest_platform_h_

View File

@ -64,6 +64,12 @@ pluginInstanceShutdown(InstanceData* instanceData)
{
}
void
pluginDoSetWindow(InstanceData* instanceData, NPWindow* newWindow)
{
instanceData->window = *newWindow;
}
void
pluginWidgetInit(InstanceData* instanceData, void* oldWindow)
{
@ -186,3 +192,22 @@ pluginHandleEvent(InstanceData* instanceData, void* event)
return 0;
}
int32_t pluginGetEdge(InstanceData* instanceData, RectEdge edge)
{
// XXX nothing here yet since we don't support windowed plugins
return NPTEST_INT32_ERROR;
}
int32_t pluginGetClipRegionRectCount(InstanceData* instanceData)
{
// XXX nothing here yet since we don't support windowed plugins
return NPTEST_INT32_ERROR;
}
int32_t pluginGetClipRegionRectEdge(InstanceData* instanceData,
int32_t rectIndex, RectEdge edge)
{
// XXX nothing here yet since we don't support windowed plugins
return NPTEST_INT32_ERROR;
}