📄 webnetscapepluginview.mm
字号:
qdPortState->oldVisibleRegion = NewRgn(); GetPortVisibleRegion(port, qdPortState->oldVisibleRegion); RgnHandle clipRegion = NewRgn(); qdPortState->clipRegion = clipRegion; CGContextRef currentContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort]; if (currentContext && WKCGContextIsBitmapContext(currentContext)) { // We use WKCGContextIsBitmapContext here, because if we just called CGBitmapContextGetData // on any context, we'd log to the console every time. But even if WKCGContextIsBitmapContext // returns true, it still might not be a context we need to create a GWorld for; for example // transparency layers will return true, but return 0 for CGBitmapContextGetData. void* offscreenData = CGBitmapContextGetData(currentContext); if (offscreenData) { // If the current context is an offscreen bitmap, then create a GWorld for it. ::Rect offscreenBounds; offscreenBounds.top = 0; offscreenBounds.left = 0; offscreenBounds.right = CGBitmapContextGetWidth(currentContext); offscreenBounds.bottom = CGBitmapContextGetHeight(currentContext); GWorldPtr newOffscreenGWorld; QDErr err = NewGWorldFromPtr(&newOffscreenGWorld, getQDPixelFormatForBitmapContext(currentContext), &offscreenBounds, 0, 0, 0, static_cast<char*>(offscreenData), CGBitmapContextGetBytesPerRow(currentContext)); ASSERT(newOffscreenGWorld && !err); if (!err) { if (offscreenGWorld) DisposeGWorld(offscreenGWorld); offscreenGWorld = newOffscreenGWorld; SetGWorld(offscreenGWorld, NULL); port = offscreenGWorld; nPort.qdPort.port = port; boundsInWindow = [self bounds]; // Generate a QD origin based on the current affine transform for currentContext. CGAffineTransform offscreenMatrix = CGContextGetCTM(currentContext); CGPoint origin = {0,0}; CGPoint axisFlip = {1,1}; origin = CGPointApplyAffineTransform(origin, offscreenMatrix); axisFlip = CGPointApplyAffineTransform(axisFlip, offscreenMatrix); // Quartz bitmaps have origins at the bottom left, but the axes may be inverted, so handle that. origin.x = offscreenBounds.left - origin.x * (axisFlip.x - origin.x); origin.y = offscreenBounds.bottom + origin.y * (axisFlip.y - origin.y); nPort.qdPort.portx = static_cast<int32>(-boundsInWindow.origin.x + origin.x); nPort.qdPort.porty = static_cast<int32>(-boundsInWindow.origin.y - origin.y); window.x = 0; window.y = 0; window.window = &nPort; // Use the clip bounds from the context instead of the bounds we created // from the window above. getNPRect(CGRectOffset(CGContextGetClipBoundingBox(currentContext), -origin.x, origin.y), window.clipRect); } } } MacSetRectRgn(clipRegion, window.clipRect.left + nPort.qdPort.portx, window.clipRect.top + nPort.qdPort.porty, window.clipRect.right + nPort.qdPort.portx, window.clipRect.bottom + nPort.qdPort.porty); // Clip to the dirty region if drawing to a window. When drawing to another bitmap context, do not clip. if ([NSGraphicsContext currentContext] == [[self currentWindow] graphicsContext]) { // Clip to dirty region so plug-in does not draw over already-drawn regions of the window that are // not going to be redrawn this update. This forces plug-ins to play nice with z-index ordering. if (forUpdate) { RgnHandle viewClipRegion = NewRgn(); // Get list of dirty rects from the opaque ancestor -- WebKit does some tricks with invalidation and // display to enable z-ordering for NSViews; a side-effect of this is that only the WebHTMLView // knows about the true set of dirty rects. NSView *opaqueAncestor = [self opaqueAncestor]; const NSRect *dirtyRects; NSInteger dirtyRectCount, dirtyRectIndex; [opaqueAncestor getRectsBeingDrawn:&dirtyRects count:&dirtyRectCount]; for (dirtyRectIndex = 0; dirtyRectIndex < dirtyRectCount; dirtyRectIndex++) { NSRect dirtyRect = [self convertRect:dirtyRects[dirtyRectIndex] fromView:opaqueAncestor]; if (!NSEqualSizes(dirtyRect.size, NSZeroSize)) { // Create a region for this dirty rect RgnHandle dirtyRectRegion = NewRgn(); SetRectRgn(dirtyRectRegion, static_cast<short>(NSMinX(dirtyRect)), static_cast<short>(NSMinY(dirtyRect)), static_cast<short>(NSMaxX(dirtyRect)), static_cast<short>(NSMaxY(dirtyRect))); // Union this dirty rect with the rest of the dirty rects UnionRgn(viewClipRegion, dirtyRectRegion, viewClipRegion); DisposeRgn(dirtyRectRegion); } } // Intersect the dirty region with the clip region, so that we only draw over dirty parts SectRgn(clipRegion, viewClipRegion, clipRegion); DisposeRgn(viewClipRegion); } } // Switch to the port and set it up. SetPort(port); PenNormal(); ForeColor(blackColor); BackColor(whiteColor); SetOrigin(nPort.qdPort.portx, nPort.qdPort.porty); SetPortClipRegion(nPort.qdPort.port, clipRegion); if (forUpdate) { // AppKit may have tried to help us by doing a BeginUpdate. // But the invalid region at that level didn't include AppKit's notion of what was not valid. // We reset the port's visible region to counteract what BeginUpdate did. SetPortVisibleRegion(nPort.qdPort.port, clipRegion); InvalWindowRgn(windowRef, clipRegion); } qdPortState->forUpdate = forUpdate; break; }#endif /* NP_NO_QUICKDRAW */ case NPDrawingModelCoreGraphics: { ASSERT([NSView focusView] == self); CGContextRef context = static_cast<CGContextRef>([[NSGraphicsContext currentContext] graphicsPort]); PortState_CG *cgPortState = (PortState_CG *)malloc(sizeof(PortState_CG)); portState = (PortState)cgPortState; cgPortState->context = context; // Update the plugin's window/context#ifdef NP_NO_CARBON nPort.cgPort.window = (NPNSWindow *)[self currentWindow];#else nPort.cgPort.window = _eventHandler->platformWindow([self currentWindow]);#endif /* NP_NO_CARBON */ nPort.cgPort.context = context; window.window = &nPort.cgPort; // Save current graphics context's state; will be restored by -restorePortState: CGContextSaveGState(context); // Clip to the dirty region if drawing to a window. When drawing to another bitmap context, do not clip. if ([NSGraphicsContext currentContext] == [[self currentWindow] graphicsContext]) { // Get list of dirty rects from the opaque ancestor -- WebKit does some tricks with invalidation and // display to enable z-ordering for NSViews; a side-effect of this is that only the WebHTMLView // knows about the true set of dirty rects. NSView *opaqueAncestor = [self opaqueAncestor]; const NSRect *dirtyRects; NSInteger count; [opaqueAncestor getRectsBeingDrawn:&dirtyRects count:&count]; Vector<CGRect, 16> convertedDirtyRects; convertedDirtyRects.resize(count); for (int i = 0; i < count; ++i) reinterpret_cast<NSRect&>(convertedDirtyRects[i]) = [self convertRect:dirtyRects[i] fromView:opaqueAncestor]; CGContextClipToRects(context, convertedDirtyRects.data(), count); } break; } case NPDrawingModelCoreAnimation: window.window = [self currentWindow]; // Just set the port state to a dummy value. portState = (PortState)1; break; default: ASSERT_NOT_REACHED(); portState = NULL; break; } return portState;}- (PortState)saveAndSetNewPortState{ return [self saveAndSetNewPortStateForUpdate:NO];}- (void)restorePortState:(PortState)portState{ ASSERT([self currentWindow]); ASSERT(portState); switch (drawingModel) {#ifndef NP_NO_QUICKDRAW case NPDrawingModelQuickDraw: { PortState_QD *qdPortState = (PortState_QD *)portState; WindowRef windowRef = (WindowRef)[[self currentWindow] windowRef]; CGrafPtr port = GetWindowPort(windowRef); SetPort(port); if (qdPortState->forUpdate) ValidWindowRgn(windowRef, qdPortState->clipRegion); SetOrigin(qdPortState->oldOrigin.h, qdPortState->oldOrigin.v); SetPortClipRegion(port, qdPortState->oldClipRegion); if (qdPortState->forUpdate) SetPortVisibleRegion(port, qdPortState->oldVisibleRegion); DisposeRgn(qdPortState->oldClipRegion); DisposeRgn(qdPortState->oldVisibleRegion); DisposeRgn(qdPortState->clipRegion); SetGWorld(qdPortState->oldPort, qdPortState->oldDevice); break; }#endif /* NP_NO_QUICKDRAW */ case NPDrawingModelCoreGraphics: ASSERT([NSView focusView] == self); ASSERT(((PortState_CG *)portState)->context == nPort.cgPort.context); CGContextRestoreGState(nPort.cgPort.context); break; case NPDrawingModelCoreAnimation: ASSERT(portState == (PortState)1); break; default: ASSERT_NOT_REACHED(); break; }}- (BOOL)sendEvent:(void*)event isDrawRect:(BOOL)eventIsDrawRect{ if (![self window]) return NO; ASSERT(event); if (!_isStarted) return NO; ASSERT([_pluginPackage.get() pluginFuncs]->event); // Make sure we don't call NPP_HandleEvent while we're inside NPP_SetWindow. // We probably don't want more general reentrancy protection; we are really // protecting only against this one case, which actually comes up when // you first install the SVG viewer plug-in. if (inSetWindow) return NO; Frame* frame = core([self webFrame]); if (!frame) return NO; Page* page = frame->page(); if (!page) return NO; // Can only send drawRect (updateEvt) to CoreGraphics plugins when actually drawing ASSERT((drawingModel != NPDrawingModelCoreGraphics) || !eventIsDrawRect || [NSView focusView] == self); PortState portState = NULL; if (isDrawingModelQuickDraw(drawingModel) || (drawingModel != NPDrawingModelCoreAnimation && eventIsDrawRect)) { // In CoreGraphics mode, the port state only needs to be saved/set when redrawing the plug-in view. // The plug-in is not allowed to draw at any other time. portState = [self saveAndSetNewPortStateForUpdate:eventIsDrawRect]; // We may have changed the window, so inform the plug-in. [self setWindowIfNecessary]; } #if !defined(NDEBUG) && !defined(NP_NO_QUICKDRAW) // Draw green to help debug. // If we see any green we know something's wrong. // Note that PaintRect() only works for QuickDraw plugins; otherwise the current QD port is undefined. if (isDrawingModelQuickDraw(drawingModel) && eventIsDrawRect) { ForeColor(greenColor); const ::Rect bigRect = { -10000, -10000, 10000, 10000 }; PaintRect(&bigRect); ForeColor(blackColor); }#endif // Temporarily retain self in case the plug-in view is released while sending an event. [[self retain] autorelease]; BOOL acceptedEvent; [self willCallPlugInFunction]; { JSC::JSLock::DropAllLocks dropAllLocks(false); acceptedEvent = ![_pluginPackage.get() pluginFuncs]->event(plugin, event); } [self didCallPlugInFunction]; if (portState) { if ([self currentWindow]) [self restorePortState:portState]; if (portState != (PortState)1) free(portState); } return acceptedEvent;}- (void)windowFocusChanged:(BOOL)hasFocus{ _eventHandler->windowFocusChanged(hasFocus);}- (void)sendDrawRectEvent:(NSRect)rect{ ASSERT(_eventHandler); _eventHandler->drawRect(rect);}- (void)stopTimers{ [super stopTimers]; if (_eventHandler) _eventHandler->stopTimers(); if (!timers) return; HashMap<uint32, PluginTimer*>::const_iterator end = timers->end(); for (HashMap<uint32, PluginTimer*>::const_iterator it = timers->begin(); it != end; ++it) { PluginTimer* timer = it->second; timer->stop(); } }- (void)startTimers{ [super startTimers]; // If the plugin is completely obscured (scrolled out of view, for example), then we will // send null events at a reduced rate. _eventHandler->startTimers(_isCompletelyObscured); if (!timers) return; HashMap<uint32, PluginTimer*>::const_iterator end = timers->end(); for (HashMap<uint32, PluginTimer*>::const_iterator it = timers->begin(); it != end; ++it) { PluginTimer* timer = it->second; ASSERT(!timer->isActive()); timer->start(_isCompletelyObscured); } }- (void)focusChanged{ // We need to null check the event handler here because // the plug-in view can resign focus after it's been stopped // and the event handler has been deleted. if (_eventHandler) _eventHandler->focusChanged(_hasFocus);}- (void)mouseDown:(NSEvent *)theEvent{ if (!_isStarted) return; _eventHandler->mouseDown(theEvent);}- (void)mouseUp:(NSEvent *)theEvent{ if (!_isStarted) return; _eventHandler->mouseUp(theEvent);}- (void)mouseEntered:(NSEvent *)theEvent{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -