WebNetscapePluginView.mm 92 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500
  1. /*
  2. * Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. *
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
  14. * its contributors may be used to endorse or promote products derived
  15. * from this software without specific prior written permission.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
  18. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  19. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  20. * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
  21. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  22. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  23. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  24. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  25. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  26. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27. */
  28. #if ENABLE(NETSCAPE_PLUGIN_API)
  29. #import "WebNetscapePluginView.h"
  30. #import "QuickDrawCompatibility.h"
  31. #import "WebDataSourceInternal.h"
  32. #import "WebDefaultUIDelegate.h"
  33. #import "WebFrameInternal.h"
  34. #import "WebFrameView.h"
  35. #import "WebKitErrorsPrivate.h"
  36. #import "WebKitLogging.h"
  37. #import "WebKitNSStringExtras.h"
  38. #import "WebKitSystemInterface.h"
  39. #import "WebNSDataExtras.h"
  40. #import "WebNSDictionaryExtras.h"
  41. #import "WebNSObjectExtras.h"
  42. #import "WebNSURLExtras.h"
  43. #import "WebNSURLRequestExtras.h"
  44. #import "WebNSViewExtras.h"
  45. #import "WebNetscapeContainerCheckContextInfo.h"
  46. #import "WebNetscapeContainerCheckPrivate.h"
  47. #import "WebNetscapePluginEventHandler.h"
  48. #import "WebNetscapePluginPackage.h"
  49. #import "WebNetscapePluginStream.h"
  50. #import "WebPluginContainerCheck.h"
  51. #import "WebPluginRequest.h"
  52. #import "WebPreferences.h"
  53. #import "WebUIDelegatePrivate.h"
  54. #import "WebViewInternal.h"
  55. #import <Carbon/Carbon.h>
  56. #import <WebCore/CookieJar.h>
  57. #import <WebCore/DocumentLoader.h>
  58. #import <WebCore/Element.h>
  59. #import <WebCore/Frame.h>
  60. #import <WebCore/FrameLoader.h>
  61. #import <WebCore/FrameTree.h>
  62. #import <WebCore/FrameView.h>
  63. #import <WebCore/HTMLPlugInElement.h>
  64. #import <WebCore/Page.h>
  65. #import <WebCore/PluginMainThreadScheduler.h>
  66. #import <WebCore/ProxyServer.h>
  67. #import <WebCore/RunLoop.h>
  68. #import <WebCore/ScriptController.h>
  69. #import <WebCore/SecurityOrigin.h>
  70. #import <WebCore/SoftLinking.h>
  71. #import <WebCore/UserGestureIndicator.h>
  72. #import <WebCore/WebCoreObjCExtras.h>
  73. #import <WebCore/WebCoreURLResponse.h>
  74. #import <WebCore/npruntime_impl.h>
  75. #import <WebKit/DOMPrivate.h>
  76. #import <WebKit/WebUIDelegate.h>
  77. #import <objc/runtime.h>
  78. #import <runtime/InitializeThreading.h>
  79. #import <runtime/JSLock.h>
  80. #import <wtf/Assertions.h>
  81. #import <wtf/MainThread.h>
  82. #import <wtf/text/CString.h>
  83. #define LoginWindowDidSwitchFromUserNotification @"WebLoginWindowDidSwitchFromUserNotification"
  84. #define LoginWindowDidSwitchToUserNotification @"WebLoginWindowDidSwitchToUserNotification"
  85. #define WKNVSupportsCompositingCoreAnimationPluginsBool 74656 /* TRUE if the browser supports hardware compositing of Core Animation plug-ins */
  86. static const int WKNVSilverlightFullscreenPerformanceIssueFixed = 7288546; /* TRUE if Siverlight addressed its underlying bug in <rdar://problem/7288546> */
  87. using namespace WebCore;
  88. using namespace WebKit;
  89. static inline bool isDrawingModelQuickDraw(NPDrawingModel drawingModel)
  90. {
  91. #ifndef NP_NO_QUICKDRAW
  92. return drawingModel == NPDrawingModelQuickDraw;
  93. #else
  94. return false;
  95. #endif
  96. };
  97. @interface WebNetscapePluginView (Internal)
  98. - (NPError)_createPlugin;
  99. - (void)_destroyPlugin;
  100. - (NSBitmapImageRep *)_printedPluginBitmap;
  101. - (void)_redeliverStream;
  102. - (BOOL)_shouldCancelSrcStream;
  103. @end
  104. static WebNetscapePluginView *currentPluginView = nil;
  105. typedef struct OpaquePortState* PortState;
  106. static const double ThrottledTimerInterval = 0.25;
  107. class PluginTimer : public TimerBase {
  108. public:
  109. typedef void (*TimerFunc)(NPP npp, uint32_t timerID);
  110. PluginTimer(NPP npp, uint32_t timerID, uint32_t interval, NPBool repeat, TimerFunc timerFunc)
  111. : m_npp(npp)
  112. , m_timerID(timerID)
  113. , m_interval(interval)
  114. , m_repeat(repeat)
  115. , m_timerFunc(timerFunc)
  116. {
  117. }
  118. void start(bool throttle)
  119. {
  120. ASSERT(!isActive());
  121. double timeInterval = m_interval / 1000.0;
  122. if (throttle)
  123. timeInterval = std::max(timeInterval, ThrottledTimerInterval);
  124. if (m_repeat)
  125. startRepeating(timeInterval);
  126. else
  127. startOneShot(timeInterval);
  128. }
  129. private:
  130. virtual void fired()
  131. {
  132. m_timerFunc(m_npp, m_timerID);
  133. if (!m_repeat)
  134. delete this;
  135. }
  136. NPP m_npp;
  137. uint32_t m_timerID;
  138. uint32_t m_interval;
  139. NPBool m_repeat;
  140. TimerFunc m_timerFunc;
  141. };
  142. #ifndef NP_NO_QUICKDRAW
  143. // QuickDraw is not available in 64-bit
  144. typedef struct {
  145. GrafPtr oldPort;
  146. GDHandle oldDevice;
  147. Point oldOrigin;
  148. RgnHandle oldClipRegion;
  149. RgnHandle oldVisibleRegion;
  150. RgnHandle clipRegion;
  151. BOOL forUpdate;
  152. } PortState_QD;
  153. #endif /* NP_NO_QUICKDRAW */
  154. typedef struct {
  155. CGContextRef context;
  156. } PortState_CG;
  157. @class NSTextInputContext;
  158. @interface NSResponder (AppKitDetails)
  159. - (NSTextInputContext *)inputContext;
  160. @end
  161. @interface WebNetscapePluginView (ForwardDeclarations)
  162. - (void)setWindowIfNecessary;
  163. - (NPError)loadRequest:(NSMutableURLRequest *)request inTarget:(const char *)cTarget withNotifyData:(void *)notifyData sendNotification:(BOOL)sendNotification;
  164. @end
  165. @implementation WebNetscapePluginView
  166. + (void)initialize
  167. {
  168. JSC::initializeThreading();
  169. WTF::initializeMainThreadToProcessMainThread();
  170. WebCore::RunLoop::initializeMainRunLoop();
  171. WebCoreObjCFinalizeOnMainThread(self);
  172. WKSendUserChangeNotifications();
  173. }
  174. // MARK: EVENTS
  175. // The WindowRef created by -[NSWindow windowRef] has a QuickDraw GrafPort that covers
  176. // the entire window frame (or structure region to use the Carbon term) rather then just the window content.
  177. // We can remove this when <rdar://problem/4201099> is fixed.
  178. - (void)fixWindowPort
  179. {
  180. #ifndef NP_NO_QUICKDRAW
  181. ASSERT(isDrawingModelQuickDraw(drawingModel));
  182. NSWindow *currentWindow = [self currentWindow];
  183. if ([currentWindow isKindOfClass:objc_getClass("NSCarbonWindow")])
  184. return;
  185. float windowHeight = [currentWindow frame].size.height;
  186. NSView *contentView = [currentWindow contentView];
  187. NSRect contentRect = [contentView convertRect:[contentView frame] toView:nil]; // convert to window-relative coordinates
  188. CGrafPtr oldPort;
  189. GetPort(&oldPort);
  190. SetPort(GetWindowPort((WindowRef)[currentWindow windowRef]));
  191. MovePortTo(static_cast<short>(contentRect.origin.x), /* Flip Y */ static_cast<short>(windowHeight - NSMaxY(contentRect)));
  192. PortSize(static_cast<short>(contentRect.size.width), static_cast<short>(contentRect.size.height));
  193. SetPort(oldPort);
  194. #endif
  195. }
  196. #ifndef NP_NO_QUICKDRAW
  197. static UInt32 getQDPixelFormatForBitmapContext(CGContextRef context)
  198. {
  199. UInt32 byteOrder = CGBitmapContextGetBitmapInfo(context) & kCGBitmapByteOrderMask;
  200. if (byteOrder == kCGBitmapByteOrderDefault)
  201. switch (CGBitmapContextGetBitsPerPixel(context)) {
  202. case 16:
  203. byteOrder = kCGBitmapByteOrder16Host;
  204. break;
  205. case 32:
  206. byteOrder = kCGBitmapByteOrder32Host;
  207. break;
  208. }
  209. switch (byteOrder) {
  210. case kCGBitmapByteOrder16Little:
  211. return k16LE555PixelFormat;
  212. case kCGBitmapByteOrder32Little:
  213. return k32BGRAPixelFormat;
  214. case kCGBitmapByteOrder16Big:
  215. return k16BE555PixelFormat;
  216. case kCGBitmapByteOrder32Big:
  217. return k32ARGBPixelFormat;
  218. }
  219. ASSERT_NOT_REACHED();
  220. return 0;
  221. }
  222. static inline void getNPRect(const CGRect& cgr, NPRect& npr)
  223. {
  224. npr.top = static_cast<uint16_t>(cgr.origin.y);
  225. npr.left = static_cast<uint16_t>(cgr.origin.x);
  226. npr.bottom = static_cast<uint16_t>(CGRectGetMaxY(cgr));
  227. npr.right = static_cast<uint16_t>(CGRectGetMaxX(cgr));
  228. }
  229. #endif
  230. static inline void getNPRect(const NSRect& nr, NPRect& npr)
  231. {
  232. npr.top = static_cast<uint16_t>(nr.origin.y);
  233. npr.left = static_cast<uint16_t>(nr.origin.x);
  234. npr.bottom = static_cast<uint16_t>(NSMaxY(nr));
  235. npr.right = static_cast<uint16_t>(NSMaxX(nr));
  236. }
  237. - (PortState)saveAndSetNewPortStateForUpdate:(BOOL)forUpdate
  238. {
  239. ASSERT([self currentWindow] != nil);
  240. // The base coordinates of a window and it's contentView happen to be the equal at a userSpaceScaleFactor
  241. // of 1. For non-1.0 scale factors this assumption is false.
  242. NSView *windowContentView = [[self window] contentView];
  243. NSRect boundsInWindow = [self convertRect:[self bounds] toView:windowContentView];
  244. NSRect visibleRectInWindow = [self actualVisibleRectInWindow];
  245. // Flip Y to convert -[NSWindow contentView] coordinates to top-left-based window coordinates.
  246. float borderViewHeight = [[self currentWindow] frame].size.height;
  247. boundsInWindow.origin.y = borderViewHeight - NSMaxY(boundsInWindow);
  248. visibleRectInWindow.origin.y = borderViewHeight - NSMaxY(visibleRectInWindow);
  249. #ifndef NP_NO_QUICKDRAW
  250. WindowRef windowRef = (WindowRef)[[self currentWindow] windowRef];
  251. ASSERT(windowRef);
  252. // Look at the Carbon port to convert top-left-based window coordinates into top-left-based content coordinates.
  253. if (isDrawingModelQuickDraw(drawingModel)) {
  254. // If drawing with QuickDraw, fix the window port so that it has the same bounds as the NSWindow's
  255. // content view. This makes it easier to convert between AppKit view and QuickDraw port coordinates.
  256. [self fixWindowPort];
  257. ::Rect portBounds;
  258. CGrafPtr port = GetWindowPort(windowRef);
  259. GetPortBounds(port, &portBounds);
  260. PixMap *pix = *GetPortPixMap(port);
  261. boundsInWindow.origin.x += pix->bounds.left - portBounds.left;
  262. boundsInWindow.origin.y += pix->bounds.top - portBounds.top;
  263. visibleRectInWindow.origin.x += pix->bounds.left - portBounds.left;
  264. visibleRectInWindow.origin.y += pix->bounds.top - portBounds.top;
  265. }
  266. #endif
  267. window.type = NPWindowTypeWindow;
  268. window.x = (int32_t)boundsInWindow.origin.x;
  269. window.y = (int32_t)boundsInWindow.origin.y;
  270. window.width = static_cast<uint32_t>(NSWidth(boundsInWindow));
  271. window.height = static_cast<uint32_t>(NSHeight(boundsInWindow));
  272. // "Clip-out" the plug-in when:
  273. // 1) it's not really in a window or off-screen or has no height or width.
  274. // 2) window.x is a "big negative number" which is how WebCore expresses off-screen widgets.
  275. // 3) the window is miniaturized or the app is hidden
  276. // 4) we're inside of viewWillMoveToWindow: with a nil window. In this case, superviews may already have nil
  277. // superviews and nil windows and results from convertRect:toView: are incorrect.
  278. if (window.width <= 0 || window.height <= 0 || window.x < -100000 || [self shouldClipOutPlugin]) {
  279. // The following code tries to give plug-ins the same size they will eventually have.
  280. // The specifiedWidth and specifiedHeight variables are used to predict the size that
  281. // WebCore will eventually resize us to.
  282. // The QuickTime plug-in has problems if you give it a width or height of 0.
  283. // Since other plug-ins also might have the same sort of trouble, we make sure
  284. // to always give plug-ins a size other than 0,0.
  285. if (window.width <= 0)
  286. window.width = specifiedWidth > 0 ? specifiedWidth : 100;
  287. if (window.height <= 0)
  288. window.height = specifiedHeight > 0 ? specifiedHeight : 100;
  289. window.clipRect.bottom = window.clipRect.top;
  290. window.clipRect.left = window.clipRect.right;
  291. // Core Animation plug-ins need to be updated (with a 0,0,0,0 clipRect) when
  292. // moved to a background tab. We don't do this for Core Graphics plug-ins as
  293. // older versions of Flash have historical WebKit-specific code that isn't
  294. // compatible with this behavior.
  295. if (drawingModel == NPDrawingModelCoreAnimation)
  296. getNPRect(NSZeroRect, window.clipRect);
  297. } else {
  298. getNPRect(visibleRectInWindow, window.clipRect);
  299. }
  300. // Save the port state, set up the port for entry into the plugin
  301. PortState portState;
  302. switch (drawingModel) {
  303. #ifndef NP_NO_QUICKDRAW
  304. case NPDrawingModelQuickDraw: {
  305. // Set up NS_Port.
  306. ::Rect portBounds;
  307. CGrafPtr port = GetWindowPort(windowRef);
  308. GetPortBounds(port, &portBounds);
  309. nPort.qdPort.port = port;
  310. nPort.qdPort.portx = (int32_t)-boundsInWindow.origin.x;
  311. nPort.qdPort.porty = (int32_t)-boundsInWindow.origin.y;
  312. window.window = &nPort;
  313. PortState_QD *qdPortState = (PortState_QD*)malloc(sizeof(PortState_QD));
  314. portState = (PortState)qdPortState;
  315. GetGWorld(&qdPortState->oldPort, &qdPortState->oldDevice);
  316. qdPortState->oldOrigin.h = portBounds.left;
  317. qdPortState->oldOrigin.v = portBounds.top;
  318. qdPortState->oldClipRegion = NewRgn();
  319. GetPortClipRegion(port, qdPortState->oldClipRegion);
  320. qdPortState->oldVisibleRegion = NewRgn();
  321. GetPortVisibleRegion(port, qdPortState->oldVisibleRegion);
  322. RgnHandle clipRegion = NewRgn();
  323. qdPortState->clipRegion = clipRegion;
  324. CGContextRef currentContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
  325. if (currentContext && WKCGContextIsBitmapContext(currentContext)) {
  326. // We use WKCGContextIsBitmapContext here, because if we just called CGBitmapContextGetData
  327. // on any context, we'd log to the console every time. But even if WKCGContextIsBitmapContext
  328. // returns true, it still might not be a context we need to create a GWorld for; for example
  329. // transparency layers will return true, but return 0 for CGBitmapContextGetData.
  330. void* offscreenData = CGBitmapContextGetData(currentContext);
  331. if (offscreenData) {
  332. // If the current context is an offscreen bitmap, then create a GWorld for it.
  333. ::Rect offscreenBounds;
  334. offscreenBounds.top = 0;
  335. offscreenBounds.left = 0;
  336. offscreenBounds.right = CGBitmapContextGetWidth(currentContext);
  337. offscreenBounds.bottom = CGBitmapContextGetHeight(currentContext);
  338. GWorldPtr newOffscreenGWorld;
  339. QDErr err = NewGWorldFromPtr(&newOffscreenGWorld,
  340. getQDPixelFormatForBitmapContext(currentContext), &offscreenBounds, 0, 0, 0,
  341. static_cast<char*>(offscreenData), CGBitmapContextGetBytesPerRow(currentContext));
  342. ASSERT(newOffscreenGWorld);
  343. ASSERT(!err);
  344. if (!err) {
  345. if (offscreenGWorld)
  346. DisposeGWorld(offscreenGWorld);
  347. offscreenGWorld = newOffscreenGWorld;
  348. SetGWorld(offscreenGWorld, NULL);
  349. port = offscreenGWorld;
  350. nPort.qdPort.port = port;
  351. boundsInWindow = [self bounds];
  352. // Generate a QD origin based on the current affine transform for currentContext.
  353. CGAffineTransform offscreenMatrix = CGContextGetCTM(currentContext);
  354. CGPoint origin = {0,0};
  355. CGPoint axisFlip = {1,1};
  356. origin = CGPointApplyAffineTransform(origin, offscreenMatrix);
  357. axisFlip = CGPointApplyAffineTransform(axisFlip, offscreenMatrix);
  358. // Quartz bitmaps have origins at the bottom left, but the axes may be inverted, so handle that.
  359. origin.x = offscreenBounds.left - origin.x * (axisFlip.x - origin.x);
  360. origin.y = offscreenBounds.bottom + origin.y * (axisFlip.y - origin.y);
  361. nPort.qdPort.portx = static_cast<int32_t>(-boundsInWindow.origin.x + origin.x);
  362. nPort.qdPort.porty = static_cast<int32_t>(-boundsInWindow.origin.y - origin.y);
  363. window.x = 0;
  364. window.y = 0;
  365. window.window = &nPort;
  366. // Use the clip bounds from the context instead of the bounds we created
  367. // from the window above.
  368. getNPRect(CGRectOffset(CGContextGetClipBoundingBox(currentContext), -origin.x, origin.y), window.clipRect);
  369. }
  370. }
  371. }
  372. MacSetRectRgn(clipRegion,
  373. window.clipRect.left + nPort.qdPort.portx, window.clipRect.top + nPort.qdPort.porty,
  374. window.clipRect.right + nPort.qdPort.portx, window.clipRect.bottom + nPort.qdPort.porty);
  375. // Clip to the dirty region if drawing to a window. When drawing to another bitmap context, do not clip.
  376. if ([NSGraphicsContext currentContext] == [[self currentWindow] graphicsContext]) {
  377. // Clip to dirty region so plug-in does not draw over already-drawn regions of the window that are
  378. // not going to be redrawn this update. This forces plug-ins to play nice with z-index ordering.
  379. if (forUpdate) {
  380. RgnHandle viewClipRegion = NewRgn();
  381. // Get list of dirty rects from the opaque ancestor -- WebKit does some tricks with invalidation and
  382. // display to enable z-ordering for NSViews; a side-effect of this is that only the WebHTMLView
  383. // knows about the true set of dirty rects.
  384. NSView *opaqueAncestor = [self opaqueAncestor];
  385. const NSRect *dirtyRects;
  386. NSInteger dirtyRectCount, dirtyRectIndex;
  387. [opaqueAncestor getRectsBeingDrawn:&dirtyRects count:&dirtyRectCount];
  388. for (dirtyRectIndex = 0; dirtyRectIndex < dirtyRectCount; dirtyRectIndex++) {
  389. NSRect dirtyRect = [self convertRect:dirtyRects[dirtyRectIndex] fromView:opaqueAncestor];
  390. if (!NSEqualSizes(dirtyRect.size, NSZeroSize)) {
  391. // Create a region for this dirty rect
  392. RgnHandle dirtyRectRegion = NewRgn();
  393. SetRectRgn(dirtyRectRegion, static_cast<short>(NSMinX(dirtyRect)), static_cast<short>(NSMinY(dirtyRect)), static_cast<short>(NSMaxX(dirtyRect)), static_cast<short>(NSMaxY(dirtyRect)));
  394. // Union this dirty rect with the rest of the dirty rects
  395. UnionRgn(viewClipRegion, dirtyRectRegion, viewClipRegion);
  396. DisposeRgn(dirtyRectRegion);
  397. }
  398. }
  399. // Intersect the dirty region with the clip region, so that we only draw over dirty parts
  400. SectRgn(clipRegion, viewClipRegion, clipRegion);
  401. DisposeRgn(viewClipRegion);
  402. }
  403. }
  404. // Switch to the port and set it up.
  405. SetPort(port);
  406. PenNormal();
  407. ForeColor(blackColor);
  408. BackColor(whiteColor);
  409. SetOrigin(nPort.qdPort.portx, nPort.qdPort.porty);
  410. SetPortClipRegion(nPort.qdPort.port, clipRegion);
  411. if (forUpdate) {
  412. // AppKit may have tried to help us by doing a BeginUpdate.
  413. // But the invalid region at that level didn't include AppKit's notion of what was not valid.
  414. // We reset the port's visible region to counteract what BeginUpdate did.
  415. SetPortVisibleRegion(nPort.qdPort.port, clipRegion);
  416. InvalWindowRgn(windowRef, clipRegion);
  417. }
  418. qdPortState->forUpdate = forUpdate;
  419. break;
  420. }
  421. #endif /* NP_NO_QUICKDRAW */
  422. case NPDrawingModelCoreGraphics: {
  423. if (![self canDraw]) {
  424. portState = NULL;
  425. break;
  426. }
  427. ASSERT([NSView focusView] == self);
  428. CGContextRef context = static_cast<CGContextRef>([[NSGraphicsContext currentContext] graphicsPort]);
  429. PortState_CG *cgPortState = (PortState_CG *)malloc(sizeof(PortState_CG));
  430. portState = (PortState)cgPortState;
  431. cgPortState->context = context;
  432. #ifndef NP_NO_CARBON
  433. if (eventModel != NPEventModelCocoa) {
  434. // Update the plugin's window/context
  435. nPort.cgPort.window = windowRef;
  436. nPort.cgPort.context = context;
  437. window.window = &nPort.cgPort;
  438. }
  439. #endif /* NP_NO_CARBON */
  440. // Save current graphics context's state; will be restored by -restorePortState:
  441. CGContextSaveGState(context);
  442. // Clip to the dirty region if drawing to a window. When drawing to another bitmap context, do not clip.
  443. if ([NSGraphicsContext currentContext] == [[self currentWindow] graphicsContext]) {
  444. // Get list of dirty rects from the opaque ancestor -- WebKit does some tricks with invalidation and
  445. // display to enable z-ordering for NSViews; a side-effect of this is that only the WebHTMLView
  446. // knows about the true set of dirty rects.
  447. NSView *opaqueAncestor = [self opaqueAncestor];
  448. const NSRect *dirtyRects;
  449. NSInteger count;
  450. [opaqueAncestor getRectsBeingDrawn:&dirtyRects count:&count];
  451. Vector<CGRect, 16> convertedDirtyRects;
  452. convertedDirtyRects.resize(count);
  453. for (int i = 0; i < count; ++i)
  454. reinterpret_cast<NSRect&>(convertedDirtyRects[i]) = [self convertRect:dirtyRects[i] fromView:opaqueAncestor];
  455. CGContextClipToRects(context, convertedDirtyRects.data(), count);
  456. }
  457. break;
  458. }
  459. case NPDrawingModelCoreAnimation:
  460. // Just set the port state to a dummy value.
  461. portState = (PortState)1;
  462. break;
  463. default:
  464. ASSERT_NOT_REACHED();
  465. portState = NULL;
  466. break;
  467. }
  468. return portState;
  469. }
  470. - (PortState)saveAndSetNewPortState
  471. {
  472. return [self saveAndSetNewPortStateForUpdate:NO];
  473. }
  474. - (void)restorePortState:(PortState)portState
  475. {
  476. ASSERT([self currentWindow]);
  477. ASSERT(portState);
  478. switch (drawingModel) {
  479. #ifndef NP_NO_QUICKDRAW
  480. case NPDrawingModelQuickDraw: {
  481. PortState_QD *qdPortState = (PortState_QD *)portState;
  482. WindowRef windowRef = (WindowRef)[[self currentWindow] windowRef];
  483. CGrafPtr port = GetWindowPort(windowRef);
  484. SetPort(port);
  485. if (qdPortState->forUpdate)
  486. ValidWindowRgn(windowRef, qdPortState->clipRegion);
  487. SetOrigin(qdPortState->oldOrigin.h, qdPortState->oldOrigin.v);
  488. SetPortClipRegion(port, qdPortState->oldClipRegion);
  489. if (qdPortState->forUpdate)
  490. SetPortVisibleRegion(port, qdPortState->oldVisibleRegion);
  491. DisposeRgn(qdPortState->oldClipRegion);
  492. DisposeRgn(qdPortState->oldVisibleRegion);
  493. DisposeRgn(qdPortState->clipRegion);
  494. SetGWorld(qdPortState->oldPort, qdPortState->oldDevice);
  495. break;
  496. }
  497. #endif /* NP_NO_QUICKDRAW */
  498. case NPDrawingModelCoreGraphics: {
  499. ASSERT([NSView focusView] == self);
  500. CGContextRef context = ((PortState_CG *)portState)->context;
  501. ASSERT(!nPort.cgPort.context || (context == nPort.cgPort.context));
  502. CGContextRestoreGState(context);
  503. break;
  504. }
  505. case NPDrawingModelCoreAnimation:
  506. ASSERT(portState == (PortState)1);
  507. break;
  508. default:
  509. ASSERT_NOT_REACHED();
  510. break;
  511. }
  512. }
  513. - (BOOL)sendEvent:(void*)event isDrawRect:(BOOL)eventIsDrawRect
  514. {
  515. if (![self window])
  516. return NO;
  517. ASSERT(event);
  518. if (!_isStarted)
  519. return NO;
  520. ASSERT([_pluginPackage.get() pluginFuncs]->event);
  521. // Make sure we don't call NPP_HandleEvent while we're inside NPP_SetWindow.
  522. // We probably don't want more general reentrancy protection; we are really
  523. // protecting only against this one case, which actually comes up when
  524. // you first install the SVG viewer plug-in.
  525. if (inSetWindow)
  526. return NO;
  527. Frame* frame = core([self webFrame]);
  528. if (!frame)
  529. return NO;
  530. Page* page = frame->page();
  531. if (!page)
  532. return NO;
  533. // Can only send drawRect (updateEvt) to CoreGraphics plugins when actually drawing
  534. ASSERT((drawingModel != NPDrawingModelCoreGraphics) || !eventIsDrawRect || [NSView focusView] == self);
  535. PortState portState = NULL;
  536. if (isDrawingModelQuickDraw(drawingModel) || (drawingModel != NPDrawingModelCoreAnimation && eventIsDrawRect)) {
  537. // In CoreGraphics mode, the port state only needs to be saved/set when redrawing the plug-in view.
  538. // The plug-in is not allowed to draw at any other time.
  539. portState = [self saveAndSetNewPortStateForUpdate:eventIsDrawRect];
  540. // We may have changed the window, so inform the plug-in.
  541. [self setWindowIfNecessary];
  542. }
  543. #if !defined(NDEBUG) && !defined(NP_NO_QUICKDRAW)
  544. // Draw green to help debug.
  545. // If we see any green we know something's wrong.
  546. // Note that PaintRect() only works for QuickDraw plugins; otherwise the current QD port is undefined.
  547. if (isDrawingModelQuickDraw(drawingModel) && eventIsDrawRect) {
  548. ForeColor(greenColor);
  549. const ::Rect bigRect = { -10000, -10000, 10000, 10000 };
  550. PaintRect(&bigRect);
  551. ForeColor(blackColor);
  552. }
  553. #endif
  554. // Temporarily retain self in case the plug-in view is released while sending an event.
  555. [[self retain] autorelease];
  556. BOOL acceptedEvent;
  557. [self willCallPlugInFunction];
  558. // Set the pluginAllowPopup flag.
  559. ASSERT(_eventHandler);
  560. {
  561. JSC::JSLock::DropAllLocks dropAllLocks(JSDOMWindowBase::commonVM());
  562. UserGestureIndicator gestureIndicator(_eventHandler->currentEventIsUserGesture() ? DefinitelyProcessingNewUserGesture : PossiblyProcessingUserGesture);
  563. acceptedEvent = [_pluginPackage.get() pluginFuncs]->event(plugin, event);
  564. }
  565. [self didCallPlugInFunction];
  566. if (portState) {
  567. if ([self currentWindow])
  568. [self restorePortState:portState];
  569. if (portState != (PortState)1)
  570. free(portState);
  571. }
  572. return acceptedEvent;
  573. }
  574. - (void)windowFocusChanged:(BOOL)hasFocus
  575. {
  576. _eventHandler->windowFocusChanged(hasFocus);
  577. }
  578. - (void)sendDrawRectEvent:(NSRect)rect
  579. {
  580. ASSERT(_eventHandler);
  581. CGContextRef context = static_cast<CGContextRef>([[NSGraphicsContext currentContext] graphicsPort]);
  582. _eventHandler->drawRect(context, rect);
  583. }
  584. - (void)stopTimers
  585. {
  586. [super stopTimers];
  587. if (_eventHandler)
  588. _eventHandler->stopTimers();
  589. if (!timers)
  590. return;
  591. HashMap<uint32_t, PluginTimer*>::const_iterator end = timers->end();
  592. for (HashMap<uint32_t, PluginTimer*>::const_iterator it = timers->begin(); it != end; ++it) {
  593. PluginTimer* timer = it->value;
  594. timer->stop();
  595. }
  596. }
  597. - (void)startTimers
  598. {
  599. [super startTimers];
  600. // If the plugin is completely obscured (scrolled out of view, for example), then we will
  601. // send null events at a reduced rate.
  602. _eventHandler->startTimers(_isCompletelyObscured);
  603. if (!timers)
  604. return;
  605. HashMap<uint32_t, PluginTimer*>::const_iterator end = timers->end();
  606. for (HashMap<uint32_t, PluginTimer*>::const_iterator it = timers->begin(); it != end; ++it) {
  607. PluginTimer* timer = it->value;
  608. ASSERT(!timer->isActive());
  609. timer->start(_isCompletelyObscured);
  610. }
  611. }
  612. - (void)focusChanged
  613. {
  614. // We need to null check the event handler here because
  615. // the plug-in view can resign focus after it's been stopped
  616. // and the event handler has been deleted.
  617. if (_eventHandler)
  618. _eventHandler->focusChanged(_hasFocus);
  619. }
  620. - (void)mouseDown:(NSEvent *)theEvent
  621. {
  622. if (!_isStarted)
  623. return;
  624. _eventHandler->mouseDown(theEvent);
  625. }
  626. - (void)mouseUp:(NSEvent *)theEvent
  627. {
  628. if (!_isStarted)
  629. return;
  630. _eventHandler->mouseUp(theEvent);
  631. }
  632. - (void)handleMouseEntered:(NSEvent *)theEvent
  633. {
  634. if (!_isStarted)
  635. return;
  636. // Set cursor to arrow. Plugins often handle cursor internally, but those that don't will just get this default one.
  637. [[NSCursor arrowCursor] set];
  638. _eventHandler->mouseEntered(theEvent);
  639. }
  640. - (void)handleMouseExited:(NSEvent *)theEvent
  641. {
  642. if (!_isStarted)
  643. return;
  644. _eventHandler->mouseExited(theEvent);
  645. // Set cursor back to arrow cursor. Because NSCursor doesn't know about changes that the plugin made, we could get confused about what we think the
  646. // current cursor is otherwise. Therefore we have no choice but to unconditionally reset the cursor when the mouse exits the plugin.
  647. [[NSCursor arrowCursor] set];
  648. }
  649. - (void)handleMouseMoved:(NSEvent *)theEvent
  650. {
  651. if (!_isStarted)
  652. return;
  653. _eventHandler->mouseMoved(theEvent);
  654. }
  655. - (void)mouseDragged:(NSEvent *)theEvent
  656. {
  657. if (!_isStarted)
  658. return;
  659. _eventHandler->mouseDragged(theEvent);
  660. }
  661. - (void)scrollWheel:(NSEvent *)theEvent
  662. {
  663. if (!_isStarted) {
  664. [super scrollWheel:theEvent];
  665. return;
  666. }
  667. if (!_eventHandler->scrollWheel(theEvent))
  668. [super scrollWheel:theEvent];
  669. }
  670. - (void)keyUp:(NSEvent *)theEvent
  671. {
  672. if (!_isStarted)
  673. return;
  674. _eventHandler->keyUp(theEvent);
  675. }
  676. - (void)keyDown:(NSEvent *)theEvent
  677. {
  678. if (!_isStarted)
  679. return;
  680. _eventHandler->keyDown(theEvent);
  681. }
  682. - (void)flagsChanged:(NSEvent *)theEvent
  683. {
  684. if (!_isStarted)
  685. return;
  686. _eventHandler->flagsChanged(theEvent);
  687. }
  688. - (void)sendModifierEventWithKeyCode:(int)keyCode character:(char)character
  689. {
  690. if (!_isStarted)
  691. return;
  692. _eventHandler->syntheticKeyDownWithCommandModifier(keyCode, character);
  693. }
  694. - (void)privateBrowsingModeDidChange
  695. {
  696. if (!_isStarted)
  697. return;
  698. NPBool value = _isPrivateBrowsingEnabled;
  699. [self willCallPlugInFunction];
  700. {
  701. JSC::JSLock::DropAllLocks dropAllLocks(JSDOMWindowBase::commonVM());
  702. if ([_pluginPackage.get() pluginFuncs]->setvalue)
  703. [_pluginPackage.get() pluginFuncs]->setvalue(plugin, NPNVprivateModeBool, &value);
  704. }
  705. [self didCallPlugInFunction];
  706. }
  707. // MARK: WEB_NETSCAPE_PLUGIN
  708. - (BOOL)isNewWindowEqualToOldWindow
  709. {
  710. if (window.x != lastSetWindow.x)
  711. return NO;
  712. if (window.y != lastSetWindow.y)
  713. return NO;
  714. if (window.width != lastSetWindow.width)
  715. return NO;
  716. if (window.height != lastSetWindow.height)
  717. return NO;
  718. if (window.clipRect.top != lastSetWindow.clipRect.top)
  719. return NO;
  720. if (window.clipRect.left != lastSetWindow.clipRect.left)
  721. return NO;
  722. if (window.clipRect.bottom != lastSetWindow.clipRect.bottom)
  723. return NO;
  724. if (window.clipRect.right != lastSetWindow.clipRect.right)
  725. return NO;
  726. if (window.type != lastSetWindow.type)
  727. return NO;
  728. switch (drawingModel) {
  729. #ifndef NP_NO_QUICKDRAW
  730. case NPDrawingModelQuickDraw:
  731. if (nPort.qdPort.portx != lastSetPort.qdPort.portx)
  732. return NO;
  733. if (nPort.qdPort.porty != lastSetPort.qdPort.porty)
  734. return NO;
  735. if (nPort.qdPort.port != lastSetPort.qdPort.port)
  736. return NO;
  737. break;
  738. #endif /* NP_NO_QUICKDRAW */
  739. case NPDrawingModelCoreGraphics:
  740. if (nPort.cgPort.window != lastSetPort.cgPort.window)
  741. return NO;
  742. if (nPort.cgPort.context != lastSetPort.cgPort.context)
  743. return NO;
  744. break;
  745. case NPDrawingModelCoreAnimation:
  746. if (window.window != lastSetWindow.window)
  747. return NO;
  748. break;
  749. default:
  750. ASSERT_NOT_REACHED();
  751. break;
  752. }
  753. return YES;
  754. }
  755. -(void)tellQuickTimeToChill
  756. {
  757. #ifndef NP_NO_QUICKDRAW
  758. ASSERT(isDrawingModelQuickDraw(drawingModel));
  759. // Make a call to the secret QuickDraw API that makes QuickTime calm down.
  760. WindowRef windowRef = (WindowRef)[[self window] windowRef];
  761. if (!windowRef) {
  762. return;
  763. }
  764. CGrafPtr port = GetWindowPort(windowRef);
  765. ::Rect bounds;
  766. GetPortBounds(port, &bounds);
  767. WKCallDrawingNotification(port, &bounds);
  768. #endif /* NP_NO_QUICKDRAW */
  769. }
  770. - (void)updateAndSetWindow
  771. {
  772. // A plug-in can only update if it's (1) already been started (2) isn't stopped
  773. // and (3) is able to draw on-screen. To meet condition (3) the plug-in must not
  774. // be hidden and be attached to a window. There are two exceptions to this rule:
  775. //
  776. // Exception 1: QuickDraw plug-ins must be manually told when to stop writing
  777. // bits to the window backing store, thus to do so requires a new call to
  778. // NPP_SetWindow() with an empty NPWindow struct.
  779. //
  780. // Exception 2: CoreGraphics plug-ins expect to have their drawable area updated
  781. // when they are moved to a background tab, via a NPP_SetWindow call. This is
  782. // accomplished by allowing -saveAndSetNewPortStateForUpdate to "clip-out" the window's
  783. // clipRect. Flash is curently an exception to this. See 6453738.
  784. //
  785. if (!_isStarted)
  786. return;
  787. #ifdef NP_NO_QUICKDRAW
  788. if (![self canDraw])
  789. return;
  790. #else
  791. if (drawingModel == NPDrawingModelQuickDraw)
  792. [self tellQuickTimeToChill];
  793. else if (drawingModel == NPDrawingModelCoreGraphics && ![self canDraw] && _isFlash) {
  794. // The Flash plug-in does not expect an NPP_SetWindow call from WebKit in this case.
  795. // See Exception 2 above.
  796. return;
  797. }
  798. #endif // NP_NO_QUICKDRAW
  799. BOOL didLockFocus = [NSView focusView] != self && [self lockFocusIfCanDraw];
  800. PortState portState = [self saveAndSetNewPortState];
  801. if (portState) {
  802. [self setWindowIfNecessary];
  803. [self restorePortState:portState];
  804. if (portState != (PortState)1)
  805. free(portState);
  806. } else if (drawingModel == NPDrawingModelCoreGraphics)
  807. [self setWindowIfNecessary];
  808. if (didLockFocus)
  809. [self unlockFocus];
  810. }
  811. - (void)setWindowIfNecessary
  812. {
  813. if (!_isStarted)
  814. return;
  815. if (![self isNewWindowEqualToOldWindow]) {
  816. // Make sure we don't call NPP_HandleEvent while we're inside NPP_SetWindow.
  817. // We probably don't want more general reentrancy protection; we are really
  818. // protecting only against this one case, which actually comes up when
  819. // you first install the SVG viewer plug-in.
  820. NPError npErr;
  821. BOOL wasInSetWindow = inSetWindow;
  822. inSetWindow = YES;
  823. [self willCallPlugInFunction];
  824. {
  825. JSC::JSLock::DropAllLocks dropAllLocks(JSDOMWindowBase::commonVM());
  826. npErr = [_pluginPackage.get() pluginFuncs]->setwindow(plugin, &window);
  827. }
  828. [self didCallPlugInFunction];
  829. inSetWindow = wasInSetWindow;
  830. #ifndef NDEBUG
  831. switch (drawingModel) {
  832. #ifndef NP_NO_QUICKDRAW
  833. case NPDrawingModelQuickDraw:
  834. LOG(Plugins, "NPP_SetWindow (QuickDraw): %d, port=0x%08x, window.x:%d window.y:%d window.width:%d window.height:%d",
  835. npErr, (int)nPort.qdPort.port, (int)window.x, (int)window.y, (int)window.width, (int)window.height);
  836. break;
  837. #endif /* NP_NO_QUICKDRAW */
  838. case NPDrawingModelCoreGraphics:
  839. LOG(Plugins, "NPP_SetWindow (CoreGraphics): %d, window=%p, context=%p, window.x:%d window.y:%d window.width:%d window.height:%d window.clipRect size:%dx%d",
  840. npErr, nPort.cgPort.window, nPort.cgPort.context, (int)window.x, (int)window.y, (int)window.width, (int)window.height,
  841. window.clipRect.right - window.clipRect.left, window.clipRect.bottom - window.clipRect.top);
  842. break;
  843. case NPDrawingModelCoreAnimation:
  844. LOG(Plugins, "NPP_SetWindow (CoreAnimation): %d, window=%p window.x:%d window.y:%d window.width:%d window.height:%d",
  845. npErr, window.window, nPort.cgPort.context, (int)window.x, (int)window.y, (int)window.width, (int)window.height);
  846. break;
  847. default:
  848. ASSERT_NOT_REACHED();
  849. break;
  850. }
  851. #endif /* !defined(NDEBUG) */
  852. lastSetWindow = window;
  853. lastSetPort = nPort;
  854. }
  855. }
  856. + (void)setCurrentPluginView:(WebNetscapePluginView *)view
  857. {
  858. currentPluginView = view;
  859. }
  860. + (WebNetscapePluginView *)currentPluginView
  861. {
  862. return currentPluginView;
  863. }
  864. - (BOOL)createPlugin
  865. {
  866. // Open the plug-in package so it remains loaded while our plugin uses it
  867. [_pluginPackage.get() open];
  868. // Initialize drawingModel to an invalid value so that we can detect when the plugin does not specify a drawingModel
  869. drawingModel = (NPDrawingModel)-1;
  870. // Initialize eventModel to an invalid value so that we can detect when the plugin does not specify an event model.
  871. eventModel = (NPEventModel)-1;
  872. NPError npErr = [self _createPlugin];
  873. if (npErr != NPERR_NO_ERROR) {
  874. LOG_ERROR("NPP_New failed with error: %d", npErr);
  875. [self _destroyPlugin];
  876. [_pluginPackage.get() close];
  877. return NO;
  878. }
  879. if (drawingModel == (NPDrawingModel)-1) {
  880. #ifndef NP_NO_QUICKDRAW
  881. // Default to QuickDraw if the plugin did not specify a drawing model.
  882. drawingModel = NPDrawingModelQuickDraw;
  883. #else
  884. // QuickDraw is not available, so we can't default to it. Instead, default to CoreGraphics.
  885. drawingModel = NPDrawingModelCoreGraphics;
  886. #endif
  887. }
  888. if (eventModel == (NPEventModel)-1) {
  889. // If the plug-in did not specify a drawing model we default to Carbon when it is available.
  890. #ifndef NP_NO_CARBON
  891. eventModel = NPEventModelCarbon;
  892. #else
  893. eventModel = NPEventModelCocoa;
  894. #endif // NP_NO_CARBON
  895. }
  896. #ifndef NP_NO_CARBON
  897. if (eventModel == NPEventModelCocoa && isDrawingModelQuickDraw(drawingModel)) {
  898. LOG(Plugins, "Plugin can't use use Cocoa event model with QuickDraw drawing model: %@", _pluginPackage.get());
  899. [self _destroyPlugin];
  900. [_pluginPackage.get() close];
  901. return NO;
  902. }
  903. #endif // NP_NO_CARBON
  904. if (drawingModel == NPDrawingModelCoreAnimation) {
  905. void *value = 0;
  906. if ([_pluginPackage.get() pluginFuncs]->getvalue(plugin, NPPVpluginCoreAnimationLayer, &value) == NPERR_NO_ERROR && value) {
  907. // The plug-in gives us a retained layer.
  908. _pluginLayer = adoptNS((CALayer *)value);
  909. BOOL accleratedCompositingEnabled = false;
  910. #if USE(ACCELERATED_COMPOSITING)
  911. accleratedCompositingEnabled = [[[self webView] preferences] acceleratedCompositingEnabled];
  912. #endif
  913. if (accleratedCompositingEnabled) {
  914. // FIXME: This code can be shared between WebHostedNetscapePluginView and WebNetscapePluginView.
  915. // Since this layer isn't going to be inserted into a view, we need to create another layer and flip its geometry
  916. // in order to get the coordinate system right.
  917. RetainPtr<CALayer> realPluginLayer = adoptNS(_pluginLayer.leakRef());
  918. _pluginLayer = adoptNS([[CALayer alloc] init]);
  919. _pluginLayer.get().bounds = realPluginLayer.get().bounds;
  920. _pluginLayer.get().geometryFlipped = YES;
  921. realPluginLayer.get().autoresizingMask = kCALayerWidthSizable | kCALayerHeightSizable;
  922. [_pluginLayer.get() addSublayer:realPluginLayer.get()];
  923. // Eagerly enter compositing mode, since we know we'll need it. This avoids firing setNeedsStyleRecalc()
  924. // for iframes that contain composited plugins at bad times. https://bugs.webkit.org/show_bug.cgi?id=39033
  925. core([self webFrame])->view()->enterCompositingMode();
  926. [self element]->setNeedsStyleRecalc(SyntheticStyleChange);
  927. } else
  928. [self setWantsLayer:YES];
  929. LOG(Plugins, "%@ is using Core Animation drawing model with layer %@", _pluginPackage.get(), _pluginLayer.get());
  930. }
  931. ASSERT(_pluginLayer);
  932. }
  933. // Create the event handler
  934. _eventHandler = WebNetscapePluginEventHandler::create(self);
  935. return YES;
  936. }
  937. // FIXME: This method is an ideal candidate to move up to the base class
  938. - (CALayer *)pluginLayer
  939. {
  940. return _pluginLayer.get();
  941. }
  942. - (void)setLayer:(CALayer *)newLayer
  943. {
  944. [super setLayer:newLayer];
  945. if (newLayer && _pluginLayer) {
  946. _pluginLayer.get().frame = [newLayer frame];
  947. _pluginLayer.get().autoresizingMask = kCALayerWidthSizable | kCALayerHeightSizable;
  948. [newLayer addSublayer:_pluginLayer.get()];
  949. }
  950. }
  951. - (void)loadStream
  952. {
  953. if ([self _shouldCancelSrcStream])
  954. return;
  955. if (_loadManually) {
  956. [self _redeliverStream];
  957. return;
  958. }
  959. // If the OBJECT/EMBED tag has no SRC, the URL is passed to us as "".
  960. // Check for this and don't start a load in this case.
  961. if (_sourceURL && ![_sourceURL.get() _web_isEmpty]) {
  962. NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:_sourceURL.get()];
  963. [request _web_setHTTPReferrer:core([self webFrame])->loader()->outgoingReferrer()];
  964. [self loadRequest:request inTarget:nil withNotifyData:nil sendNotification:NO];
  965. }
  966. }
  967. - (BOOL)shouldStop
  968. {
  969. // If we're already calling a plug-in function, do not call NPP_Destroy(). The plug-in function we are calling
  970. // may assume that its instance->pdata, or other memory freed by NPP_Destroy(), is valid and unchanged until said
  971. // plugin-function returns.
  972. // See <rdar://problem/4480737>.
  973. if (pluginFunctionCallDepth > 0) {
  974. shouldStopSoon = YES;
  975. return NO;
  976. }
  977. return YES;
  978. }
  979. - (void)destroyPlugin
  980. {
  981. // To stop active streams it's necessary to invoke stop() on a copy
  982. // of streams. This is because calling WebNetscapePluginStream::stop() also has the side effect
  983. // of removing a stream from this hash set.
  984. Vector<RefPtr<WebNetscapePluginStream> > streamsCopy;
  985. copyToVector(streams, streamsCopy);
  986. for (size_t i = 0; i < streamsCopy.size(); i++)
  987. streamsCopy[i]->stop();
  988. for (WebFrame *frame in [_pendingFrameLoads keyEnumerator])
  989. [frame _setInternalLoadDelegate:nil];
  990. [NSObject cancelPreviousPerformRequestsWithTarget:self];
  991. // Setting the window type to 0 ensures that NPP_SetWindow will be called if the plug-in is restarted.
  992. lastSetWindow.type = (NPWindowType)0;
  993. _pluginLayer = 0;
  994. [self _destroyPlugin];
  995. [_pluginPackage.get() close];
  996. _eventHandler.clear();
  997. }
  998. - (NPEventModel)eventModel
  999. {
  1000. return eventModel;
  1001. }
  1002. - (NPP)plugin
  1003. {
  1004. return plugin;
  1005. }
  1006. - (void)setAttributeKeys:(NSArray *)keys andValues:(NSArray *)values
  1007. {
  1008. ASSERT([keys count] == [values count]);
  1009. // Convert the attributes to 2 C string arrays.
  1010. // These arrays are passed to NPP_New, but the strings need to be
  1011. // modifiable and live the entire life of the plugin.
  1012. // The Java plug-in requires the first argument to be the base URL
  1013. if ([_MIMEType.get() isEqualToString:@"application/x-java-applet"]) {
  1014. cAttributes = (char **)malloc(([keys count] + 1) * sizeof(char *));
  1015. cValues = (char **)malloc(([values count] + 1) * sizeof(char *));
  1016. cAttributes[0] = strdup("DOCBASE");
  1017. cValues[0] = strdup([_baseURL.get() _web_URLCString]);
  1018. argsCount++;
  1019. } else {
  1020. cAttributes = (char **)malloc([keys count] * sizeof(char *));
  1021. cValues = (char **)malloc([values count] * sizeof(char *));
  1022. }
  1023. BOOL isWMP = [_pluginPackage.get() bundleIdentifier] == "com.microsoft.WMP.defaultplugin";
  1024. unsigned i;
  1025. unsigned count = [keys count];
  1026. for (i = 0; i < count; i++) {
  1027. NSString *key = [keys objectAtIndex:i];
  1028. NSString *value = [values objectAtIndex:i];
  1029. if ([key _webkit_isCaseInsensitiveEqualToString:@"height"]) {
  1030. specifiedHeight = [value intValue];
  1031. } else if ([key _webkit_isCaseInsensitiveEqualToString:@"width"]) {
  1032. specifiedWidth = [value intValue];
  1033. }
  1034. // Avoid Window Media Player crash when these attributes are present.
  1035. if (isWMP && ([key _webkit_isCaseInsensitiveEqualToString:@"SAMIStyle"] || [key _webkit_isCaseInsensitiveEqualToString:@"SAMILang"])) {
  1036. continue;
  1037. }
  1038. cAttributes[argsCount] = strdup([key UTF8String]);
  1039. cValues[argsCount] = strdup([value UTF8String]);
  1040. LOG(Plugins, "%@ = %@", key, value);
  1041. argsCount++;
  1042. }
  1043. }
  1044. - (uint32_t)checkIfAllowedToLoadURL:(const char*)urlCString frame:(const char*)frameNameCString
  1045. callbackFunc:(void (*)(NPP npp, uint32_t checkID, NPBool allowed, void* context))callbackFunc
  1046. context:(void*)context
  1047. {
  1048. if (!_containerChecksInProgress)
  1049. _containerChecksInProgress = [[NSMutableDictionary alloc] init];
  1050. NSString *frameName = frameNameCString ? [NSString stringWithCString:frameNameCString encoding:NSISOLatin1StringEncoding] : nil;
  1051. ++_currentContainerCheckRequestID;
  1052. WebNetscapeContainerCheckContextInfo *contextInfo = [[WebNetscapeContainerCheckContextInfo alloc] initWithCheckRequestID:_currentContainerCheckRequestID
  1053. callbackFunc:callbackFunc
  1054. context:context];
  1055. WebPluginContainerCheck *check = [WebPluginContainerCheck checkWithRequest:[self requestWithURLCString:urlCString]
  1056. target:frameName
  1057. resultObject:self
  1058. selector:@selector(_containerCheckResult:contextInfo:)
  1059. controller:self
  1060. contextInfo:contextInfo];
  1061. [contextInfo release];
  1062. [_containerChecksInProgress setObject:check forKey:[NSNumber numberWithInt:_currentContainerCheckRequestID]];
  1063. [check start];
  1064. return _currentContainerCheckRequestID;
  1065. }
  1066. - (void)_containerCheckResult:(PolicyAction)policy contextInfo:(id)contextInfo
  1067. {
  1068. ASSERT([contextInfo isKindOfClass:[WebNetscapeContainerCheckContextInfo class]]);
  1069. void (*pluginCallback)(NPP npp, uint32_t, NPBool, void*) = [contextInfo callback];
  1070. if (!pluginCallback) {
  1071. ASSERT_NOT_REACHED();
  1072. return;
  1073. }
  1074. pluginCallback([self plugin], [contextInfo checkRequestID], (policy == PolicyUse), [contextInfo context]);
  1075. }
  1076. - (void)cancelCheckIfAllowedToLoadURL:(uint32_t)checkID
  1077. {
  1078. WebPluginContainerCheck *check = (WebPluginContainerCheck *)[_containerChecksInProgress objectForKey:[NSNumber numberWithInt:checkID]];
  1079. if (!check)
  1080. return;
  1081. [check cancel];
  1082. [_containerChecksInProgress removeObjectForKey:[NSNumber numberWithInt:checkID]];
  1083. }
  1084. // WebPluginContainerCheck automatically calls this method after invoking our _containerCheckResult: selector.
  1085. // It works this way because calling -[WebPluginContainerCheck cancel] allows it to do it's teardown process.
  1086. - (void)_webPluginContainerCancelCheckIfAllowedToLoadRequest:(id)webPluginContainerCheck
  1087. {
  1088. ASSERT([webPluginContainerCheck isKindOfClass:[WebPluginContainerCheck class]]);
  1089. WebPluginContainerCheck *check = (WebPluginContainerCheck *)webPluginContainerCheck;
  1090. ASSERT([[check contextInfo] isKindOfClass:[WebNetscapeContainerCheckContextInfo class]]);
  1091. [self cancelCheckIfAllowedToLoadURL:[[check contextInfo] checkRequestID]];
  1092. }
  1093. // MARK: NSVIEW
  1094. - (id)initWithFrame:(NSRect)frame
  1095. pluginPackage:(WebNetscapePluginPackage *)pluginPackage
  1096. URL:(NSURL *)URL
  1097. baseURL:(NSURL *)baseURL
  1098. MIMEType:(NSString *)MIME
  1099. attributeKeys:(NSArray *)keys
  1100. attributeValues:(NSArray *)values
  1101. loadManually:(BOOL)loadManually
  1102. element:(PassRefPtr<WebCore::HTMLPlugInElement>)element
  1103. {
  1104. self = [super initWithFrame:frame pluginPackage:pluginPackage URL:URL baseURL:baseURL MIMEType:MIME attributeKeys:keys attributeValues:values loadManually:loadManually element:element];
  1105. if (!self)
  1106. return nil;
  1107. _pendingFrameLoads = adoptNS([[NSMapTable alloc] initWithKeyOptions:NSPointerFunctionsStrongMemory valueOptions:NSPointerFunctionsStrongMemory capacity:0]);
  1108. // load the plug-in if it is not already loaded
  1109. if (![pluginPackage load]) {
  1110. [self release];
  1111. return nil;
  1112. }
  1113. return self;
  1114. }
  1115. - (id)initWithFrame:(NSRect)frame
  1116. {
  1117. ASSERT_NOT_REACHED();
  1118. return nil;
  1119. }
  1120. - (void)fini
  1121. {
  1122. #ifndef NP_NO_QUICKDRAW
  1123. if (offscreenGWorld)
  1124. DisposeGWorld(offscreenGWorld);
  1125. #endif
  1126. for (unsigned i = 0; i < argsCount; i++) {
  1127. free(cAttributes[i]);
  1128. free(cValues[i]);
  1129. }
  1130. free(cAttributes);
  1131. free(cValues);
  1132. ASSERT(!_eventHandler);
  1133. if (timers) {
  1134. deleteAllValues(*timers);
  1135. delete timers;
  1136. }
  1137. [_containerChecksInProgress release];
  1138. }
  1139. - (void)disconnectStream:(WebNetscapePluginStream*)stream
  1140. {
  1141. streams.remove(stream);
  1142. }
  1143. - (void)dealloc
  1144. {
  1145. ASSERT(!_isStarted);
  1146. ASSERT(!plugin);
  1147. [self fini];
  1148. [super dealloc];
  1149. }
  1150. - (void)finalize
  1151. {
  1152. ASSERT_MAIN_THREAD();
  1153. ASSERT(!_isStarted);
  1154. [self fini];
  1155. [super finalize];
  1156. }
  1157. - (void)drawRect:(NSRect)rect
  1158. {
  1159. if (_cachedSnapshot) {
  1160. NSRect sourceRect = { NSZeroPoint, [_cachedSnapshot.get() size] };
  1161. [_cachedSnapshot.get() drawInRect:[self bounds] fromRect:sourceRect operation:NSCompositeSourceOver fraction:1];
  1162. return;
  1163. }
  1164. if (drawingModel == NPDrawingModelCoreAnimation && (!_snapshotting || ![self supportsSnapshotting]))
  1165. return;
  1166. if (!_isStarted)
  1167. return;
  1168. if ([NSGraphicsContext currentContextDrawingToScreen] || _isFlash)
  1169. [self sendDrawRectEvent:rect];
  1170. else {
  1171. NSBitmapImageRep *printedPluginBitmap = [self _printedPluginBitmap];
  1172. if (printedPluginBitmap) {
  1173. // Flip the bitmap before drawing because the QuickDraw port is flipped relative
  1174. // to this view.
  1175. CGContextRef cgContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
  1176. CGContextSaveGState(cgContext);
  1177. NSRect bounds = [self bounds];
  1178. CGContextTranslateCTM(cgContext, 0.0f, NSHeight(bounds));
  1179. CGContextScaleCTM(cgContext, 1.0f, -1.0f);
  1180. [printedPluginBitmap drawInRect:bounds];
  1181. CGContextRestoreGState(cgContext);
  1182. }
  1183. }
  1184. }
  1185. - (NPObject *)createPluginScriptableObject
  1186. {
  1187. if (![_pluginPackage.get() pluginFuncs]->getvalue || !_isStarted)
  1188. return NULL;
  1189. NPObject *value = NULL;
  1190. NPError error;
  1191. [self willCallPlugInFunction];
  1192. {
  1193. JSC::JSLock::DropAllLocks dropAllLocks(JSDOMWindowBase::commonVM());
  1194. error = [_pluginPackage.get() pluginFuncs]->getvalue(plugin, NPPVpluginScriptableNPObject, &value);
  1195. }
  1196. [self didCallPlugInFunction];
  1197. if (error != NPERR_NO_ERROR)
  1198. return NULL;
  1199. return value;
  1200. }
  1201. - (BOOL)getFormValue:(NSString **)value
  1202. {
  1203. if (![_pluginPackage.get() pluginFuncs]->getvalue || !_isStarted)
  1204. return false;
  1205. // Plugins will allocate memory for the buffer by using NPN_MemAlloc().
  1206. char* buffer = NULL;
  1207. NPError error;
  1208. [self willCallPlugInFunction];
  1209. {
  1210. JSC::JSLock::DropAllLocks dropAllLocks(JSDOMWindowBase::commonVM());
  1211. error = [_pluginPackage.get() pluginFuncs]->getvalue(plugin, NPPVformValue, &buffer);
  1212. }
  1213. [self didCallPlugInFunction];
  1214. if (error != NPERR_NO_ERROR || !buffer)
  1215. return false;
  1216. *value = [[NSString alloc] initWithUTF8String:buffer];
  1217. [_pluginPackage.get() browserFuncs]->memfree(buffer);
  1218. return true;
  1219. }
  1220. - (void)willCallPlugInFunction
  1221. {
  1222. ASSERT(plugin);
  1223. // Could try to prevent infinite recursion here, but it's probably not worth the effort.
  1224. pluginFunctionCallDepth++;
  1225. }
  1226. - (void)didCallPlugInFunction
  1227. {
  1228. ASSERT(pluginFunctionCallDepth > 0);
  1229. pluginFunctionCallDepth--;
  1230. // If -stop was called while we were calling into a plug-in function, and we're no longer
  1231. // inside a plug-in function, stop now.
  1232. if (pluginFunctionCallDepth == 0 && shouldStopSoon) {
  1233. shouldStopSoon = NO;
  1234. [self stop];
  1235. }
  1236. }
  1237. -(void)pluginView:(NSView *)pluginView receivedResponse:(NSURLResponse *)response
  1238. {
  1239. ASSERT(_loadManually);
  1240. ASSERT(!_manualStream);
  1241. _manualStream = WebNetscapePluginStream::create(core([self webFrame])->loader());
  1242. }
  1243. - (void)pluginView:(NSView *)pluginView receivedData:(NSData *)data
  1244. {
  1245. ASSERT(_loadManually);
  1246. ASSERT(_manualStream);
  1247. _dataLengthReceived += [data length];
  1248. if (!_isStarted)
  1249. return;
  1250. if (!_manualStream->plugin()) {
  1251. // Check if the load should be cancelled
  1252. if ([self _shouldCancelSrcStream]) {
  1253. NSURLResponse *response = [[self dataSource] response];
  1254. NSError *error = [[NSError alloc] _initWithPluginErrorCode:WebKitErrorPlugInWillHandleLoad
  1255. contentURL:[response URL]
  1256. pluginPageURL:nil
  1257. pluginName:nil // FIXME: Get this from somewhere
  1258. MIMEType:[response MIMEType]];
  1259. [[self dataSource] _documentLoader]->cancelMainResourceLoad(error);
  1260. [error release];
  1261. return;
  1262. }
  1263. _manualStream->setRequestURL([[[self dataSource] request] URL]);
  1264. _manualStream->setPlugin([self plugin]);
  1265. ASSERT(_manualStream->plugin());
  1266. _manualStream->startStreamWithResponse([[self dataSource] response]);
  1267. }
  1268. if (_manualStream->plugin())
  1269. _manualStream->didReceiveData(0, static_cast<const char *>([data bytes]), [data length]);
  1270. }
  1271. - (void)pluginView:(NSView *)pluginView receivedError:(NSError *)error
  1272. {
  1273. ASSERT(_loadManually);
  1274. _error = error;
  1275. if (!_isStarted) {
  1276. return;
  1277. }
  1278. _manualStream->destroyStreamWithError(error);
  1279. }
  1280. - (void)pluginViewFinishedLoading:(NSView *)pluginView
  1281. {
  1282. ASSERT(_loadManually);
  1283. ASSERT(_manualStream);
  1284. if (_isStarted)
  1285. _manualStream->didFinishLoading(0);
  1286. }
  1287. - (NSTextInputContext *)inputContext
  1288. {
  1289. return nil;
  1290. }
  1291. @end
  1292. @implementation WebNetscapePluginView (WebNPPCallbacks)
  1293. - (void)evaluateJavaScriptPluginRequest:(WebPluginRequest *)JSPluginRequest
  1294. {
  1295. // FIXME: Is this isStarted check needed here? evaluateJavaScriptPluginRequest should not be called
  1296. // if we are stopped since this method is called after a delay and we call
  1297. // cancelPreviousPerformRequestsWithTarget inside of stop.
  1298. if (!_isStarted) {
  1299. return;
  1300. }
  1301. NSURL *URL = [[JSPluginRequest request] URL];
  1302. NSString *JSString = [URL _webkit_scriptIfJavaScriptURL];
  1303. ASSERT(JSString);
  1304. NSString *result = [[self webFrame] _stringByEvaluatingJavaScriptFromString:JSString forceUserGesture:[JSPluginRequest isCurrentEventUserGesture]];
  1305. // Don't continue if stringByEvaluatingJavaScriptFromString caused the plug-in to stop.
  1306. if (!_isStarted) {
  1307. return;
  1308. }
  1309. if ([JSPluginRequest frameName] != nil) {
  1310. // FIXME: If the result is a string, we probably want to put that string into the frame.
  1311. if ([JSPluginRequest sendNotification]) {
  1312. [self willCallPlugInFunction];
  1313. {
  1314. JSC::JSLock::DropAllLocks dropAllLocks(JSDOMWindowBase::commonVM());
  1315. [_pluginPackage.get() pluginFuncs]->urlnotify(plugin, [URL _web_URLCString], NPRES_DONE, [JSPluginRequest notifyData]);
  1316. }
  1317. [self didCallPlugInFunction];
  1318. }
  1319. } else if ([result length] > 0) {
  1320. // Don't call NPP_NewStream and other stream methods if there is no JS result to deliver. This is what Mozilla does.
  1321. NSData *JSData = [result dataUsingEncoding:NSUTF8StringEncoding];
  1322. RefPtr<WebNetscapePluginStream> stream = WebNetscapePluginStream::create([NSURLRequest requestWithURL:URL], plugin, [JSPluginRequest sendNotification], [JSPluginRequest notifyData]);
  1323. RetainPtr<NSURLResponse> response = adoptNS([[NSURLResponse alloc] initWithURL:URL
  1324. MIMEType:@"text/plain"
  1325. expectedContentLength:[JSData length]
  1326. textEncodingName:nil]);
  1327. stream->startStreamWithResponse(response.get());
  1328. stream->didReceiveData(0, static_cast<const char*>([JSData bytes]), [JSData length]);
  1329. stream->didFinishLoading(0);
  1330. }
  1331. }
  1332. - (void)webFrame:(WebFrame *)webFrame didFinishLoadWithReason:(NPReason)reason
  1333. {
  1334. ASSERT(_isStarted);
  1335. WebPluginRequest *pluginRequest = [_pendingFrameLoads objectForKey:webFrame];
  1336. ASSERT(pluginRequest != nil);
  1337. ASSERT([pluginRequest sendNotification]);
  1338. [self willCallPlugInFunction];
  1339. {
  1340. JSC::JSLock::DropAllLocks dropAllLocks(JSDOMWindowBase::commonVM());
  1341. [_pluginPackage.get() pluginFuncs]->urlnotify(plugin, [[[pluginRequest request] URL] _web_URLCString], reason, [pluginRequest notifyData]);
  1342. }
  1343. [self didCallPlugInFunction];
  1344. [_pendingFrameLoads removeObjectForKey:webFrame];
  1345. [webFrame _setInternalLoadDelegate:nil];
  1346. }
  1347. - (void)webFrame:(WebFrame *)webFrame didFinishLoadWithError:(NSError *)error
  1348. {
  1349. NPReason reason = NPRES_DONE;
  1350. if (error != nil)
  1351. reason = WebNetscapePluginStream::reasonForError(error);
  1352. [self webFrame:webFrame didFinishLoadWithReason:reason];
  1353. }
  1354. - (void)loadPluginRequest:(WebPluginRequest *)pluginRequest
  1355. {
  1356. NSURLRequest *request = [pluginRequest request];
  1357. NSString *frameName = [pluginRequest frameName];
  1358. WebFrame *frame = nil;
  1359. NSURL *URL = [request URL];
  1360. NSString *JSString = [URL _webkit_scriptIfJavaScriptURL];
  1361. ASSERT(frameName || JSString);
  1362. if (frameName) {
  1363. // FIXME - need to get rid of this window creation which
  1364. // bypasses normal targeted link handling
  1365. frame = kit(core([self webFrame])->loader()->findFrameForNavigation(frameName));
  1366. if (frame == nil) {
  1367. WebView *currentWebView = [self webView];
  1368. NSDictionary *features = [[NSDictionary alloc] init];
  1369. WebView *newWebView = [[currentWebView _UIDelegateForwarder] webView:currentWebView
  1370. createWebViewWithRequest:nil
  1371. windowFeatures:features];
  1372. [features release];
  1373. if (!newWebView) {
  1374. if ([pluginRequest sendNotification]) {
  1375. [self willCallPlugInFunction];
  1376. {
  1377. JSC::JSLock::DropAllLocks dropAllLocks(JSDOMWindowBase::commonVM());
  1378. [_pluginPackage.get() pluginFuncs]->urlnotify(plugin, [[[pluginRequest request] URL] _web_URLCString], NPERR_GENERIC_ERROR, [pluginRequest notifyData]);
  1379. }
  1380. [self didCallPlugInFunction];
  1381. }
  1382. return;
  1383. }
  1384. frame = [newWebView mainFrame];
  1385. core(frame)->tree()->setName(frameName);
  1386. [[newWebView _UIDelegateForwarder] webViewShow:newWebView];
  1387. }
  1388. }
  1389. if (JSString) {
  1390. ASSERT(frame == nil || [self webFrame] == frame);
  1391. [self evaluateJavaScriptPluginRequest:pluginRequest];
  1392. } else {
  1393. [frame loadRequest:request];
  1394. if ([pluginRequest sendNotification]) {
  1395. // Check if another plug-in view or even this view is waiting for the frame to load.
  1396. // If it is, tell it that the load was cancelled because it will be anyway.
  1397. WebNetscapePluginView *view = [frame _internalLoadDelegate];
  1398. if (view != nil) {
  1399. ASSERT([view isKindOfClass:[WebNetscapePluginView class]]);
  1400. [view webFrame:frame didFinishLoadWithReason:NPRES_USER_BREAK];
  1401. }
  1402. [_pendingFrameLoads setObject:pluginRequest forKey:frame];
  1403. [frame _setInternalLoadDelegate:self];
  1404. }
  1405. }
  1406. }
  1407. - (NPError)loadRequest:(NSMutableURLRequest *)request inTarget:(const char *)cTarget withNotifyData:(void *)notifyData sendNotification:(BOOL)sendNotification
  1408. {
  1409. NSURL *URL = [request URL];
  1410. if (!URL)
  1411. return NPERR_INVALID_URL;
  1412. // Don't allow requests to be loaded when the document loader is stopping all loaders.
  1413. if ([[self dataSource] _documentLoader]->isStopping())
  1414. return NPERR_GENERIC_ERROR;
  1415. NSString *target = nil;
  1416. if (cTarget) {
  1417. // Find the frame given the target string.
  1418. target = [NSString stringWithCString:cTarget encoding:NSISOLatin1StringEncoding];
  1419. }
  1420. WebFrame *frame = [self webFrame];
  1421. // don't let a plugin start any loads if it is no longer part of a document that is being
  1422. // displayed unless the loads are in the same frame as the plugin.
  1423. if ([[self dataSource] _documentLoader] != core([self webFrame])->loader()->activeDocumentLoader() &&
  1424. (!cTarget || [frame findFrameNamed:target] != frame)) {
  1425. return NPERR_GENERIC_ERROR;
  1426. }
  1427. NSString *JSString = [URL _webkit_scriptIfJavaScriptURL];
  1428. if (JSString != nil) {
  1429. if (![[[self webView] preferences] isJavaScriptEnabled]) {
  1430. // Return NPERR_GENERIC_ERROR if JS is disabled. This is what Mozilla does.
  1431. return NPERR_GENERIC_ERROR;
  1432. } else if (cTarget == NULL && _mode == NP_FULL) {
  1433. // Don't allow a JavaScript request from a standalone plug-in that is self-targetted
  1434. // because this can cause the user to be redirected to a blank page (3424039).
  1435. return NPERR_INVALID_PARAM;
  1436. }
  1437. } else {
  1438. if (!core([self webFrame])->document()->securityOrigin()->canDisplay(URL))
  1439. return NPERR_GENERIC_ERROR;
  1440. }
  1441. if (cTarget || JSString) {
  1442. // Make when targetting a frame or evaluating a JS string, perform the request after a delay because we don't
  1443. // want to potentially kill the plug-in inside of its URL request.
  1444. if (JSString && target && [frame findFrameNamed:target] != frame) {
  1445. // For security reasons, only allow JS requests to be made on the frame that contains the plug-in.
  1446. return NPERR_INVALID_PARAM;
  1447. }
  1448. bool currentEventIsUserGesture = false;
  1449. if (_eventHandler)
  1450. currentEventIsUserGesture = _eventHandler->currentEventIsUserGesture();
  1451. WebPluginRequest *pluginRequest = [[WebPluginRequest alloc] initWithRequest:request
  1452. frameName:target
  1453. notifyData:notifyData
  1454. sendNotification:sendNotification
  1455. didStartFromUserGesture:currentEventIsUserGesture];
  1456. [self performSelector:@selector(loadPluginRequest:) withObject:pluginRequest afterDelay:0];
  1457. [pluginRequest release];
  1458. } else {
  1459. RefPtr<WebNetscapePluginStream> stream = WebNetscapePluginStream::create(request, plugin, sendNotification, notifyData);
  1460. streams.add(stream.get());
  1461. stream->start();
  1462. }
  1463. return NPERR_NO_ERROR;
  1464. }
  1465. -(NPError)getURLNotify:(const char *)URLCString target:(const char *)cTarget notifyData:(void *)notifyData
  1466. {
  1467. LOG(Plugins, "NPN_GetURLNotify: %s target: %s", URLCString, cTarget);
  1468. NSMutableURLRequest *request = [self requestWithURLCString:URLCString];
  1469. return [self loadRequest:request inTarget:cTarget withNotifyData:notifyData sendNotification:YES];
  1470. }
  1471. -(NPError)getURL:(const char *)URLCString target:(const char *)cTarget
  1472. {
  1473. LOG(Plugins, "NPN_GetURL: %s target: %s", URLCString, cTarget);
  1474. NSMutableURLRequest *request = [self requestWithURLCString:URLCString];
  1475. return [self loadRequest:request inTarget:cTarget withNotifyData:NULL sendNotification:NO];
  1476. }
  1477. - (NPError)_postURL:(const char *)URLCString
  1478. target:(const char *)target
  1479. len:(UInt32)len
  1480. buf:(const char *)buf
  1481. file:(NPBool)file
  1482. notifyData:(void *)notifyData
  1483. sendNotification:(BOOL)sendNotification
  1484. allowHeaders:(BOOL)allowHeaders
  1485. {
  1486. if (!URLCString || !len || !buf) {
  1487. return NPERR_INVALID_PARAM;
  1488. }
  1489. NSData *postData = nil;
  1490. if (file) {
  1491. // If we're posting a file, buf is either a file URL or a path to the file.
  1492. NSString *bufString = (NSString *)CFStringCreateWithCString(kCFAllocatorDefault, buf, kCFStringEncodingWindowsLatin1);
  1493. if (!bufString) {
  1494. return NPERR_INVALID_PARAM;
  1495. }
  1496. NSURL *fileURL = [NSURL _web_URLWithDataAsString:bufString];
  1497. NSString *path;
  1498. if ([fileURL isFileURL]) {
  1499. path = [fileURL path];
  1500. } else {
  1501. path = bufString;
  1502. }
  1503. postData = [NSData dataWithContentsOfFile:[path _webkit_fixedCarbonPOSIXPath]];
  1504. CFRelease(bufString);
  1505. if (!postData) {
  1506. return NPERR_FILE_NOT_FOUND;
  1507. }
  1508. } else {
  1509. postData = [NSData dataWithBytes:buf length:len];
  1510. }
  1511. if ([postData length] == 0) {
  1512. return NPERR_INVALID_PARAM;
  1513. }
  1514. NSMutableURLRequest *request = [self requestWithURLCString:URLCString];
  1515. [request setHTTPMethod:@"POST"];
  1516. if (allowHeaders) {
  1517. if ([postData _web_startsWithBlankLine]) {
  1518. postData = [postData subdataWithRange:NSMakeRange(1, [postData length] - 1)];
  1519. } else {
  1520. NSInteger location = [postData _web_locationAfterFirstBlankLine];
  1521. if (location != NSNotFound) {
  1522. // If the blank line is somewhere in the middle of postData, everything before is the header.
  1523. NSData *headerData = [postData subdataWithRange:NSMakeRange(0, location)];
  1524. NSMutableDictionary *header = [headerData _webkit_parseRFC822HeaderFields];
  1525. unsigned dataLength = [postData length] - location;
  1526. // Sometimes plugins like to set Content-Length themselves when they post,
  1527. // but WebFoundation does not like that. So we will remove the header
  1528. // and instead truncate the data to the requested length.
  1529. NSString *contentLength = [header objectForKey:@"Content-Length"];
  1530. if (contentLength != nil)
  1531. dataLength = std::min<unsigned>([contentLength intValue], dataLength);
  1532. [header removeObjectForKey:@"Content-Length"];
  1533. if ([header count] > 0) {
  1534. [request setAllHTTPHeaderFields:header];
  1535. }
  1536. // Everything after the blank line is the actual content of the POST.
  1537. postData = [postData subdataWithRange:NSMakeRange(location, dataLength)];
  1538. }
  1539. }
  1540. if ([postData length] == 0) {
  1541. return NPERR_INVALID_PARAM;
  1542. }
  1543. }
  1544. // Plug-ins expect to receive uncached data when doing a POST (3347134).
  1545. [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
  1546. [request setHTTPBody:postData];
  1547. return [self loadRequest:request inTarget:target withNotifyData:notifyData sendNotification:sendNotification];
  1548. }
  1549. - (NPError)postURLNotify:(const char *)URLCString
  1550. target:(const char *)target
  1551. len:(UInt32)len
  1552. buf:(const char *)buf
  1553. file:(NPBool)file
  1554. notifyData:(void *)notifyData
  1555. {
  1556. LOG(Plugins, "NPN_PostURLNotify: %s", URLCString);
  1557. return [self _postURL:URLCString target:target len:len buf:buf file:file notifyData:notifyData sendNotification:YES allowHeaders:YES];
  1558. }
  1559. -(NPError)postURL:(const char *)URLCString
  1560. target:(const char *)target
  1561. len:(UInt32)len
  1562. buf:(const char *)buf
  1563. file:(NPBool)file
  1564. {
  1565. LOG(Plugins, "NPN_PostURL: %s", URLCString);
  1566. // As documented, only allow headers to be specified via NPP_PostURL when using a file.
  1567. return [self _postURL:URLCString target:target len:len buf:buf file:file notifyData:NULL sendNotification:NO allowHeaders:file];
  1568. }
  1569. -(NPError)newStream:(NPMIMEType)type target:(const char *)target stream:(NPStream**)stream
  1570. {
  1571. LOG(Plugins, "NPN_NewStream");
  1572. return NPERR_GENERIC_ERROR;
  1573. }
  1574. -(NPError)write:(NPStream*)stream len:(SInt32)len buffer:(void *)buffer
  1575. {
  1576. LOG(Plugins, "NPN_Write");
  1577. return NPERR_GENERIC_ERROR;
  1578. }
  1579. -(NPError)destroyStream:(NPStream*)stream reason:(NPReason)reason
  1580. {
  1581. LOG(Plugins, "NPN_DestroyStream");
  1582. // This function does a sanity check to ensure that the NPStream provided actually
  1583. // belongs to the plug-in that provided it, which fixes a crash in the DivX
  1584. // plug-in: <rdar://problem/5093862> | http://bugs.webkit.org/show_bug.cgi?id=13203
  1585. if (!stream || WebNetscapePluginStream::ownerForStream(stream) != plugin) {
  1586. LOG(Plugins, "Invalid NPStream passed to NPN_DestroyStream: %p", stream);
  1587. return NPERR_INVALID_INSTANCE_ERROR;
  1588. }
  1589. WebNetscapePluginStream* browserStream = static_cast<WebNetscapePluginStream*>(stream->ndata);
  1590. browserStream->cancelLoadAndDestroyStreamWithError(browserStream->errorForReason(reason));
  1591. return NPERR_NO_ERROR;
  1592. }
  1593. - (const char *)userAgent
  1594. {
  1595. NSString *userAgent = [[self webView] userAgentForURL:_baseURL.get()];
  1596. if (_isSilverlight) {
  1597. // Silverlight has a workaround for a leak in Safari 2. This workaround is
  1598. // applied when the user agent does not contain "Version/3" so we append it
  1599. // at the end of the user agent.
  1600. userAgent = [userAgent stringByAppendingString:@" Version/3.2.1"];
  1601. }
  1602. return [userAgent UTF8String];
  1603. }
  1604. -(void)status:(const char *)message
  1605. {
  1606. CFStringRef status = CFStringCreateWithCString(NULL, message ? message : "", kCFStringEncodingUTF8);
  1607. if (!status) {
  1608. LOG_ERROR("NPN_Status: the message was not valid UTF-8");
  1609. return;
  1610. }
  1611. LOG(Plugins, "NPN_Status: %@", status);
  1612. WebView *wv = [self webView];
  1613. [[wv _UIDelegateForwarder] webView:wv setStatusText:(NSString *)status];
  1614. CFRelease(status);
  1615. }
  1616. -(void)invalidateRect:(NPRect *)invalidRect
  1617. {
  1618. LOG(Plugins, "NPN_InvalidateRect");
  1619. [self invalidatePluginContentRect:NSMakeRect(invalidRect->left, invalidRect->top,
  1620. (float)invalidRect->right - invalidRect->left, (float)invalidRect->bottom - invalidRect->top)];
  1621. }
  1622. - (void)invalidateRegion:(NPRegion)invalidRegion
  1623. {
  1624. LOG(Plugins, "NPN_InvalidateRegion");
  1625. NSRect invalidRect = NSZeroRect;
  1626. switch (drawingModel) {
  1627. #ifndef NP_NO_QUICKDRAW
  1628. case NPDrawingModelQuickDraw:
  1629. {
  1630. ::Rect qdRect;
  1631. GetRegionBounds((NPQDRegion)invalidRegion, &qdRect);
  1632. invalidRect = NSMakeRect(qdRect.left, qdRect.top, qdRect.right - qdRect.left, qdRect.bottom - qdRect.top);
  1633. }
  1634. break;
  1635. #endif /* NP_NO_QUICKDRAW */
  1636. case NPDrawingModelCoreGraphics:
  1637. {
  1638. CGRect cgRect = CGPathGetBoundingBox((NPCGRegion)invalidRegion);
  1639. invalidRect = *(NSRect*)&cgRect;
  1640. break;
  1641. }
  1642. default:
  1643. ASSERT_NOT_REACHED();
  1644. break;
  1645. }
  1646. [self invalidatePluginContentRect:invalidRect];
  1647. }
  1648. -(void)forceRedraw
  1649. {
  1650. LOG(Plugins, "forceRedraw");
  1651. [self invalidatePluginContentRect:[self bounds]];
  1652. [[self window] displayIfNeeded];
  1653. }
  1654. - (NPError)getVariable:(NPNVariable)variable value:(void *)value
  1655. {
  1656. switch (static_cast<unsigned>(variable)) {
  1657. case NPNVWindowNPObject:
  1658. {
  1659. Frame* frame = core([self webFrame]);
  1660. NPObject* windowScriptObject = frame ? frame->script()->windowScriptNPObject() : 0;
  1661. // Return value is expected to be retained, as described here: <http://www.mozilla.org/projects/plugins/npruntime.html#browseraccess>
  1662. if (windowScriptObject)
  1663. _NPN_RetainObject(windowScriptObject);
  1664. void **v = (void **)value;
  1665. *v = windowScriptObject;
  1666. return NPERR_NO_ERROR;
  1667. }
  1668. case NPNVPluginElementNPObject:
  1669. {
  1670. if (!_element)
  1671. return NPERR_GENERIC_ERROR;
  1672. NPObject *plugInScriptObject = _element->getNPObject();
  1673. // Return value is expected to be retained, as described here: <http://www.mozilla.org/projects/plugins/npruntime.html#browseraccess>
  1674. if (plugInScriptObject)
  1675. _NPN_RetainObject(plugInScriptObject);
  1676. void **v = (void **)value;
  1677. *v = plugInScriptObject;
  1678. return NPERR_NO_ERROR;
  1679. }
  1680. case NPNVpluginDrawingModel:
  1681. {
  1682. *(NPDrawingModel *)value = drawingModel;
  1683. return NPERR_NO_ERROR;
  1684. }
  1685. #ifndef NP_NO_QUICKDRAW
  1686. case NPNVsupportsQuickDrawBool:
  1687. {
  1688. *(NPBool *)value = TRUE;
  1689. return NPERR_NO_ERROR;
  1690. }
  1691. #endif /* NP_NO_QUICKDRAW */
  1692. case NPNVsupportsCoreGraphicsBool:
  1693. {
  1694. *(NPBool *)value = TRUE;
  1695. return NPERR_NO_ERROR;
  1696. }
  1697. case NPNVsupportsOpenGLBool:
  1698. {
  1699. *(NPBool *)value = FALSE;
  1700. return NPERR_NO_ERROR;
  1701. }
  1702. case NPNVsupportsCoreAnimationBool:
  1703. {
  1704. *(NPBool *)value = TRUE;
  1705. return NPERR_NO_ERROR;
  1706. }
  1707. #ifndef NP_NO_CARBON
  1708. case NPNVsupportsCarbonBool:
  1709. {
  1710. *(NPBool *)value = TRUE;
  1711. return NPERR_NO_ERROR;
  1712. }
  1713. #endif /* NP_NO_CARBON */
  1714. case NPNVsupportsCocoaBool:
  1715. {
  1716. *(NPBool *)value = TRUE;
  1717. return NPERR_NO_ERROR;
  1718. }
  1719. case NPNVprivateModeBool:
  1720. {
  1721. *(NPBool *)value = _isPrivateBrowsingEnabled;
  1722. return NPERR_NO_ERROR;
  1723. }
  1724. case WKNVBrowserContainerCheckFuncs:
  1725. {
  1726. *(WKNBrowserContainerCheckFuncs **)value = browserContainerCheckFuncs();
  1727. return NPERR_NO_ERROR;
  1728. }
  1729. #if USE(ACCELERATED_COMPOSITING)
  1730. case WKNVSupportsCompositingCoreAnimationPluginsBool:
  1731. {
  1732. *(NPBool *)value = [[[self webView] preferences] acceleratedCompositingEnabled];
  1733. return NPERR_NO_ERROR;
  1734. }
  1735. #endif
  1736. default:
  1737. break;
  1738. }
  1739. return NPERR_GENERIC_ERROR;
  1740. }
  1741. - (NPError)setVariable:(NPPVariable)variable value:(void *)value
  1742. {
  1743. switch (variable) {
  1744. case NPPVpluginDrawingModel:
  1745. {
  1746. // Can only set drawing model inside NPP_New()
  1747. if (self != [[self class] currentPluginView])
  1748. return NPERR_GENERIC_ERROR;
  1749. // Check for valid, supported drawing model
  1750. NPDrawingModel newDrawingModel = (NPDrawingModel)(uintptr_t)value;
  1751. switch (newDrawingModel) {
  1752. // Supported drawing models:
  1753. #ifndef NP_NO_QUICKDRAW
  1754. case NPDrawingModelQuickDraw:
  1755. #endif
  1756. case NPDrawingModelCoreGraphics:
  1757. case NPDrawingModelCoreAnimation:
  1758. drawingModel = newDrawingModel;
  1759. return NPERR_NO_ERROR;
  1760. // Unsupported (or unknown) drawing models:
  1761. default:
  1762. LOG(Plugins, "Plugin %@ uses unsupported drawing model: %d", _eventHandler.get(), drawingModel);
  1763. return NPERR_GENERIC_ERROR;
  1764. }
  1765. }
  1766. case NPPVpluginEventModel:
  1767. {
  1768. // Can only set event model inside NPP_New()
  1769. if (self != [[self class] currentPluginView])
  1770. return NPERR_GENERIC_ERROR;
  1771. // Check for valid, supported event model
  1772. NPEventModel newEventModel = (NPEventModel)(uintptr_t)value;
  1773. switch (newEventModel) {
  1774. // Supported event models:
  1775. #ifndef NP_NO_CARBON
  1776. case NPEventModelCarbon:
  1777. #endif
  1778. case NPEventModelCocoa:
  1779. eventModel = newEventModel;
  1780. return NPERR_NO_ERROR;
  1781. // Unsupported (or unknown) event models:
  1782. default:
  1783. LOG(Plugins, "Plugin %@ uses unsupported event model: %d", _eventHandler.get(), eventModel);
  1784. return NPERR_GENERIC_ERROR;
  1785. }
  1786. }
  1787. default:
  1788. return NPERR_GENERIC_ERROR;
  1789. }
  1790. }
  1791. - (uint32_t)scheduleTimerWithInterval:(uint32_t)interval repeat:(NPBool)repeat timerFunc:(void (*)(NPP npp, uint32_t timerID))timerFunc
  1792. {
  1793. if (!timerFunc)
  1794. return 0;
  1795. if (!timers)
  1796. timers = new HashMap<uint32_t, PluginTimer*>;
  1797. uint32_t timerID;
  1798. do {
  1799. timerID = ++currentTimerID;
  1800. } while (timers->contains(timerID) || timerID == 0);
  1801. PluginTimer* timer = new PluginTimer(plugin, timerID, interval, repeat, timerFunc);
  1802. timers->set(timerID, timer);
  1803. if (_shouldFireTimers)
  1804. timer->start(_isCompletelyObscured);
  1805. return timerID;
  1806. }
  1807. - (void)unscheduleTimer:(uint32_t)timerID
  1808. {
  1809. if (!timers)
  1810. return;
  1811. if (PluginTimer* timer = timers->take(timerID))
  1812. delete timer;
  1813. }
  1814. - (NPError)popUpContextMenu:(NPMenu *)menu
  1815. {
  1816. NSEvent *currentEvent = [NSApp currentEvent];
  1817. // NPN_PopUpContextMenu must be called from within the plug-in's NPP_HandleEvent.
  1818. if (!currentEvent)
  1819. return NPERR_GENERIC_ERROR;
  1820. [NSMenu popUpContextMenu:(NSMenu *)menu withEvent:currentEvent forView:self];
  1821. return NPERR_NO_ERROR;
  1822. }
  1823. - (NPError)getVariable:(NPNURLVariable)variable forURL:(const char*)url value:(char**)value length:(uint32_t*)length
  1824. {
  1825. switch (variable) {
  1826. case NPNURLVCookie: {
  1827. if (!value)
  1828. break;
  1829. NSURL *URL = [self URLWithCString:url];
  1830. if (!URL)
  1831. break;
  1832. if (Frame* frame = core([self webFrame])) {
  1833. String cookieString = cookies(frame->document(), URL);
  1834. CString cookieStringUTF8 = cookieString.utf8();
  1835. if (cookieStringUTF8.isNull())
  1836. return NPERR_GENERIC_ERROR;
  1837. *value = static_cast<char*>(NPN_MemAlloc(cookieStringUTF8.length()));
  1838. memcpy(*value, cookieStringUTF8.data(), cookieStringUTF8.length());
  1839. if (length)
  1840. *length = cookieStringUTF8.length();
  1841. return NPERR_NO_ERROR;
  1842. }
  1843. break;
  1844. }
  1845. case NPNURLVProxy: {
  1846. if (!value)
  1847. break;
  1848. NSURL *URL = [self URLWithCString:url];
  1849. if (!URL)
  1850. break;
  1851. Vector<ProxyServer> proxyServers = proxyServersForURL(URL, 0);
  1852. CString proxiesUTF8 = toString(proxyServers).utf8();
  1853. *value = static_cast<char*>(NPN_MemAlloc(proxiesUTF8.length()));
  1854. memcpy(*value, proxiesUTF8.data(), proxiesUTF8.length());
  1855. if (length)
  1856. *length = proxiesUTF8.length();
  1857. return NPERR_NO_ERROR;
  1858. }
  1859. }
  1860. return NPERR_GENERIC_ERROR;
  1861. }
  1862. - (NPError)setVariable:(NPNURLVariable)variable forURL:(const char*)url value:(const char*)value length:(uint32_t)length
  1863. {
  1864. switch (variable) {
  1865. case NPNURLVCookie: {
  1866. NSURL *URL = [self URLWithCString:url];
  1867. if (!URL)
  1868. break;
  1869. String cookieString = String::fromUTF8(value, length);
  1870. if (!cookieString)
  1871. break;
  1872. if (Frame* frame = core([self webFrame])) {
  1873. setCookies(frame->document(), URL, cookieString);
  1874. return NPERR_NO_ERROR;
  1875. }
  1876. break;
  1877. }
  1878. case NPNURLVProxy:
  1879. // Can't set the proxy for a URL.
  1880. break;
  1881. }
  1882. return NPERR_GENERIC_ERROR;
  1883. }
  1884. - (NPError)getAuthenticationInfoWithProtocol:(const char*)protocolStr host:(const char*)hostStr port:(int32_t)port scheme:(const char*)schemeStr realm:(const char*)realmStr
  1885. username:(char**)usernameStr usernameLength:(uint32_t*)usernameLength
  1886. password:(char**)passwordStr passwordLength:(uint32_t*)passwordLength
  1887. {
  1888. if (!protocolStr || !hostStr || !schemeStr || !realmStr || !usernameStr || !usernameLength || !passwordStr || !passwordLength)
  1889. return NPERR_GENERIC_ERROR;
  1890. CString username;
  1891. CString password;
  1892. if (!getAuthenticationInfo(protocolStr, hostStr, port, schemeStr, realmStr, username, password))
  1893. return NPERR_GENERIC_ERROR;
  1894. *usernameLength = username.length();
  1895. *usernameStr = static_cast<char*>(NPN_MemAlloc(username.length()));
  1896. memcpy(*usernameStr, username.data(), username.length());
  1897. *passwordLength = password.length();
  1898. *passwordStr = static_cast<char*>(NPN_MemAlloc(password.length()));
  1899. memcpy(*passwordStr, password.data(), password.length());
  1900. return NPERR_NO_ERROR;
  1901. }
  1902. - (char*)resolveURL:(const char*)url forTarget:(const char*)target
  1903. {
  1904. CString location = [self resolvedURLStringForURL:url target:target];
  1905. if (location.isNull())
  1906. return 0;
  1907. // We use strdup here because the caller needs to free it with NPN_MemFree (which calls free).
  1908. return strdup(location.data());
  1909. }
  1910. @end
  1911. @implementation WebNetscapePluginView (Internal)
  1912. - (BOOL)_shouldCancelSrcStream
  1913. {
  1914. ASSERT(_isStarted);
  1915. // Check if we should cancel the load
  1916. NPBool cancelSrcStream = 0;
  1917. if ([_pluginPackage.get() pluginFuncs]->getvalue &&
  1918. [_pluginPackage.get() pluginFuncs]->getvalue(plugin, NPPVpluginCancelSrcStream, &cancelSrcStream) == NPERR_NO_ERROR && cancelSrcStream)
  1919. return YES;
  1920. return NO;
  1921. }
  1922. // Work around Silverlight full screen performance issue by maintaining an accelerated GL pixel format.
  1923. // We can safely remove it at some point in the future when both:
  1924. // 1) Microsoft releases a genuine fix for 7288546.
  1925. // 2) Enough Silverlight users update to the new Silverlight.
  1926. // For now, we'll distinguish older broken versions of Silverlight by asking the plug-in if it resolved its full screen badness.
  1927. - (void)_workaroundSilverlightFullscreenBug:(BOOL)initializedPlugin
  1928. {
  1929. ASSERT(_isSilverlight);
  1930. NPBool isFullscreenPerformanceIssueFixed = 0;
  1931. NPPluginFuncs *pluginFuncs = [_pluginPackage.get() pluginFuncs];
  1932. if (pluginFuncs->getvalue && pluginFuncs->getvalue(plugin, static_cast<NPPVariable>(WKNVSilverlightFullscreenPerformanceIssueFixed), &isFullscreenPerformanceIssueFixed) == NPERR_NO_ERROR && isFullscreenPerformanceIssueFixed)
  1933. return;
  1934. static CGLPixelFormatObj pixelFormatObject = 0;
  1935. static unsigned refCount = 0;
  1936. if (initializedPlugin) {
  1937. refCount++;
  1938. if (refCount == 1) {
  1939. const CGLPixelFormatAttribute attributes[] = { kCGLPFAAccelerated, static_cast<CGLPixelFormatAttribute>(0) };
  1940. GLint npix;
  1941. CGLChoosePixelFormat(attributes, &pixelFormatObject, &npix);
  1942. }
  1943. } else {
  1944. ASSERT(pixelFormatObject);
  1945. refCount--;
  1946. if (!refCount)
  1947. CGLReleasePixelFormat(pixelFormatObject);
  1948. }
  1949. }
  1950. - (NPError)_createPlugin
  1951. {
  1952. plugin = (NPP)calloc(1, sizeof(NPP_t));
  1953. plugin->ndata = self;
  1954. ASSERT([_pluginPackage.get() pluginFuncs]->newp);
  1955. // NPN_New(), which creates the plug-in instance, should never be called while calling a plug-in function for that instance.
  1956. ASSERT(pluginFunctionCallDepth == 0);
  1957. PluginMainThreadScheduler::scheduler().registerPlugin(plugin);
  1958. _isFlash = [_pluginPackage.get() bundleIdentifier] == "com.macromedia.Flash Player.plugin";
  1959. _isSilverlight = [_pluginPackage.get() bundleIdentifier] == "com.microsoft.SilverlightPlugin";
  1960. [[self class] setCurrentPluginView:self];
  1961. NPError npErr = [_pluginPackage.get() pluginFuncs]->newp((char *)[_MIMEType.get() cString], plugin, _mode, argsCount, cAttributes, cValues, NULL);
  1962. [[self class] setCurrentPluginView:nil];
  1963. if (_isSilverlight)
  1964. [self _workaroundSilverlightFullscreenBug:YES];
  1965. LOG(Plugins, "NPP_New: %d", npErr);
  1966. return npErr;
  1967. }
  1968. - (void)_destroyPlugin
  1969. {
  1970. PluginMainThreadScheduler::scheduler().unregisterPlugin(plugin);
  1971. if (_isSilverlight)
  1972. [self _workaroundSilverlightFullscreenBug:NO];
  1973. NPError npErr;
  1974. npErr = ![_pluginPackage.get() pluginFuncs]->destroy(plugin, NULL);
  1975. LOG(Plugins, "NPP_Destroy: %d", npErr);
  1976. if (Frame* frame = core([self webFrame]))
  1977. frame->script()->cleanupScriptObjectsForPlugin(self);
  1978. free(plugin);
  1979. plugin = NULL;
  1980. }
  1981. - (NSBitmapImageRep *)_printedPluginBitmap
  1982. {
  1983. #ifdef NP_NO_QUICKDRAW
  1984. return nil;
  1985. #else
  1986. // Cannot print plugins that do not implement NPP_Print
  1987. if (![_pluginPackage.get() pluginFuncs]->print)
  1988. return nil;
  1989. // This NSBitmapImageRep will share its bitmap buffer with a GWorld that the plugin will draw into.
  1990. // The bitmap is created in 32-bits-per-pixel ARGB format, which is the default GWorld pixel format.
  1991. NSBitmapImageRep *bitmap = [[[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
  1992. pixelsWide:window.width
  1993. pixelsHigh:window.height
  1994. bitsPerSample:8
  1995. samplesPerPixel:4
  1996. hasAlpha:YES
  1997. isPlanar:NO
  1998. colorSpaceName:NSDeviceRGBColorSpace
  1999. bitmapFormat:NSAlphaFirstBitmapFormat
  2000. bytesPerRow:0
  2001. bitsPerPixel:0] autorelease];
  2002. ASSERT(bitmap);
  2003. // Create a GWorld with the same underlying buffer into which the plugin can draw
  2004. ::Rect printGWorldBounds;
  2005. SetRect(&printGWorldBounds, 0, 0, window.width, window.height);
  2006. GWorldPtr printGWorld;
  2007. if (NewGWorldFromPtr(&printGWorld,
  2008. k32ARGBPixelFormat,
  2009. &printGWorldBounds,
  2010. NULL,
  2011. NULL,
  2012. 0,
  2013. (Ptr)[bitmap bitmapData],
  2014. [bitmap bytesPerRow]) != noErr) {
  2015. LOG_ERROR("Could not create GWorld for printing");
  2016. return nil;
  2017. }
  2018. /// Create NPWindow for the GWorld
  2019. NPWindow printNPWindow;
  2020. printNPWindow.window = &printGWorld; // Normally this is an NP_Port, but when printing it is the actual CGrafPtr
  2021. printNPWindow.x = 0;
  2022. printNPWindow.y = 0;
  2023. printNPWindow.width = window.width;
  2024. printNPWindow.height = window.height;
  2025. printNPWindow.clipRect.top = 0;
  2026. printNPWindow.clipRect.left = 0;
  2027. printNPWindow.clipRect.right = window.width;
  2028. printNPWindow.clipRect.bottom = window.height;
  2029. printNPWindow.type = NPWindowTypeDrawable; // Offscreen graphics port as opposed to a proper window
  2030. // Create embed-mode NPPrint
  2031. NPPrint npPrint;
  2032. npPrint.mode = NP_EMBED;
  2033. npPrint.print.embedPrint.window = printNPWindow;
  2034. npPrint.print.embedPrint.platformPrint = printGWorld;
  2035. // Tell the plugin to print into the GWorld
  2036. [self willCallPlugInFunction];
  2037. {
  2038. JSC::JSLock::DropAllLocks dropAllLocks(JSDOMWindowBase::commonVM());
  2039. [_pluginPackage.get() pluginFuncs]->print(plugin, &npPrint);
  2040. }
  2041. [self didCallPlugInFunction];
  2042. // Don't need the GWorld anymore
  2043. DisposeGWorld(printGWorld);
  2044. return bitmap;
  2045. #endif
  2046. }
  2047. - (void)_redeliverStream
  2048. {
  2049. if ([self dataSource] && _isStarted) {
  2050. // Deliver what has not been passed to the plug-in up to this point.
  2051. if (_dataLengthReceived > 0) {
  2052. NSData *data = [[[self dataSource] data] subdataWithRange:NSMakeRange(0, _dataLengthReceived)];
  2053. _dataLengthReceived = 0;
  2054. [self pluginView:self receivedData:data];
  2055. if (![[self dataSource] isLoading]) {
  2056. if (_error)
  2057. [self pluginView:self receivedError:_error.get()];
  2058. else
  2059. [self pluginViewFinishedLoading:self];
  2060. }
  2061. }
  2062. }
  2063. }
  2064. @end
  2065. #endif