1/* ***** BEGIN LICENSE BLOCK ***** 2 * 3 * Copyright (c) 2008, Mozilla Corporation 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * * Redistributions of source code must retain the above copyright notice, this 10 * list of conditions and the following disclaimer. 11 * * Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * * Neither the name of the Mozilla Corporation nor the names of its 15 * contributors may be used to endorse or promote products derived from this 16 * software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 22 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 25 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 * 29 * Contributor(s): 30 * Josh Aas <josh@mozilla.com> 31 * 32 * ***** END LICENSE BLOCK ***** */ 33 34#include "nptest_platform.h" 35#include "nsAlgorithm.h" 36#include <CoreServices/CoreServices.h> 37#include <algorithm> 38 39using namespace std; 40 41bool 42pluginSupportsWindowMode() 43{ 44 return false; 45} 46 47bool 48pluginSupportsWindowlessMode() 49{ 50 return true; 51} 52 53NPError 54pluginInstanceInit(InstanceData* instanceData) 55{ 56 NPP npp = instanceData->npp; 57 58 NPBool supportsCoreGraphics = false; 59 if ((NPN_GetValue(npp, NPNVsupportsCoreGraphicsBool, &supportsCoreGraphics) == NPERR_NO_ERROR) && 60 supportsCoreGraphics) { 61 NPN_SetValue(npp, NPPVpluginDrawingModel, (void*)NPDrawingModelCoreGraphics); 62 } else { 63 printf("CoreGraphics drawing model not supported, can't create a plugin instance.\n"); 64 return NPERR_INCOMPATIBLE_VERSION_ERROR; 65 } 66 67 NPBool supportsCocoaEvents = false; 68 if ((NPN_GetValue(npp, NPNVsupportsCocoaBool, &supportsCocoaEvents) == NPERR_NO_ERROR) && 69 supportsCocoaEvents) { 70 NPN_SetValue(npp, NPPVpluginEventModel, (void*)NPEventModelCocoa); 71 instanceData->eventModel = NPEventModelCocoa; 72 } else { 73 printf("Cocoa event model not supported, can't create a plugin instance.\n"); 74 return NPERR_INCOMPATIBLE_VERSION_ERROR; 75 } 76 77 return NPERR_NO_ERROR; 78} 79 80void 81pluginInstanceShutdown(InstanceData* instanceData) 82{ 83} 84 85static bool 86RectEquals(const NPRect& r1, const NPRect& r2) 87{ 88 return r1.left == r2.left && r1.top == r2.top && 89 r1.right == r2.right && r1.bottom == r2.bottom; 90} 91 92void 93pluginDoSetWindow(InstanceData* instanceData, NPWindow* newWindow) 94{ 95 // Ugh. Due to a terrible Gecko bug, we have to ignore position changes 96 // when the clip rect doesn't change; the position can be wrong 97 // when set by a path other than nsPluginFrame::FixUpPluginWindow. 98 int32_t oldX = instanceData->window.x; 99 int32_t oldY = instanceData->window.y; 100 bool clipChanged = 101 !RectEquals(instanceData->window.clipRect, newWindow->clipRect); 102 instanceData->window = *newWindow; 103 if (!clipChanged) { 104 instanceData->window.x = oldX; 105 instanceData->window.y = oldY; 106 } 107} 108 109void 110pluginWidgetInit(InstanceData* instanceData, void* oldWindow) 111{ 112 // Should never be called since we don't support window mode 113} 114 115static void 116GetColorsFromRGBA(uint32_t rgba, float* r, float* g, float* b, float* a) 117{ 118 *b = (rgba & 0xFF) / 255.0; 119 *g = ((rgba & 0xFF00) >> 8) / 255.0; 120 *r = ((rgba & 0xFF0000) >> 16) / 255.0; 121 *a = ((rgba & 0xFF000000) >> 24) / 255.0; 122} 123 124static void 125pluginDraw(InstanceData* instanceData, NPCocoaEvent* event) 126{ 127 if (!instanceData) 128 return; 129 130 notifyDidPaint(instanceData); 131 132 NPP npp = instanceData->npp; 133 if (!npp) 134 return; 135 136 const char* uaString = NPN_UserAgent(npp); 137 if (!uaString) 138 return; 139 140 NPWindow window = instanceData->window; 141 142 CGContextRef cgContext = event->data.draw.context; 143 144 float windowWidth = window.width; 145 float windowHeight = window.height; 146 147 switch(instanceData->scriptableObject->drawMode) { 148 case DM_DEFAULT: { 149 CFStringRef uaCFString = CFStringCreateWithCString(kCFAllocatorDefault, uaString, kCFStringEncodingASCII); 150 // save the cgcontext gstate 151 CGContextSaveGState(cgContext); 152 153 // we get a flipped context 154 CGContextTranslateCTM(cgContext, 0.0, windowHeight); 155 CGContextScaleCTM(cgContext, 1.0, -1.0); 156 157 // draw a gray background for the plugin 158 CGContextAddRect(cgContext, CGRectMake(0, 0, windowWidth, windowHeight)); 159 CGContextSetGrayFillColor(cgContext, 0.5, 1.0); 160 CGContextDrawPath(cgContext, kCGPathFill); 161 162 // draw a black frame around the plugin 163 CGContextAddRect(cgContext, CGRectMake(0, 0, windowWidth, windowHeight)); 164 CGContextSetGrayStrokeColor(cgContext, 0.0, 1.0); 165 CGContextSetLineWidth(cgContext, 6.0); 166 CGContextStrokePath(cgContext); 167 168 // draw the UA string using Core Text 169 CGContextSetTextMatrix(cgContext, CGAffineTransformIdentity); 170 171 // Initialize a rectangular path. 172 CGMutablePathRef path = CGPathCreateMutable(); 173 CGRect bounds = CGRectMake(10.0, 10.0, std::max(0.0, windowWidth - 20.0), 174 std::max(0.0, windowHeight - 20.0)); 175 CGPathAddRect(path, NULL, bounds); 176 177 // Initialize an attributed string. 178 CFMutableAttributedStringRef attrString = CFAttributedStringCreateMutable(kCFAllocatorDefault, 0); 179 CFAttributedStringReplaceString(attrString, CFRangeMake(0, 0), uaCFString); 180 181 // Create a color and add it as an attribute to the string. 182 CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB(); 183 CGFloat components[] = { 0.0, 0.0, 0.0, 1.0 }; 184 CGColorRef red = CGColorCreate(rgbColorSpace, components); 185 CGColorSpaceRelease(rgbColorSpace); 186 CFAttributedStringSetAttribute(attrString, CFRangeMake(0, 50), kCTForegroundColorAttributeName, red); 187 188 // Create the framesetter with the attributed string. 189 CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString(attrString); 190 CFRelease(attrString); 191 192 // Create the frame and draw it into the graphics context 193 CTFrameRef frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, 0), path, NULL); 194 CFRelease(framesetter); 195 if (frame) { 196 CTFrameDraw(frame, cgContext); 197 CFRelease(frame); 198 } 199 200 // restore the cgcontext gstate 201 CGContextRestoreGState(cgContext); 202 break; 203 } 204 case DM_SOLID_COLOR: { 205 // save the cgcontext gstate 206 CGContextSaveGState(cgContext); 207 208 // we get a flipped context 209 CGContextTranslateCTM(cgContext, 0.0, windowHeight); 210 CGContextScaleCTM(cgContext, 1.0, -1.0); 211 212 // draw a solid background for the plugin 213 CGContextAddRect(cgContext, CGRectMake(0, 0, windowWidth, windowHeight)); 214 215 float r,g,b,a; 216 GetColorsFromRGBA(instanceData->scriptableObject->drawColor, &r, &g, &b, &a); 217 CGContextSetRGBFillColor(cgContext, r, g, b, a); 218 CGContextDrawPath(cgContext, kCGPathFill); 219 220 // restore the cgcontext gstate 221 CGContextRestoreGState(cgContext); 222 break; 223 } 224 } 225} 226 227int16_t 228pluginHandleEvent(InstanceData* instanceData, void* event) 229{ 230 NPCocoaEvent* cocoaEvent = (NPCocoaEvent*)event; 231 if (!cocoaEvent) 232 return kNPEventNotHandled; 233 234 switch (cocoaEvent->type) { 235 case NPCocoaEventDrawRect: 236 pluginDraw(instanceData, cocoaEvent); 237 break; 238 case NPCocoaEventMouseDown: 239 case NPCocoaEventMouseUp: 240 case NPCocoaEventMouseMoved: 241 case NPCocoaEventMouseDragged: 242 instanceData->lastMouseX = (int32_t)cocoaEvent->data.mouse.pluginX; 243 instanceData->lastMouseY = (int32_t)cocoaEvent->data.mouse.pluginY; 244 if (cocoaEvent->type == NPCocoaEventMouseUp) { 245 instanceData->mouseUpEventCount++; 246 } 247 break; 248 case NPCocoaEventWindowFocusChanged: 249 instanceData->topLevelWindowActivationState = cocoaEvent->data.focus.hasFocus ? 250 ACTIVATION_STATE_ACTIVATED : ACTIVATION_STATE_DEACTIVATED; 251 instanceData->topLevelWindowActivationEventCount = instanceData->topLevelWindowActivationEventCount + 1; 252 break; 253 case NPCocoaEventFocusChanged: 254 instanceData->focusState = cocoaEvent->data.focus.hasFocus ? 255 ACTIVATION_STATE_ACTIVATED : ACTIVATION_STATE_DEACTIVATED; 256 instanceData->focusEventCount = instanceData->focusEventCount + 1; 257 break; 258 default: 259 return kNPEventNotHandled; 260 } 261 262 return kNPEventHandled; 263} 264 265int32_t pluginGetEdge(InstanceData* instanceData, RectEdge edge) 266{ 267 NPWindow* w = &instanceData->window; 268 switch (edge) { 269 case EDGE_LEFT: 270 return w->x; 271 case EDGE_TOP: 272 return w->y; 273 case EDGE_RIGHT: 274 return w->x + w->width; 275 case EDGE_BOTTOM: 276 return w->y + w->height; 277 } 278 MOZ_CRASH("Unexpected RectEdge?!"); 279} 280 281int32_t pluginGetClipRegionRectCount(InstanceData* instanceData) 282{ 283 return 1; 284} 285 286int32_t pluginGetClipRegionRectEdge(InstanceData* instanceData, 287 int32_t rectIndex, RectEdge edge) 288{ 289 if (rectIndex != 0) 290 return NPTEST_INT32_ERROR; 291 292 // We have to add the Cocoa titlebar height here since the clip rect 293 // is being returned relative to that 294 static const int COCOA_TITLEBAR_HEIGHT = 22; 295 296 NPWindow* w = &instanceData->window; 297 switch (edge) { 298 case EDGE_LEFT: 299 return w->clipRect.left; 300 case EDGE_TOP: 301 return w->clipRect.top + COCOA_TITLEBAR_HEIGHT; 302 case EDGE_RIGHT: 303 return w->clipRect.right; 304 case EDGE_BOTTOM: 305 return w->clipRect.bottom + COCOA_TITLEBAR_HEIGHT; 306 } 307 MOZ_CRASH("Unexpected RectEdge?!"); 308} 309 310void pluginDoInternalConsistencyCheck(InstanceData* instanceData, string& error) 311{ 312} 313