michael@0: /* ***** BEGIN LICENSE BLOCK ***** michael@0: * michael@0: * Copyright (c) 2008, Mozilla Corporation michael@0: * All rights reserved. michael@0: * michael@0: * Redistribution and use in source and binary forms, with or without michael@0: * modification, are permitted provided that the following conditions are met: michael@0: * michael@0: * * Redistributions of source code must retain the above copyright notice, this michael@0: * list of conditions and the following disclaimer. michael@0: * * Redistributions in binary form must reproduce the above copyright notice, michael@0: * this list of conditions and the following disclaimer in the documentation michael@0: * and/or other materials provided with the distribution. michael@0: * * Neither the name of the Mozilla Corporation nor the names of its michael@0: * contributors may be used to endorse or promote products derived from this michael@0: * software without specific prior written permission. michael@0: * michael@0: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND michael@0: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED michael@0: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE michael@0: * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR michael@0: * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES michael@0: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; michael@0: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON michael@0: * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT michael@0: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS michael@0: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. michael@0: * michael@0: * Contributor(s): michael@0: * Josh Aas michael@0: * michael@0: * ***** END LICENSE BLOCK ***** */ michael@0: michael@0: #include "nptest_platform.h" michael@0: #include "nsAlgorithm.h" michael@0: #include michael@0: #include michael@0: michael@0: using namespace std; michael@0: michael@0: bool michael@0: pluginSupportsWindowMode() michael@0: { michael@0: return false; michael@0: } michael@0: michael@0: bool michael@0: pluginSupportsWindowlessMode() michael@0: { michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: pluginSupportsAsyncBitmapDrawing() michael@0: { michael@0: return false; michael@0: } michael@0: michael@0: NPError michael@0: pluginInstanceInit(InstanceData* instanceData) michael@0: { michael@0: NPP npp = instanceData->npp; michael@0: michael@0: NPBool supportsCoreGraphics = false; michael@0: if ((NPN_GetValue(npp, NPNVsupportsCoreGraphicsBool, &supportsCoreGraphics) == NPERR_NO_ERROR) && michael@0: supportsCoreGraphics) { michael@0: NPN_SetValue(npp, NPPVpluginDrawingModel, (void*)NPDrawingModelCoreGraphics); michael@0: } else { michael@0: printf("CoreGraphics drawing model not supported, can't create a plugin instance.\n"); michael@0: return NPERR_INCOMPATIBLE_VERSION_ERROR; michael@0: } michael@0: michael@0: NPBool supportsCocoaEvents = false; michael@0: if ((NPN_GetValue(npp, NPNVsupportsCocoaBool, &supportsCocoaEvents) == NPERR_NO_ERROR) && michael@0: supportsCocoaEvents) { michael@0: NPN_SetValue(npp, NPPVpluginEventModel, (void*)NPEventModelCocoa); michael@0: instanceData->eventModel = NPEventModelCocoa; michael@0: } else { michael@0: printf("Cocoa event model not supported, can't create a plugin instance.\n"); michael@0: return NPERR_INCOMPATIBLE_VERSION_ERROR; michael@0: } michael@0: michael@0: return NPERR_NO_ERROR; michael@0: } michael@0: michael@0: void michael@0: pluginInstanceShutdown(InstanceData* instanceData) michael@0: { michael@0: } michael@0: michael@0: static bool michael@0: RectEquals(const NPRect& r1, const NPRect& r2) michael@0: { michael@0: return r1.left == r2.left && r1.top == r2.top && michael@0: r1.right == r2.right && r1.bottom == r2.bottom; michael@0: } michael@0: michael@0: void michael@0: pluginDoSetWindow(InstanceData* instanceData, NPWindow* newWindow) michael@0: { michael@0: // Ugh. Due to a terrible Gecko bug, we have to ignore position changes michael@0: // when the clip rect doesn't change; the position can be wrong michael@0: // when set by a path other than nsObjectFrame::FixUpPluginWindow. michael@0: int32_t oldX = instanceData->window.x; michael@0: int32_t oldY = instanceData->window.y; michael@0: bool clipChanged = michael@0: !RectEquals(instanceData->window.clipRect, newWindow->clipRect); michael@0: instanceData->window = *newWindow; michael@0: if (!clipChanged) { michael@0: instanceData->window.x = oldX; michael@0: instanceData->window.y = oldY; michael@0: } michael@0: } michael@0: michael@0: void michael@0: pluginWidgetInit(InstanceData* instanceData, void* oldWindow) michael@0: { michael@0: // Should never be called since we don't support window mode michael@0: } michael@0: michael@0: static void michael@0: GetColorsFromRGBA(uint32_t rgba, float* r, float* g, float* b, float* a) michael@0: { michael@0: *b = (rgba & 0xFF) / 255.0; michael@0: *g = ((rgba & 0xFF00) >> 8) / 255.0; michael@0: *r = ((rgba & 0xFF0000) >> 16) / 255.0; michael@0: *a = ((rgba & 0xFF000000) >> 24) / 255.0; michael@0: } michael@0: michael@0: static void michael@0: pluginDraw(InstanceData* instanceData, NPCocoaEvent* event) michael@0: { michael@0: if (!instanceData) michael@0: return; michael@0: michael@0: notifyDidPaint(instanceData); michael@0: michael@0: NPP npp = instanceData->npp; michael@0: if (!npp) michael@0: return; michael@0: michael@0: const char* uaString = NPN_UserAgent(npp); michael@0: if (!uaString) michael@0: return; michael@0: michael@0: NPWindow window = instanceData->window; michael@0: michael@0: CGContextRef cgContext = event->data.draw.context; michael@0: michael@0: float windowWidth = window.width; michael@0: float windowHeight = window.height; michael@0: michael@0: switch(instanceData->scriptableObject->drawMode) { michael@0: case DM_DEFAULT: { michael@0: CFStringRef uaCFString = CFStringCreateWithCString(kCFAllocatorDefault, uaString, kCFStringEncodingASCII); michael@0: // save the cgcontext gstate michael@0: CGContextSaveGState(cgContext); michael@0: michael@0: // we get a flipped context michael@0: CGContextTranslateCTM(cgContext, 0.0, windowHeight); michael@0: CGContextScaleCTM(cgContext, 1.0, -1.0); michael@0: michael@0: // draw a gray background for the plugin michael@0: CGContextAddRect(cgContext, CGRectMake(0, 0, windowWidth, windowHeight)); michael@0: CGContextSetGrayFillColor(cgContext, 0.5, 1.0); michael@0: CGContextDrawPath(cgContext, kCGPathFill); michael@0: michael@0: // draw a black frame around the plugin michael@0: CGContextAddRect(cgContext, CGRectMake(0, 0, windowWidth, windowHeight)); michael@0: CGContextSetGrayStrokeColor(cgContext, 0.0, 1.0); michael@0: CGContextSetLineWidth(cgContext, 6.0); michael@0: CGContextStrokePath(cgContext); michael@0: michael@0: // draw the UA string using Core Text michael@0: CGContextSetTextMatrix(cgContext, CGAffineTransformIdentity); michael@0: michael@0: // Initialize a rectangular path. michael@0: CGMutablePathRef path = CGPathCreateMutable(); michael@0: CGRect bounds = CGRectMake(10.0, 10.0, std::max(0.0, windowWidth - 20.0), michael@0: std::max(0.0, windowHeight - 20.0)); michael@0: CGPathAddRect(path, NULL, bounds); michael@0: michael@0: // Initialize an attributed string. michael@0: CFMutableAttributedStringRef attrString = CFAttributedStringCreateMutable(kCFAllocatorDefault, 0); michael@0: CFAttributedStringReplaceString(attrString, CFRangeMake(0, 0), uaCFString); michael@0: michael@0: // Create a color and add it as an attribute to the string. michael@0: CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB(); michael@0: CGFloat components[] = { 0.0, 0.0, 0.0, 1.0 }; michael@0: CGColorRef red = CGColorCreate(rgbColorSpace, components); michael@0: CGColorSpaceRelease(rgbColorSpace); michael@0: CFAttributedStringSetAttribute(attrString, CFRangeMake(0, 50), kCTForegroundColorAttributeName, red); michael@0: michael@0: // Create the framesetter with the attributed string. michael@0: CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString(attrString); michael@0: CFRelease(attrString); michael@0: michael@0: // Create the frame and draw it into the graphics context michael@0: CTFrameRef frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, 0), path, NULL); michael@0: CFRelease(framesetter); michael@0: if (frame) { michael@0: CTFrameDraw(frame, cgContext); michael@0: CFRelease(frame); michael@0: } michael@0: michael@0: // restore the cgcontext gstate michael@0: CGContextRestoreGState(cgContext); michael@0: break; michael@0: } michael@0: case DM_SOLID_COLOR: { michael@0: // save the cgcontext gstate michael@0: CGContextSaveGState(cgContext); michael@0: michael@0: // we get a flipped context michael@0: CGContextTranslateCTM(cgContext, 0.0, windowHeight); michael@0: CGContextScaleCTM(cgContext, 1.0, -1.0); michael@0: michael@0: // draw a solid background for the plugin michael@0: CGContextAddRect(cgContext, CGRectMake(0, 0, windowWidth, windowHeight)); michael@0: michael@0: float r,g,b,a; michael@0: GetColorsFromRGBA(instanceData->scriptableObject->drawColor, &r, &g, &b, &a); michael@0: CGContextSetRGBFillColor(cgContext, r, g, b, a); michael@0: CGContextDrawPath(cgContext, kCGPathFill); michael@0: michael@0: // restore the cgcontext gstate michael@0: CGContextRestoreGState(cgContext); michael@0: break; michael@0: } michael@0: } michael@0: } michael@0: michael@0: int16_t michael@0: pluginHandleEvent(InstanceData* instanceData, void* event) michael@0: { michael@0: NPCocoaEvent* cocoaEvent = (NPCocoaEvent*)event; michael@0: if (!cocoaEvent) michael@0: return kNPEventNotHandled; michael@0: michael@0: switch (cocoaEvent->type) { michael@0: case NPCocoaEventDrawRect: michael@0: pluginDraw(instanceData, cocoaEvent); michael@0: break; michael@0: case NPCocoaEventMouseDown: michael@0: case NPCocoaEventMouseUp: michael@0: case NPCocoaEventMouseMoved: michael@0: instanceData->lastMouseX = (int32_t)cocoaEvent->data.mouse.pluginX; michael@0: instanceData->lastMouseY = (int32_t)cocoaEvent->data.mouse.pluginY; michael@0: if (cocoaEvent->type == NPCocoaEventMouseUp) { michael@0: instanceData->mouseUpEventCount++; michael@0: } michael@0: break; michael@0: case NPCocoaEventWindowFocusChanged: michael@0: instanceData->topLevelWindowActivationState = cocoaEvent->data.focus.hasFocus ? michael@0: ACTIVATION_STATE_ACTIVATED : ACTIVATION_STATE_DEACTIVATED; michael@0: instanceData->topLevelWindowActivationEventCount = instanceData->topLevelWindowActivationEventCount + 1; michael@0: break; michael@0: case NPCocoaEventFocusChanged: michael@0: instanceData->focusState = cocoaEvent->data.focus.hasFocus ? michael@0: ACTIVATION_STATE_ACTIVATED : ACTIVATION_STATE_DEACTIVATED; michael@0: instanceData->focusEventCount = instanceData->focusEventCount + 1; michael@0: break; michael@0: default: michael@0: return kNPEventNotHandled; michael@0: } michael@0: michael@0: return kNPEventHandled; michael@0: } michael@0: michael@0: int32_t pluginGetEdge(InstanceData* instanceData, RectEdge edge) michael@0: { michael@0: NPWindow* w = &instanceData->window; michael@0: switch (edge) { michael@0: case EDGE_LEFT: michael@0: return w->x; michael@0: case EDGE_TOP: michael@0: return w->y; michael@0: case EDGE_RIGHT: michael@0: return w->x + w->width; michael@0: case EDGE_BOTTOM: michael@0: return w->y + w->height; michael@0: } michael@0: return NPTEST_INT32_ERROR; michael@0: } michael@0: michael@0: int32_t pluginGetClipRegionRectCount(InstanceData* instanceData) michael@0: { michael@0: return 1; michael@0: } michael@0: michael@0: int32_t pluginGetClipRegionRectEdge(InstanceData* instanceData, michael@0: int32_t rectIndex, RectEdge edge) michael@0: { michael@0: if (rectIndex != 0) michael@0: return NPTEST_INT32_ERROR; michael@0: michael@0: // We have to add the Cocoa titlebar height here since the clip rect michael@0: // is being returned relative to that michael@0: static const int COCOA_TITLEBAR_HEIGHT = 22; michael@0: michael@0: NPWindow* w = &instanceData->window; michael@0: switch (edge) { michael@0: case EDGE_LEFT: michael@0: return w->clipRect.left; michael@0: case EDGE_TOP: michael@0: return w->clipRect.top + COCOA_TITLEBAR_HEIGHT; michael@0: case EDGE_RIGHT: michael@0: return w->clipRect.right; michael@0: case EDGE_BOTTOM: michael@0: return w->clipRect.bottom + COCOA_TITLEBAR_HEIGHT; michael@0: } michael@0: return NPTEST_INT32_ERROR; michael@0: } michael@0: michael@0: void pluginDoInternalConsistencyCheck(InstanceData* instanceData, string& error) michael@0: { michael@0: }