llmediactrl.cpp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158
  1. /**
  2. * @file LLMediaCtrl.cpp
  3. * @brief Web browser UI control
  4. *
  5. * $LicenseInfo:firstyear=2006&license=viewergpl$
  6. *
  7. * Copyright (c) 2006-2009, Linden Research, Inc.
  8. *
  9. * Second Life Viewer Source Code
  10. * The source code in this file ("Source Code") is provided by Linden Lab
  11. * to you under the terms of the GNU General Public License, version 2.0
  12. * ("GPL"), unless you have obtained a separate licensing agreement
  13. * ("Other License"), formally executed by you and Linden Lab. Terms of
  14. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16. *
  17. * There are special exceptions to the terms and conditions of the GPL as
  18. * it is applied to this Source Code. View the full text of the exception
  19. * in the file doc/FLOSS-exception.txt in this software distribution, or
  20. * online at
  21. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22. *
  23. * By copying, modifying or distributing this software, you acknowledge
  24. * that you have read and understood your obligations described above,
  25. * and agree to abide by those obligations.
  26. *
  27. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29. * COMPLETENESS OR PERFORMANCE.
  30. * $/LicenseInfo$
  31. */
  32. #include "llviewerprecompiledheaders.h"
  33. #include "dullahan_version.h"
  34. #include "llmediactrl.h"
  35. #include "lldir.h"
  36. #include "llfloater.h"
  37. #include "llhttpconstants.h"
  38. #include "llkeyboard.h"
  39. #include "llnotifications.h"
  40. #include "llpluginclassmedia.h"
  41. #include "llrender.h"
  42. #include "llrenderutils.h" // For gl_rect_2d()
  43. #include "lluictrlfactory.h"
  44. #include "llviewborder.h"
  45. #include "llappviewer.h" // For gRestoreGL
  46. #include "llcommandhandler.h"
  47. #include "llfloaterworldmap.h"
  48. #include "llslurl.h" // For SLURL_*_SCHEME
  49. #include "llurldispatcher.h"
  50. #include "llviewercontrol.h"
  51. #include "llviewermedia.h"
  52. #include "llviewertexture.h"
  53. #include "llviewerwindow.h"
  54. //static
  55. LLMediaCtrl::instances_list_t LLMediaCtrl::sMediaCtrlInstances;
  56. //-----------------------------------------------------------------------------
  57. // LLMediaCtrl
  58. //-----------------------------------------------------------------------------
  59. static const std::string LL_WEB_BROWSER_CTRL_TAG = "web_browser";
  60. static LLRegisterWidget<LLMediaCtrl> r(LL_WEB_BROWSER_CTRL_TAG);
  61. LLMediaCtrl::LLMediaCtrl(const std::string& name, const LLRect& rect)
  62. : LLUICtrl(name, rect, false, NULL, NULL),
  63. mTextureDepthBytes(4),
  64. mBorder(NULL),
  65. mFrequentUpdates(true),
  66. mForceUpdate(false),
  67. mTrusted(false),
  68. mCurrentNavUrl("about:blank"),
  69. mAlwaysRefresh(false),
  70. mMediaSource(NULL),
  71. mStretchToFill(true),
  72. mDecoupleTextureSize(false),
  73. mTextureWidth(1024),
  74. mTextureHeight(1024),
  75. mMaintainAspectRatio(true),
  76. mHidingInitialLoad(true)
  77. {
  78. sMediaCtrlInstances.insert(this);
  79. LLRect r = getRect();
  80. S32 screen_width = ll_roundp((F32)r.getWidth() *
  81. LLUI::sGLScaleFactor.mV[VX]);
  82. S32 screen_height = ll_roundp((F32)r.getHeight() *
  83. LLUI::sGLScaleFactor.mV[VY]);
  84. setTextureSize(screen_width, screen_height);
  85. mMediaTextureID.generate();
  86. LLRect border_rect(0, r.getHeight() + 2, r.getWidth() + 2, 0);
  87. mBorder = new LLViewBorder(std::string("web control border"),
  88. border_rect, LLViewBorder::BEVEL_IN);
  89. addChild(mBorder);
  90. }
  91. // Note: this is now a singleton and destruction happens via initClass() now
  92. //virtual
  93. LLMediaCtrl::~LLMediaCtrl()
  94. {
  95. if (mMediaSource)
  96. {
  97. mMediaSource->remObserver(this);
  98. mMediaSource = NULL;
  99. }
  100. sMediaCtrlInstances.erase(this);
  101. }
  102. bool LLMediaCtrl::ensureMediaSourceExists()
  103. {
  104. if (mMediaSource.notNull())
  105. {
  106. return true;
  107. }
  108. // If we do not already have a media source, try to create one.
  109. mMediaSource = LLViewerMedia::newMediaImpl(mMediaTextureID, mTextureWidth,
  110. mTextureHeight);
  111. if (mMediaSource.isNull())
  112. {
  113. llwarns << "Media source creation failed for media texture Id: "
  114. << mMediaTextureID << llendl;
  115. return false;
  116. }
  117. mMediaSource->setUsedInUI(true);
  118. mMediaSource->setHomeURL(mHomePageUrl, mHomePageMimeType);
  119. mMediaSource->setTarget(mTarget);
  120. mMediaSource->setTrustedBrowser(mTrusted);
  121. mMediaSource->setVisible(getVisible());
  122. mMediaSource->addObserver(this);
  123. #if 0
  124. mMediaSource->setBackgroundColor(getBackgroundColor());
  125. #endif
  126. static LLCachedControl<F32> scale(gSavedSettings, "CEFScaleFactor");
  127. F64 sf = llmax((F64)scale, 0.1);
  128. mMediaSource->setPageZoomFactor((F64)LLUI::sGLScaleFactor.mV[VX] * sf);
  129. return true;
  130. }
  131. void LLMediaCtrl::setBorderVisible(bool border_visible)
  132. {
  133. if (mBorder)
  134. {
  135. mBorder->setVisible(border_visible);
  136. }
  137. }
  138. void LLMediaCtrl::setTrusted(bool trusted)
  139. {
  140. mTrusted = trusted;
  141. if (mMediaSource)
  142. {
  143. mMediaSource->setTrustedBrowser(mTrusted);
  144. }
  145. }
  146. //virtual
  147. bool LLMediaCtrl::handleHover(S32 x, S32 y, MASK mask)
  148. {
  149. if (mMediaSource)
  150. {
  151. convertInputCoords(x, y);
  152. mMediaSource->mouseMove(x, y, mask);
  153. gViewerWindowp->setCursor(mMediaSource->getLastSetCursor());
  154. return true;
  155. }
  156. else
  157. {
  158. LL_DEBUGS("Media") << "No media source, passing event to LLUICtrl"
  159. << LL_ENDL;
  160. return LLUICtrl::handleHover(x, y, mask);
  161. }
  162. }
  163. //virtual
  164. bool LLMediaCtrl::handleScrollWheel(S32 x, S32 y, S32 clicks)
  165. {
  166. if (mMediaSource && mMediaSource->hasMedia())
  167. {
  168. convertInputCoords(x, y);
  169. MASK mask = gKeyboardp ? gKeyboardp->currentMask(true) : 0;
  170. mMediaSource->scrollWheel(x, y, 0, clicks, mask);
  171. return true;
  172. }
  173. else
  174. {
  175. LL_DEBUGS("Media") << "No active media, passing event to LLUICtrl"
  176. << LL_ENDL;
  177. return LLUICtrl::handleScrollWheel(x, y, clicks);
  178. }
  179. }
  180. //virtual
  181. bool LLMediaCtrl::handleMouseUp(S32 x, S32 y, MASK mask)
  182. {
  183. if (mMediaSource)
  184. {
  185. convertInputCoords(x, y);
  186. mMediaSource->mouseUp(x, y, mask);
  187. gFocusMgr.setMouseCapture(NULL);
  188. return true;
  189. }
  190. else
  191. {
  192. LL_DEBUGS("Media") << "No media source, passing event to LLUICtrl"
  193. << LL_ENDL;
  194. return LLUICtrl::handleMouseUp(x, y, mask);
  195. }
  196. }
  197. //virtual
  198. bool LLMediaCtrl::handleMouseDown(S32 x, S32 y, MASK mask)
  199. {
  200. if (mMediaSource)
  201. {
  202. convertInputCoords(x, y);
  203. mMediaSource->mouseDown(x, y, mask);
  204. gFocusMgr.setMouseCapture(this);
  205. setFocus(true);
  206. return true;
  207. }
  208. else
  209. {
  210. LL_DEBUGS("Media") << "No media source, passing event to LLUICtrl"
  211. << LL_ENDL;
  212. return LLUICtrl::handleMouseDown(x, y, mask);
  213. }
  214. }
  215. //virtual
  216. bool LLMediaCtrl::handleRightMouseUp(S32 x, S32 y, MASK mask)
  217. {
  218. if (mMediaSource)
  219. {
  220. convertInputCoords(x, y);
  221. mMediaSource->mouseUp(x, y, mask, 1);
  222. gFocusMgr.setMouseCapture(NULL);
  223. return true;
  224. }
  225. else
  226. {
  227. LL_DEBUGS("Media") << "No media source, passing event to LLUICtrl"
  228. << LL_ENDL;
  229. return LLUICtrl::handleRightMouseUp(x, y, mask);
  230. }
  231. }
  232. //virtual
  233. bool LLMediaCtrl::handleRightMouseDown(S32 x, S32 y, MASK mask)
  234. {
  235. if (mMediaSource)
  236. {
  237. convertInputCoords(x, y);
  238. mMediaSource->mouseDown(x, y, mask, 1);
  239. gFocusMgr.setMouseCapture(this);
  240. setFocus(true);
  241. return true;
  242. }
  243. else
  244. {
  245. LL_DEBUGS("Media") << "No media source, passing event to LLUICtrl"
  246. << LL_ENDL;
  247. return LLUICtrl::handleRightMouseDown(x, y, mask);
  248. }
  249. }
  250. //virtual
  251. bool LLMediaCtrl::handleDoubleClick(S32 x, S32 y, MASK mask)
  252. {
  253. if (mMediaSource)
  254. {
  255. convertInputCoords(x, y);
  256. mMediaSource->mouseDoubleClick(x, y, mask);
  257. gFocusMgr.setMouseCapture(this);
  258. setFocus(true);
  259. return true;
  260. }
  261. else
  262. {
  263. LL_DEBUGS("Media") << "No media source, passing event to LLUICtrl"
  264. << LL_ENDL;
  265. return LLUICtrl::handleDoubleClick(x, y, mask);
  266. }
  267. }
  268. //virtual
  269. void LLMediaCtrl::onFocusReceived()
  270. {
  271. if (mMediaSource)
  272. {
  273. mMediaSource->focus(true);
  274. // Set focus for edit menu items
  275. gEditMenuHandlerp = mMediaSource;
  276. }
  277. LLUICtrl::onFocusReceived();
  278. }
  279. //virtual
  280. void LLMediaCtrl::onFocusLost()
  281. {
  282. if (mMediaSource)
  283. {
  284. mMediaSource->focus(false);
  285. if (gEditMenuHandlerp == mMediaSource)
  286. {
  287. // Clear focus for edit menu items
  288. gEditMenuHandlerp = NULL;
  289. }
  290. }
  291. gViewerWindowp->focusClient();
  292. LLUICtrl::onFocusLost();
  293. }
  294. //virtual
  295. bool LLMediaCtrl::handleKeyHere(KEY key, MASK mask)
  296. {
  297. bool result = false;
  298. if (mMediaSource)
  299. {
  300. if (LLView::sDebugKeys)
  301. {
  302. llinfos << "Key handling passed to the media source" << llendl;
  303. }
  304. result = mMediaSource->handleKeyHere(key, mask);
  305. }
  306. if (!result)
  307. {
  308. if (LLView::sDebugKeys)
  309. {
  310. llinfos << "Key handling passed to the UI control" << llendl;
  311. }
  312. result = LLUICtrl::handleKeyHere(key, mask);
  313. }
  314. return result;
  315. }
  316. //virtual
  317. bool LLMediaCtrl::handleKeyUpHere(KEY key, MASK mask)
  318. {
  319. bool result = false;
  320. if (mMediaSource)
  321. {
  322. result = mMediaSource->handleKeyUpHere(key, mask);
  323. }
  324. if (!result)
  325. {
  326. result = LLUICtrl::handleKeyUpHere(key, mask);
  327. }
  328. return result;
  329. }
  330. //virtual
  331. bool LLMediaCtrl::handleUnicodeCharHere(llwchar uni_char)
  332. {
  333. bool result = false;
  334. // Only accept 'printable' characters, sigh...
  335. if (uni_char >= 32 && // discard 'control' characters
  336. uni_char != 127) // SDL thinks this is 'delete' - yuck.
  337. {
  338. if (LLView::sDebugKeys)
  339. {
  340. llinfos << "Key handling passed to the media source" << llendl;
  341. }
  342. if (mMediaSource)
  343. {
  344. result = mMediaSource->handleUnicodeCharHere(uni_char);
  345. }
  346. }
  347. if (!result)
  348. {
  349. if (LLView::sDebugKeys)
  350. {
  351. llinfos << "Key handling passed to the UI control" << llendl;
  352. }
  353. result = LLUICtrl::handleUnicodeCharHere(uni_char);
  354. }
  355. return result;
  356. }
  357. #if 0 // Not used
  358. //virtual
  359. void LLMediaCtrl::handleVisibilityChange(bool new_visibility)
  360. {
  361. llinfos << "Visibility changed to " << (new_visibility ? "true" : "false")
  362. << llendl;
  363. if (mMediaSource)
  364. {
  365. mMediaSource->setVisible(new_visibility);
  366. }
  367. }
  368. #endif
  369. //virtual
  370. void LLMediaCtrl::onVisibilityChange(bool new_visibility)
  371. {
  372. // Set state of frequent updates automatically if visibility changes
  373. if (new_visibility)
  374. {
  375. mFrequentUpdates = true;
  376. }
  377. else
  378. {
  379. mFrequentUpdates = false;
  380. }
  381. LLUICtrl::onVisibilityChange(new_visibility);
  382. }
  383. //virtual
  384. void LLMediaCtrl::reshape(S32 width, S32 height, bool called_from_parent)
  385. {
  386. if (!mDecoupleTextureSize)
  387. {
  388. S32 screen_width = ll_round((F32)width * LLUI::sGLScaleFactor.mV[VX]);
  389. S32 screen_height = ll_round((F32)height *
  390. LLUI::sGLScaleFactor.mV[VY]);
  391. // When floater is minimized, these sizes are negative
  392. if (screen_height > 0 && screen_width > 0)
  393. {
  394. setTextureSize(screen_width, screen_height);
  395. }
  396. }
  397. LLUICtrl::reshape(width, height, called_from_parent);
  398. }
  399. void LLMediaCtrl::navigateBack()
  400. {
  401. if (mMediaSource && mMediaSource->hasMedia())
  402. {
  403. mMediaSource->getMediaPlugin()->browse_back();
  404. }
  405. }
  406. void LLMediaCtrl::navigateForward()
  407. {
  408. if (mMediaSource && mMediaSource->hasMedia())
  409. {
  410. mMediaSource->getMediaPlugin()->browse_forward();
  411. }
  412. }
  413. bool LLMediaCtrl::canNavigateBack()
  414. {
  415. return mMediaSource && mMediaSource->canNavigateBack();
  416. }
  417. bool LLMediaCtrl::canNavigateForward()
  418. {
  419. return mMediaSource && mMediaSource->canNavigateForward();
  420. }
  421. void LLMediaCtrl::navigateTo(const std::string& url_in,
  422. const std::string& mime_type)
  423. {
  424. // Do not browse to anything that got a SLURL scheme:
  425. size_t i = url_in.find("://");
  426. if (i != std::string::npos)
  427. {
  428. std::string scheme = url_in.substr(0, i);
  429. LLStringUtil::toLower(scheme);
  430. if (scheme == LLSLURL::SLURL_SECONDLIFE_SCHEME ||
  431. scheme == LLSLURL::SLURL_HOP_SCHEME ||
  432. scheme == LLSLURL::SLURL_X_GRID_INFO_SCHEME ||
  433. scheme == LLSLURL::SLURL_X_GRID_LOCATION_INFO_SCHEME)
  434. {
  435. llwarns << "Attempted to navigate to a SLURL: " << url_in
  436. << " - Aborted." << llendl;
  437. return;
  438. }
  439. }
  440. if (mCurrentNavUrl == url_in || !ensureMediaSourceExists())
  441. {
  442. return; // Nothing to do...
  443. }
  444. mCurrentNavUrl = url_in;
  445. mMediaSource->setSize(mTextureWidth, mTextureHeight);
  446. mMediaSource->navigateTo(url_in, mime_type, mime_type.empty(),
  447. // Not a server request and not filtering
  448. false, false);
  449. }
  450. void LLMediaCtrl::navigateToLocalPage(const std::string& subdir,
  451. const std::string& filename_in)
  452. {
  453. std::string language = LLUI::getLanguage();
  454. std::string filename = subdir + LL_DIR_DELIM_STR + filename_in;
  455. std::string expanded_filename = gDirUtil.findSkinnedFilename("html",
  456. language,
  457. filename);
  458. bool found = LLFile::exists(expanded_filename);
  459. if (!found && language != "en-us")
  460. {
  461. expanded_filename = gDirUtil.findSkinnedFilename("html", "en-us",
  462. filename);
  463. found = LLFile::exists(expanded_filename);
  464. }
  465. if (!found)
  466. {
  467. llwarns << "File '" << expanded_filename << "' not found" << llendl;
  468. return;
  469. }
  470. #if LL_WINDOWS
  471. // Windows filenames are not recognized "as is", unlike UNICES' (since
  472. // those start with '/')... Let's be more explicit !
  473. expanded_filename = "file:///" + expanded_filename;
  474. #else
  475. // CEF does not accept file names without a "file://" prefix
  476. expanded_filename = "file://" + expanded_filename;
  477. #endif
  478. navigateTo(expanded_filename, HTTP_CONTENT_TEXT_HTML);
  479. }
  480. void LLMediaCtrl::navigateHome()
  481. {
  482. if (ensureMediaSourceExists())
  483. {
  484. mMediaSource->setSize(mTextureWidth, mTextureHeight);
  485. mMediaSource->navigateHome();
  486. }
  487. }
  488. void LLMediaCtrl::setHomePageUrl(const std::string url_in,
  489. const std::string& mime_type)
  490. {
  491. mHomePageUrl = url_in;
  492. if (mMediaSource)
  493. {
  494. mMediaSource->setHomeURL(mHomePageUrl, mime_type);
  495. }
  496. }
  497. void LLMediaCtrl::setTarget(const std::string& target)
  498. {
  499. mTarget = target;
  500. if (mMediaSource)
  501. {
  502. mMediaSource->setTarget(mTarget);
  503. }
  504. }
  505. void LLMediaCtrl::setTextureSize(S32 width, S32 height)
  506. {
  507. mTextureWidth = width;
  508. mTextureHeight = height;
  509. if (mMediaSource)
  510. {
  511. mMediaSource->setSize(mTextureWidth, mTextureHeight);
  512. mForceUpdate = true;
  513. }
  514. }
  515. LLPluginClassMedia* LLMediaCtrl::getMediaPlugin()
  516. {
  517. return mMediaSource.isNull() ? NULL : mMediaSource->getMediaPlugin();
  518. }
  519. //virtual
  520. void LLMediaCtrl::draw()
  521. {
  522. LLRect r = getRect();
  523. if (gRestoreGL)
  524. {
  525. reshape(r.getWidth(), r.getHeight(), false);
  526. return;
  527. }
  528. // NOTE: optimization needed here - probably only need to do this once
  529. // unless tearoffs change the parent which they probably do.
  530. const LLUICtrl* ptr = findRootMostFocusRoot();
  531. if (ptr && ptr->hasFocus())
  532. {
  533. setFrequentUpdates(true);
  534. }
  535. else
  536. {
  537. setFrequentUpdates(false);
  538. }
  539. if (mHidingInitialLoad)
  540. {
  541. // If we are hiding loading, draw a black background
  542. gl_rect_2d(0, r.getHeight(), r.getWidth(), 0, LLColor4::black);
  543. LLUICtrl::draw();
  544. return;
  545. }
  546. LLPluginClassMedia* media_plugin = NULL;
  547. LLViewerMediaTexture* media_texture = NULL;
  548. bool draw_media = false;
  549. if (mMediaSource && mMediaSource->hasMedia())
  550. {
  551. media_plugin = mMediaSource->getMediaPlugin();
  552. if (media_plugin && media_plugin->textureValid())
  553. {
  554. media_texture =
  555. LLViewerTextureManager::findMediaTexture(mMediaTextureID);
  556. if (media_texture)
  557. {
  558. draw_media = true;
  559. }
  560. }
  561. }
  562. if (!draw_media)
  563. {
  564. // Draw a black background instead...
  565. gl_rect_2d(0, r.getHeight(), r.getWidth(), 0, LLColor4::black);
  566. LLUICtrl::draw();
  567. return;
  568. }
  569. F32 media_width = (F32)media_plugin->getWidth();
  570. F32 media_height = (F32)media_plugin->getHeight();
  571. F32 texture_width = (F32)media_plugin->getTextureWidth();
  572. F32 texture_height = (F32)media_plugin->getTextureHeight();
  573. if (media_width <= 0.f || media_height <= 0.f || texture_width <= 0.f ||
  574. texture_height <= 0.f || r.getWidth() <= 0 || r.getHeight() <= 0)
  575. {
  576. // Avoid divide by zero and negative sizes...
  577. LLUICtrl::draw();
  578. return;
  579. }
  580. // Alpha off for this
  581. LLGLSUIDefault gls_ui;
  582. gGL.pushUIMatrix();
  583. {
  584. static LLCachedControl<F32> scale(gSavedSettings, "CEFScaleFactor");
  585. F64 scale_factor = llmax((F64)scale, 0.1);
  586. mMediaSource->setPageZoomFactor((F64)LLUI::sGLScaleFactor.mV[VX] *
  587. scale_factor);
  588. // Scale texture to fit the space using texture coords
  589. gGL.getTexUnit(0)->bind(media_texture);
  590. gGL.color4fv(LLColor4::white.mV);
  591. F32 max_u = media_width / texture_width;
  592. F32 max_v = media_height / texture_height;
  593. S32 width, height;
  594. S32 x_offset = 0;
  595. S32 y_offset = 0;
  596. if (mStretchToFill)
  597. {
  598. if (mMaintainAspectRatio)
  599. {
  600. F32 media_aspect = media_width / media_height;
  601. F32 view_aspect = (F32)r.getWidth() / (F32)r.getHeight();
  602. if (media_aspect > view_aspect)
  603. {
  604. // Max width, adjusted height
  605. width = r.getWidth();
  606. height = llmin(llmax(S32(width / media_aspect), 0),
  607. r.getHeight());
  608. }
  609. else
  610. {
  611. // Max height, adjusted width
  612. height = r.getHeight();
  613. width = llmin(llmax(S32(height * media_aspect), 0),
  614. r.getWidth());
  615. }
  616. }
  617. else
  618. {
  619. width = r.getWidth();
  620. height = r.getHeight();
  621. }
  622. }
  623. else
  624. {
  625. width = llmin((S32)media_width, r.getWidth());
  626. height = llmin((S32)media_height, r.getHeight());
  627. }
  628. x_offset = (r.getWidth() - width) / 2;
  629. y_offset = (r.getHeight() - height) / 2;
  630. // Draw the browser
  631. gGL.setSceneBlendType(LLRender::BT_REPLACE);
  632. gGL.begin(LLRender::TRIANGLES);
  633. if (!media_plugin->getTextureCoordsOpenGL())
  634. {
  635. // Render using web browser reported width and height, instead of
  636. // trying to invert GL scale
  637. gGL.texCoord2f(max_u, 0.f);
  638. gGL.vertex2i(x_offset + width, y_offset + height);
  639. gGL.texCoord2f(0.f, 0.f);
  640. gGL.vertex2i(x_offset, y_offset + height);
  641. gGL.texCoord2f(0.f, max_v);
  642. gGL.vertex2i(x_offset, y_offset);
  643. gGL.texCoord2f(max_u, 0.f);
  644. gGL.vertex2i(x_offset + width, y_offset + height);
  645. gGL.texCoord2f(0.f, max_v);
  646. gGL.vertex2i(x_offset, y_offset);
  647. gGL.texCoord2f(max_u, max_v);
  648. gGL.vertex2i(x_offset + width, y_offset);
  649. }
  650. else
  651. {
  652. // Render using web browser reported width and height, instead of
  653. // trying to invert GL scale
  654. gGL.texCoord2f(max_u, max_v);
  655. gGL.vertex2i(x_offset + width, y_offset + height);
  656. gGL.texCoord2f(0.f, max_v);
  657. gGL.vertex2i(x_offset, y_offset + height);
  658. gGL.texCoord2f(0.f, 0.f);
  659. gGL.vertex2i(x_offset, y_offset);
  660. gGL.texCoord2f(max_u, max_v);
  661. gGL.vertex2i(x_offset + width, y_offset + height);
  662. gGL.texCoord2f(0.f, 0.f);
  663. gGL.vertex2i(x_offset, y_offset);
  664. gGL.texCoord2f(max_u, 0.f);
  665. gGL.vertex2i(x_offset + width, y_offset);
  666. }
  667. gGL.end();
  668. gGL.setSceneBlendType(LLRender::BT_ALPHA);
  669. }
  670. gGL.popUIMatrix();
  671. // Highlight if keyboard focus here. *TODO: this needs some work.
  672. if (mBorder && mBorder->getVisible())
  673. {
  674. mBorder->setKeyboardFocusHighlight(gFocusMgr.childHasKeyboardFocus(this));
  675. }
  676. LLUICtrl::draw();
  677. }
  678. void LLMediaCtrl::convertInputCoords(S32& x, S32& y)
  679. {
  680. LLPluginClassMedia* plugin = mMediaSource ? mMediaSource->getMediaPlugin()
  681. : NULL;
  682. bool flipped = plugin && plugin->getTextureCoordsOpenGL();
  683. x = ll_round((F32)x * LLUI::sGLScaleFactor.mV[VX]);
  684. if (flipped)
  685. {
  686. y = ll_round((F32)(getRect().getHeight() - y) *
  687. LLUI::sGLScaleFactor.mV[VY]);
  688. }
  689. else
  690. {
  691. y = ll_round((F32)(y) * LLUI::sGLScaleFactor.mV[VY]);
  692. }
  693. }
  694. //virtual
  695. void LLMediaCtrl::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event)
  696. {
  697. if (!self) return;
  698. switch (event)
  699. {
  700. case MEDIA_EVENT_CONTENT_UPDATED:
  701. {
  702. #if 0
  703. LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CONTENT_UPDATED"
  704. << LL_ENDL;
  705. #endif
  706. break;
  707. }
  708. case MEDIA_EVENT_TIME_DURATION_UPDATED:
  709. {
  710. #if 0
  711. LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_TIME_DURATION_UPDATED, time is "
  712. << self->getCurrentTime() << " of "
  713. << self->getDuration() << LL_ENDL;
  714. #endif
  715. break;
  716. }
  717. case MEDIA_EVENT_SIZE_CHANGED:
  718. {
  719. LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_SIZE_CHANGED"
  720. << LL_ENDL;
  721. LLRect r = getRect();
  722. reshape(r.getWidth(), r.getHeight(), false);
  723. break;
  724. }
  725. case MEDIA_EVENT_CURSOR_CHANGED:
  726. {
  727. LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CURSOR_CHANGED, new cursor is "
  728. << self->getCursorName() << LL_ENDL;
  729. break;
  730. }
  731. case MEDIA_EVENT_NAVIGATE_BEGIN:
  732. {
  733. LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_NAVIGATE_BEGIN, url is "
  734. << self->getNavigateURI() << LL_ENDL;
  735. break;
  736. }
  737. case MEDIA_EVENT_NAVIGATE_COMPLETE:
  738. {
  739. LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_NAVIGATE_COMPLETE, result string is: "
  740. << self->getNavigateResultString() << LL_ENDL;
  741. if (mHidingInitialLoad)
  742. {
  743. mHidingInitialLoad = false;
  744. }
  745. break;
  746. }
  747. case MEDIA_EVENT_NAVIGATE_ERROR_PAGE:
  748. {
  749. LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_NAVIGATE_ERROR_PAGE"
  750. << LL_ENDL;
  751. if (mErrorPageURL.length() > 0)
  752. {
  753. navigateTo(mErrorPageURL, HTTP_CONTENT_TEXT_HTML);
  754. }
  755. break;
  756. }
  757. case MEDIA_EVENT_PROGRESS_UPDATED:
  758. {
  759. LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_PROGRESS_UPDATED, loading at "
  760. << self->getProgressPercent() << "%" << LL_ENDL;
  761. break;
  762. }
  763. case MEDIA_EVENT_STATUS_TEXT_CHANGED:
  764. {
  765. LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_STATUS_TEXT_CHANGED, new status text is: "
  766. << self->getStatusText() << LL_ENDL;
  767. break;
  768. }
  769. case MEDIA_EVENT_LOCATION_CHANGED:
  770. {
  771. mCurrentNavUrl = self->getLocation();
  772. LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_LOCATION_CHANGED, new uri is: "
  773. << mCurrentNavUrl << LL_ENDL;
  774. break;
  775. }
  776. case MEDIA_EVENT_CLICK_LINK_HREF:
  777. {
  778. LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CLICK_LINK_HREF, target is \""
  779. << self->getClickTarget() << "\", uri is "
  780. << self->getClickURL() << LL_ENDL;
  781. break;
  782. }
  783. case MEDIA_EVENT_CLICK_LINK_NOFOLLOW:
  784. {
  785. LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CLICK_LINK_NOFOLLOW, uri is "
  786. << self->getClickURL() << LL_ENDL;
  787. break;
  788. }
  789. case MEDIA_EVENT_PLUGIN_FAILED:
  790. {
  791. LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_PLUGIN_FAILED"
  792. << LL_ENDL;
  793. break;
  794. }
  795. case MEDIA_EVENT_PLUGIN_FAILED_LAUNCH:
  796. {
  797. LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_PLUGIN_FAILED_LAUNCH"
  798. << LL_ENDL;
  799. break;
  800. }
  801. case MEDIA_EVENT_NAME_CHANGED:
  802. {
  803. LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_NAME_CHANGED"
  804. << LL_ENDL;
  805. break;
  806. }
  807. case MEDIA_EVENT_CLOSE_REQUEST:
  808. {
  809. LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CLOSE_REQUEST"
  810. << LL_ENDL;
  811. break;
  812. }
  813. case MEDIA_EVENT_PICK_FILE_REQUEST:
  814. {
  815. LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_PICK_FILE_REQUEST"
  816. << LL_ENDL;
  817. break;
  818. }
  819. case MEDIA_EVENT_GEOMETRY_CHANGE:
  820. {
  821. LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_GEOMETRY_CHANGE, uuid is "
  822. << self->getClickUUID() << LL_ENDL;
  823. break;
  824. }
  825. case MEDIA_EVENT_AUTH_REQUEST:
  826. {
  827. LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_AUTH_REQUEST"
  828. << LL_ENDL;
  829. break;
  830. }
  831. case MEDIA_EVENT_LINK_HOVERED:
  832. {
  833. LL_DEBUGS("Media") << "Unimplemented media event: MEDIA_EVENT_LINK_HOVERED"
  834. << LL_ENDL;
  835. break;
  836. }
  837. case MEDIA_EVENT_FILE_DOWNLOAD:
  838. {
  839. LL_DEBUGS("Media") << "Unimplemented media event: MEDIA_EVENT_FILE_DOWNLOAD"
  840. << LL_ENDL;
  841. break;
  842. }
  843. case MEDIA_EVENT_DEBUG_MESSAGE:
  844. {
  845. llinfos << self->getDebugMessageText() << llendl;
  846. break;
  847. }
  848. }
  849. // Chain all events to any potential observers of this object.
  850. emitEvent(self, event);
  851. }
  852. //virtual
  853. const std::string& LLMediaCtrl::getTag() const
  854. {
  855. return LL_WEB_BROWSER_CTRL_TAG;
  856. }
  857. //virtual
  858. LLXMLNodePtr LLMediaCtrl::getXML(bool save_children) const
  859. {
  860. LLXMLNodePtr node = LLUICtrl::getXML();
  861. node->setName(LL_WEB_BROWSER_CTRL_TAG);
  862. return node;
  863. }
  864. //static
  865. LLView* LLMediaCtrl::fromXML(LLXMLNodePtr node, LLView* parent,
  866. LLUICtrlFactory* factory)
  867. {
  868. std::string name = LL_WEB_BROWSER_CTRL_TAG;
  869. node->getAttributeString("name", name);
  870. std::string start_url;
  871. node->getAttributeString("start_url", start_url);
  872. bool border_visible = true;
  873. node->getAttributeBool("border_visible", border_visible);
  874. LLRect rect;
  875. createRect(node, rect, parent, LLRect());
  876. LLMediaCtrl* self = new LLMediaCtrl(name, rect);
  877. bool decouple_texture_size = self->getDecoupleTextureSize();
  878. node->getAttributeBool("decouple_texture_size", decouple_texture_size);
  879. self->setDecoupleTextureSize(decouple_texture_size);
  880. S32 texture_width = -1;
  881. if (node->hasAttribute("texture_width"))
  882. {
  883. node->getAttributeS32("texture_width", texture_width);
  884. }
  885. S32 texture_height = -1;
  886. if (node->hasAttribute("texture_height"))
  887. {
  888. node->getAttributeS32("texture_height", texture_height);
  889. }
  890. if (texture_width > 0 && texture_height > 0)
  891. {
  892. self->setTextureSize(texture_width, texture_height);
  893. }
  894. else if (decouple_texture_size)
  895. {
  896. // Default size
  897. self->setTextureSize(1024, 1024);
  898. }
  899. self->initFromXML(node, parent);
  900. self->setHomePageUrl(start_url);
  901. self->setBorderVisible(border_visible);
  902. if (!start_url.empty())
  903. {
  904. self->navigateHome();
  905. }
  906. return self;
  907. }
  908. //static
  909. bool LLMediaCtrl::parseRawCookie(const std::string& raw_cookie,
  910. std::string& name, std::string& value,
  911. std::string& path)
  912. {
  913. std::size_t name_pos = raw_cookie.find_first_of('=');
  914. if (name_pos != std::string::npos)
  915. {
  916. name = raw_cookie.substr(0, name_pos);
  917. std::size_t value_pos = raw_cookie.find_first_of(';', name_pos);
  918. if (value_pos != std::string::npos)
  919. {
  920. value = raw_cookie.substr(name_pos + 1, value_pos - name_pos - 1);
  921. path = "/"; // assume root path for now
  922. return true;
  923. }
  924. }
  925. return false;
  926. }
  927. //static
  928. void LLMediaCtrl::setOpenIdCookie(const std::string& url,
  929. const std::string& cookie_host,
  930. const std::string& cookie)
  931. {
  932. if (url.empty() || sMediaCtrlInstances.empty())
  933. {
  934. return;
  935. }
  936. std::string cookie_name, cookie_value, cookie_path;
  937. if (!parseRawCookie(cookie, cookie_name, cookie_value, cookie_path))
  938. {
  939. return;
  940. }
  941. LL_DEBUGS("Media") << "Storing the OpenId cookie for media plugins."
  942. << LL_ENDL;
  943. LLPluginClassMedia::setOpenIdCookie(url, cookie_host, cookie_path,
  944. cookie_name, cookie_value);
  945. for (instances_list_t::iterator it = sMediaCtrlInstances.begin(),
  946. end = sMediaCtrlInstances.end();
  947. it != end; ++it)
  948. {
  949. LLMediaCtrl* ctrl = *it;
  950. if (!ctrl) continue; // Paranoia
  951. LLPluginClassMedia* plugin = ctrl->getMediaPlugin();
  952. if (plugin)
  953. {
  954. plugin->setCookie(url, cookie_name, cookie_value, cookie_host,
  955. cookie_path, true, true);
  956. }
  957. }
  958. }
  959. //-----------------------------------------------------------------------------
  960. // LLFloaterHandler
  961. // Command handler with support for SLURL control of floaters, such as:
  962. // secondlife:///app/floater/self/close
  963. //-----------------------------------------------------------------------------
  964. class LLFloaterHandler final : public LLCommandHandler
  965. {
  966. public:
  967. LLFloaterHandler()
  968. : LLCommandHandler("floater", UNTRUSTED_BLOCK)
  969. {
  970. }
  971. bool handle(const LLSD& params, const LLSD&, LLMediaCtrl* web) override
  972. {
  973. if (!web || params.size() < 2)
  974. {
  975. return false;
  976. }
  977. LLFloater* floater = NULL;
  978. // *TODO: add a floater lookup by name
  979. if (params[0].asString() == "self")
  980. {
  981. LLView* parent = web->getParent();
  982. while (parent)
  983. {
  984. floater = parent->asFloater();
  985. if (floater)
  986. {
  987. break;
  988. }
  989. parent = parent->getParent();
  990. }
  991. }
  992. if (floater && params[1].asString() == "close")
  993. {
  994. floater->close();
  995. return true;
  996. }
  997. return false;
  998. }
  999. };
  1000. // Register with dispatch via global object
  1001. LLFloaterHandler gFloaterHandler;