llpluginclassmedia.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:30k
源码类别:

游戏引擎

开发平台:

C++ Builder

  1. /** 
  2.  * @file llpluginclassmedia.cpp
  3.  * @brief LLPluginClassMedia handles a plugin which knows about the "media" message class.
  4.  *
  5.  * @cond
  6.  * $LicenseInfo:firstyear=2008&license=viewergpl$
  7.  * 
  8.  * Copyright (c) 2008-2010, Linden Research, Inc.
  9.  * 
  10.  * Second Life Viewer Source Code
  11.  * The source code in this file ("Source Code") is provided by Linden Lab
  12.  * to you under the terms of the GNU General Public License, version 2.0
  13.  * ("GPL"), unless you have obtained a separate licensing agreement
  14.  * ("Other License"), formally executed by you and Linden Lab.  Terms of
  15.  * the GPL can be found in doc/GPL-license.txt in this distribution, or
  16.  * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  17.  * 
  18.  * There are special exceptions to the terms and conditions of the GPL as
  19.  * it is applied to this Source Code. View the full text of the exception
  20.  * in the file doc/FLOSS-exception.txt in this software distribution, or
  21.  * online at
  22.  * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  23.  * 
  24.  * By copying, modifying or distributing this software, you acknowledge
  25.  * that you have read and understood your obligations described above,
  26.  * and agree to abide by those obligations.
  27.  * 
  28.  * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  29.  * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  30.  * COMPLETENESS OR PERFORMANCE.
  31.  * $/LicenseInfo$
  32.  * @endcond
  33.  */
  34. #include "linden_common.h"
  35. #include "indra_constants.h"
  36. #include "llpluginclassmedia.h"
  37. #include "llpluginmessageclasses.h"
  38. #include "llqtwebkit.h"
  39. static int LOW_PRIORITY_TEXTURE_SIZE_DEFAULT = 256;
  40. static int nextPowerOf2( int value )
  41. {
  42. int next_power_of_2 = 1;
  43. while ( next_power_of_2 < value )
  44. {
  45. next_power_of_2 <<= 1;
  46. }
  47. return next_power_of_2;
  48. }
  49. LLPluginClassMedia::LLPluginClassMedia(LLPluginClassMediaOwner *owner)
  50. {
  51. mOwner = owner;
  52. mPlugin = NULL;
  53. reset();
  54. }
  55. LLPluginClassMedia::~LLPluginClassMedia()
  56. {
  57. reset();
  58. }
  59. bool LLPluginClassMedia::init(const std::string &launcher_filename, const std::string &plugin_filename, bool debug, const std::string &user_data_path)
  60. {
  61. LL_DEBUGS("Plugin") << "launcher: " << launcher_filename << LL_ENDL;
  62. LL_DEBUGS("Plugin") << "plugin: " << plugin_filename << LL_ENDL;
  63. LL_DEBUGS("Plugin") << "user_data_path: " << user_data_path << LL_ENDL;
  64. mPlugin = new LLPluginProcessParent(this);
  65. mPlugin->setSleepTime(mSleepTime);
  66. mPlugin->init(launcher_filename, plugin_filename, debug, user_data_path);
  67. return true;
  68. }
  69. void LLPluginClassMedia::reset()
  70. {
  71. if(mPlugin != NULL)
  72. {
  73. delete mPlugin;
  74. mPlugin = NULL;
  75. }
  76. mTextureParamsReceived = false;
  77. mRequestedTextureDepth = 0;
  78. mRequestedTextureInternalFormat = 0;
  79. mRequestedTextureFormat = 0;
  80. mRequestedTextureType = 0;
  81. mRequestedTextureSwapBytes = false;
  82. mRequestedTextureCoordsOpenGL = false;
  83. mTextureSharedMemorySize = 0;
  84. mTextureSharedMemoryName.clear();
  85. mDefaultMediaWidth = 0;
  86. mDefaultMediaHeight = 0;
  87. mNaturalMediaWidth = 0;
  88. mNaturalMediaHeight = 0;
  89. mSetMediaWidth = -1;
  90. mSetMediaHeight = -1;
  91. mRequestedMediaWidth = 0;
  92. mRequestedMediaHeight = 0;
  93. mRequestedTextureWidth = 0;
  94. mRequestedTextureHeight = 0;
  95. mFullMediaWidth = 0;
  96. mFullMediaHeight = 0;
  97. mTextureWidth = 0;
  98. mTextureHeight = 0;
  99. mMediaWidth = 0;
  100. mMediaHeight = 0;
  101. mDirtyRect = LLRect::null;
  102. mAutoScaleMedia = false;
  103. mRequestedVolume = 1.0f;
  104. mPriority = PRIORITY_NORMAL;
  105. mLowPrioritySizeLimit = LOW_PRIORITY_TEXTURE_SIZE_DEFAULT;
  106. mAllowDownsample = false;
  107. mPadding = 0;
  108. mLastMouseX = 0;
  109. mLastMouseY = 0;
  110. mStatus = LLPluginClassMediaOwner::MEDIA_NONE;
  111. mSleepTime = 1.0f / 100.0f;
  112. mCanCut = false;
  113. mCanCopy = false;
  114. mCanPaste = false;
  115. mMediaName.clear();
  116. mMediaDescription.clear();
  117. mBackgroundColor = LLColor4(1.0f, 1.0f, 1.0f, 1.0f);
  118. // media_browser class
  119. mNavigateURI.clear();
  120. mNavigateResultCode = -1;
  121. mNavigateResultString.clear();
  122. mHistoryBackAvailable = false;
  123. mHistoryForwardAvailable = false;
  124. mStatusText.clear();
  125. mProgressPercent = 0;
  126. mClickURL.clear();
  127. mClickTarget.clear();
  128. mClickTargetType = TARGET_NONE;
  129. // media_time class
  130. mCurrentTime = 0.0f;
  131. mDuration = 0.0f;
  132. mCurrentRate = 0.0f;
  133. mLoadedDuration = 0.0f;
  134. }
  135. void LLPluginClassMedia::idle(void)
  136. {
  137. if(mPlugin)
  138. {
  139. mPlugin->idle();
  140. }
  141. if((mMediaWidth == -1) || (!mTextureParamsReceived) || (mPlugin == NULL))
  142. {
  143. // Can't process a size change at this time
  144. }
  145. else if((mRequestedMediaWidth != mMediaWidth) || (mRequestedMediaHeight != mMediaHeight))
  146. {
  147. // Calculate the correct size for the media texture
  148. mRequestedTextureHeight = mRequestedMediaHeight;
  149. if(mPadding < 0)
  150. {
  151. // negative values indicate the plugin wants a power of 2
  152. mRequestedTextureWidth = nextPowerOf2(mRequestedMediaWidth);
  153. }
  154. else
  155. {
  156. mRequestedTextureWidth = mRequestedMediaWidth;
  157. if(mPadding > 1)
  158. {
  159. // Pad up to a multiple of the specified number of bytes per row
  160. int rowbytes = mRequestedTextureWidth * mRequestedTextureDepth;
  161. int pad = rowbytes % mPadding;
  162. if(pad != 0)
  163. {
  164. rowbytes += mPadding - pad;
  165. }
  166. if(rowbytes % mRequestedTextureDepth == 0)
  167. {
  168. mRequestedTextureWidth = rowbytes / mRequestedTextureDepth;
  169. }
  170. else
  171. {
  172. LL_WARNS("Plugin") << "Unable to pad texture width, padding size " << mPadding << "is not a multiple of pixel size " << mRequestedTextureDepth << LL_ENDL;
  173. }
  174. }
  175. }
  176. // Size change has been requested but not initiated yet.
  177. size_t newsize = mRequestedTextureWidth * mRequestedTextureHeight * mRequestedTextureDepth;
  178. // Add an extra line for padding, just in case.
  179. newsize += mRequestedTextureWidth * mRequestedTextureDepth;
  180. if(newsize != mTextureSharedMemorySize)
  181. {
  182. if(!mTextureSharedMemoryName.empty())
  183. {
  184. // Tell the plugin to remove the old memory segment
  185. mPlugin->removeSharedMemory(mTextureSharedMemoryName);
  186. mTextureSharedMemoryName.clear();
  187. }
  188. mTextureSharedMemorySize = newsize;
  189. mTextureSharedMemoryName = mPlugin->addSharedMemory(mTextureSharedMemorySize);
  190. if(!mTextureSharedMemoryName.empty())
  191. {
  192. void *addr = mPlugin->getSharedMemoryAddress(mTextureSharedMemoryName);
  193. // clear texture memory to avoid random screen visual fuzz from uninitialized texture data
  194. memset( addr, 0x00, newsize );
  195. // We could do this to force an update, but textureValid() will still be returning false until the first roundtrip to the plugin,
  196. // so it may not be worthwhile.
  197. // mDirtyRect.setOriginAndSize(0, 0, mRequestedMediaWidth, mRequestedMediaHeight);
  198. }
  199. }
  200. // This is our local indicator that a change is in progress.
  201. mTextureWidth = -1;
  202. mTextureHeight = -1;
  203. mMediaWidth = -1;
  204. mMediaHeight = -1;
  205. // This invalidates any existing dirty rect.
  206. resetDirty();
  207. // Send a size change message to the plugin
  208. {
  209. LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change");
  210. message.setValue("name", mTextureSharedMemoryName);
  211. message.setValueS32("width", mRequestedMediaWidth);
  212. message.setValueS32("height", mRequestedMediaHeight);
  213. message.setValueS32("texture_width", mRequestedTextureWidth);
  214. message.setValueS32("texture_height", mRequestedTextureHeight);
  215. message.setValueReal("background_r", mBackgroundColor.mV[VX]);
  216. message.setValueReal("background_g", mBackgroundColor.mV[VY]);
  217. message.setValueReal("background_b", mBackgroundColor.mV[VZ]);
  218. message.setValueReal("background_a", mBackgroundColor.mV[VW]);
  219. mPlugin->sendMessage(message); // DO NOT just use sendMessage() here -- we want this to jump ahead of the queue.
  220. LL_DEBUGS("Plugin") << "Sending size_change" << LL_ENDL;
  221. }
  222. }
  223. if(mPlugin && mPlugin->isRunning())
  224. {
  225. // Send queued messages
  226. while(!mSendQueue.empty())
  227. {
  228. LLPluginMessage message = mSendQueue.front();
  229. mSendQueue.pop();
  230. mPlugin->sendMessage(message);
  231. }
  232. }
  233. }
  234. int LLPluginClassMedia::getTextureWidth() const
  235. {
  236. return nextPowerOf2(mTextureWidth);
  237. }
  238. int LLPluginClassMedia::getTextureHeight() const
  239. {
  240. return nextPowerOf2(mTextureHeight);
  241. }
  242. unsigned char* LLPluginClassMedia::getBitsData()
  243. {
  244. unsigned char *result = NULL;
  245. if((mPlugin != NULL) && !mTextureSharedMemoryName.empty())
  246. {
  247. result = (unsigned char*)mPlugin->getSharedMemoryAddress(mTextureSharedMemoryName);
  248. }
  249. return result;
  250. }
  251. void LLPluginClassMedia::setSize(int width, int height)
  252. {
  253. if((width > 0) && (height > 0))
  254. {
  255. mSetMediaWidth = width;
  256. mSetMediaHeight = height;
  257. }
  258. else
  259. {
  260. mSetMediaWidth = -1;
  261. mSetMediaHeight = -1;
  262. }
  263. setSizeInternal();
  264. }
  265. void LLPluginClassMedia::setSizeInternal(void)
  266. {
  267. if((mSetMediaWidth > 0) && (mSetMediaHeight > 0))
  268. {
  269. mRequestedMediaWidth = mSetMediaWidth;
  270. mRequestedMediaHeight = mSetMediaHeight;
  271. }
  272. else if((mNaturalMediaWidth > 0) && (mNaturalMediaHeight > 0))
  273. {
  274. mRequestedMediaWidth = mNaturalMediaWidth;
  275. mRequestedMediaHeight = mNaturalMediaHeight;
  276. }
  277. else
  278. {
  279. mRequestedMediaWidth = mDefaultMediaWidth;
  280. mRequestedMediaHeight = mDefaultMediaHeight;
  281. }
  282. // Save these for size/interest calculations
  283. mFullMediaWidth = mRequestedMediaWidth;
  284. mFullMediaHeight = mRequestedMediaHeight;
  285. if(mAllowDownsample)
  286. {
  287. switch(mPriority)
  288. {
  289. case PRIORITY_SLIDESHOW:
  290. case PRIORITY_LOW:
  291. // Reduce maximum texture dimension to (or below) mLowPrioritySizeLimit
  292. while((mRequestedMediaWidth > mLowPrioritySizeLimit) || (mRequestedMediaHeight > mLowPrioritySizeLimit))
  293. {
  294. mRequestedMediaWidth /= 2;
  295. mRequestedMediaHeight /= 2;
  296. }
  297. break;
  298. default:
  299. // Don't adjust texture size
  300. break;
  301. }
  302. }
  303. if(mAutoScaleMedia)
  304. {
  305. mRequestedMediaWidth = nextPowerOf2(mRequestedMediaWidth);
  306. mRequestedMediaHeight = nextPowerOf2(mRequestedMediaHeight);
  307. }
  308. if(mRequestedMediaWidth > 2048)
  309. mRequestedMediaWidth = 2048;
  310. if(mRequestedMediaHeight > 2048)
  311. mRequestedMediaHeight = 2048;
  312. }
  313. void LLPluginClassMedia::setAutoScale(bool auto_scale)
  314. {
  315. if(auto_scale != mAutoScaleMedia)
  316. {
  317. mAutoScaleMedia = auto_scale;
  318. setSizeInternal();
  319. }
  320. }
  321. bool LLPluginClassMedia::textureValid(void)
  322. {
  323. if(
  324. !mTextureParamsReceived ||
  325. mTextureWidth <= 0 ||
  326. mTextureHeight <= 0 ||
  327. mMediaWidth <= 0 ||
  328. mMediaHeight <= 0 ||
  329. mRequestedMediaWidth != mMediaWidth ||
  330. mRequestedMediaHeight != mMediaHeight ||
  331. getBitsData() == NULL
  332. )
  333. return false;
  334. return true;
  335. }
  336. bool LLPluginClassMedia::getDirty(LLRect *dirty_rect)
  337. {
  338. bool result = !mDirtyRect.isEmpty();
  339. if(dirty_rect != NULL)
  340. {
  341. *dirty_rect = mDirtyRect;
  342. }
  343. return result;
  344. }
  345. void LLPluginClassMedia::resetDirty(void)
  346. {
  347. mDirtyRect = LLRect::null;
  348. }
  349. std::string LLPluginClassMedia::translateModifiers(MASK modifiers)
  350. {
  351. std::string result;
  352. if(modifiers & MASK_CONTROL)
  353. {
  354. result += "control|";
  355. }
  356. if(modifiers & MASK_ALT)
  357. {
  358. result += "alt|";
  359. }
  360. if(modifiers & MASK_SHIFT)
  361. {
  362. result += "shift|";
  363. }
  364. // TODO: should I deal with platform differences here or in callers?
  365. // TODO: how do we deal with the Mac "command" key?
  366. /*
  367. if(modifiers & MASK_SOMETHING)
  368. {
  369. result += "meta|";
  370. }
  371. */
  372. return result;
  373. }
  374. void LLPluginClassMedia::mouseEvent(EMouseEventType type, int button, int x, int y, MASK modifiers)
  375. {
  376. if(type == MOUSE_EVENT_MOVE)
  377. {
  378. if((x == mLastMouseX) && (y == mLastMouseY))
  379. {
  380. // Don't spam unnecessary mouse move events.
  381. return;
  382. }
  383. mLastMouseX = x;
  384. mLastMouseY = y;
  385. }
  386. LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "mouse_event");
  387. std::string temp;
  388. switch(type)
  389. {
  390. case MOUSE_EVENT_DOWN: temp = "down"; break;
  391. case MOUSE_EVENT_UP: temp = "up"; break;
  392. case MOUSE_EVENT_MOVE: temp = "move"; break;
  393. case MOUSE_EVENT_DOUBLE_CLICK: temp = "double_click"; break;
  394. }
  395. message.setValue("event", temp);
  396. message.setValueS32("button", button);
  397. message.setValueS32("x", x);
  398. // Incoming coordinates are OpenGL-style ((0,0) = lower left), so flip them here if the plugin has requested it.
  399. if(!mRequestedTextureCoordsOpenGL)
  400. {
  401. // TODO: Should I use mMediaHeight or mRequestedMediaHeight here?
  402. y = mMediaHeight - y;
  403. }
  404. message.setValueS32("y", y);
  405. message.setValue("modifiers", translateModifiers(modifiers));
  406. sendMessage(message);
  407. }
  408. bool LLPluginClassMedia::keyEvent(EKeyEventType type, int key_code, MASK modifiers, LLSD native_key_data)
  409. {
  410. bool result = true;
  411. // FIXME:
  412. // HACK: we don't have an easy way to tell if the plugin is going to handle a particular keycode.
  413. // For now, return false for the ones the webkit plugin won't handle properly.
  414. switch(key_code)
  415. {
  416. case KEY_BACKSPACE:
  417. case KEY_TAB:
  418. case KEY_RETURN:
  419. case KEY_PAD_RETURN:
  420. case KEY_SHIFT:
  421. case KEY_CONTROL:
  422. case KEY_ALT:
  423. case KEY_CAPSLOCK:
  424. case KEY_ESCAPE:
  425. case KEY_PAGE_UP:
  426. case KEY_PAGE_DOWN:
  427. case KEY_END:
  428. case KEY_HOME:
  429. case KEY_LEFT:
  430. case KEY_UP:
  431. case KEY_RIGHT:
  432. case KEY_DOWN:
  433. case KEY_INSERT:
  434. case KEY_DELETE:
  435. // These will be handled
  436. break;
  437. default:
  438. // regular ASCII characters will also be handled
  439. if(key_code >= KEY_SPECIAL)
  440. {
  441. // Other "special" codes will not work properly.
  442. result = false;
  443. }
  444. break;
  445. }
  446. if(result)
  447. {
  448. LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "key_event");
  449. std::string temp;
  450. switch(type)
  451. {
  452. case KEY_EVENT_DOWN: temp = "down"; break;
  453. case KEY_EVENT_UP: temp = "up"; break;
  454. case KEY_EVENT_REPEAT: temp = "repeat"; break;
  455. }
  456. message.setValue("event", temp);
  457. message.setValueS32("key", key_code);
  458. message.setValue("modifiers", translateModifiers(modifiers));
  459. message.setValueLLSD("native_key_data", native_key_data);
  460. sendMessage(message);
  461. }
  462. return result;
  463. }
  464. void LLPluginClassMedia::scrollEvent(int x, int y, MASK modifiers)
  465. {
  466. LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "scroll_event");
  467. message.setValueS32("x", x);
  468. message.setValueS32("y", y);
  469. message.setValue("modifiers", translateModifiers(modifiers));
  470. sendMessage(message);
  471. }
  472. bool LLPluginClassMedia::textInput(const std::string &text, MASK modifiers, LLSD native_key_data)
  473. {
  474. LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "text_event");
  475. message.setValue("text", text);
  476. message.setValue("modifiers", translateModifiers(modifiers));
  477. message.setValueLLSD("native_key_data", native_key_data);
  478. sendMessage(message);
  479. return true;
  480. }
  481. void LLPluginClassMedia::loadURI(const std::string &uri)
  482. {
  483. LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "load_uri");
  484. message.setValue("uri", uri);
  485. sendMessage(message);
  486. }
  487. const char* LLPluginClassMedia::priorityToString(EPriority priority)
  488. {
  489. const char* result = "UNKNOWN";
  490. switch(priority)
  491. {
  492. case PRIORITY_UNLOADED: result = "unloaded"; break;
  493. case PRIORITY_STOPPED: result = "stopped"; break;
  494. case PRIORITY_HIDDEN: result = "hidden"; break;
  495. case PRIORITY_SLIDESHOW: result = "slideshow"; break;
  496. case PRIORITY_LOW: result = "low"; break;
  497. case PRIORITY_NORMAL: result = "normal"; break;
  498. case PRIORITY_HIGH: result = "high"; break;
  499. }
  500. return result;
  501. }
  502. void LLPluginClassMedia::setPriority(EPriority priority)
  503. {
  504. if(mPriority != priority)
  505. {
  506. mPriority = priority;
  507. LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_priority");
  508. std::string priority_string = priorityToString(priority);
  509. switch(priority)
  510. {
  511. case PRIORITY_UNLOADED:
  512. mSleepTime = 1.0f;
  513. break;
  514. case PRIORITY_STOPPED:
  515. mSleepTime = 1.0f;
  516. break;
  517. case PRIORITY_HIDDEN:
  518. mSleepTime = 1.0f;
  519. break;
  520. case PRIORITY_SLIDESHOW:
  521. mSleepTime = 1.0f;
  522. break;
  523. case PRIORITY_LOW:
  524. mSleepTime = 1.0f / 25.0f;
  525. break;
  526. case PRIORITY_NORMAL:
  527. mSleepTime = 1.0f / 50.0f;
  528. break;
  529. case PRIORITY_HIGH:
  530. mSleepTime = 1.0f / 100.0f;
  531. break;
  532. }
  533. message.setValue("priority", priority_string);
  534. sendMessage(message);
  535. if(mPlugin)
  536. {
  537. mPlugin->setSleepTime(mSleepTime);
  538. }
  539. LL_DEBUGS("PluginPriority") << this << ": setting priority to " << priority_string << LL_ENDL;
  540. // This may affect the calculated size, so recalculate it here.
  541. setSizeInternal();
  542. }
  543. }
  544. void LLPluginClassMedia::setLowPrioritySizeLimit(int size)
  545. {
  546. int power = nextPowerOf2(size);
  547. if(mLowPrioritySizeLimit != power)
  548. {
  549. mLowPrioritySizeLimit = power;
  550. // This may affect the calculated size, so recalculate it here.
  551. setSizeInternal();
  552. }
  553. }
  554. F64 LLPluginClassMedia::getCPUUsage()
  555. {
  556. F64 result = 0.0f;
  557. if(mPlugin)
  558. {
  559. result = mPlugin->getCPUUsage();
  560. }
  561. return result;
  562. }
  563. void LLPluginClassMedia::cut()
  564. {
  565. LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_cut");
  566. sendMessage(message);
  567. }
  568. void LLPluginClassMedia::copy()
  569. {
  570. LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_copy");
  571. sendMessage(message);
  572. }
  573. void LLPluginClassMedia::paste()
  574. {
  575. LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_paste");
  576. sendMessage(message);
  577. }
  578. LLPluginClassMedia::ETargetType getTargetTypeFromLLQtWebkit(int target_type)
  579. {
  580. // convert a LinkTargetType value from llqtwebkit to an ETargetType
  581. // so that we don't expose the llqtwebkit header in viewer code
  582. switch (target_type)
  583. {
  584. case LLQtWebKit::LTT_TARGET_NONE:
  585. return LLPluginClassMedia::TARGET_NONE;
  586. case LLQtWebKit::LTT_TARGET_BLANK:
  587. return LLPluginClassMedia::TARGET_BLANK;
  588. case LLQtWebKit::LTT_TARGET_EXTERNAL:
  589. return LLPluginClassMedia::TARGET_EXTERNAL;
  590. default:
  591. return LLPluginClassMedia::TARGET_OTHER;
  592. }
  593. }
  594. /* virtual */ 
  595. void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
  596. {
  597. std::string message_class = message.getClass();
  598. if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA)
  599. {
  600. std::string message_name = message.getName();
  601. if(message_name == "texture_params")
  602. {
  603. mRequestedTextureDepth = message.getValueS32("depth");
  604. mRequestedTextureInternalFormat = message.getValueU32("internalformat");
  605. mRequestedTextureFormat = message.getValueU32("format");
  606. mRequestedTextureType = message.getValueU32("type");
  607. mRequestedTextureSwapBytes = message.getValueBoolean("swap_bytes");
  608. mRequestedTextureCoordsOpenGL = message.getValueBoolean("coords_opengl");
  609. // These two are optional, and will default to 0 if they're not specified.
  610. mDefaultMediaWidth = message.getValueS32("default_width");
  611. mDefaultMediaHeight = message.getValueS32("default_height");
  612. mAllowDownsample = message.getValueBoolean("allow_downsample");
  613. mPadding = message.getValueS32("padding");
  614. setSizeInternal();
  615. mTextureParamsReceived = true;
  616. }
  617. else if(message_name == "updated")
  618. {
  619. if(message.hasValue("left"))
  620. {
  621. LLRect newDirtyRect;
  622. newDirtyRect.mLeft = message.getValueS32("left");
  623. newDirtyRect.mTop = message.getValueS32("top");
  624. newDirtyRect.mRight = message.getValueS32("right");
  625. newDirtyRect.mBottom = message.getValueS32("bottom");
  626. // The plugin is likely to have top and bottom switched, due to vertical flip and OpenGL coordinate confusion.
  627. // If they're backwards, swap them.
  628. if(newDirtyRect.mTop < newDirtyRect.mBottom)
  629. {
  630. S32 temp = newDirtyRect.mTop;
  631. newDirtyRect.mTop = newDirtyRect.mBottom;
  632. newDirtyRect.mBottom = temp;
  633. }
  634. if(mDirtyRect.isEmpty())
  635. {
  636. mDirtyRect = newDirtyRect;
  637. }
  638. else
  639. {
  640. mDirtyRect.unionWith(newDirtyRect);
  641. }
  642. LL_DEBUGS("Plugin") << "adjusted incoming rect is: (" 
  643. << newDirtyRect.mLeft << ", "
  644. << newDirtyRect.mTop << ", "
  645. << newDirtyRect.mRight << ", "
  646. << newDirtyRect.mBottom << "), new dirty rect is: ("
  647. << mDirtyRect.mLeft << ", "
  648. << mDirtyRect.mTop << ", "
  649. << mDirtyRect.mRight << ", "
  650. << mDirtyRect.mBottom << ")"
  651. << LL_ENDL;
  652. mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CONTENT_UPDATED);
  653. }
  654. bool time_duration_updated = false;
  655. int previous_percent = mProgressPercent;
  656. if(message.hasValue("current_time"))
  657. {
  658. mCurrentTime = message.getValueReal("current_time");
  659. time_duration_updated = true;
  660. }
  661. if(message.hasValue("duration"))
  662. {
  663. mDuration = message.getValueReal("duration");
  664. time_duration_updated = true;
  665. }
  666. if(message.hasValue("current_rate"))
  667. {
  668. mCurrentRate = message.getValueReal("current_rate");
  669. }
  670. if(message.hasValue("loaded_duration"))
  671. {
  672. mLoadedDuration = message.getValueReal("loaded_duration");
  673. time_duration_updated = true;
  674. }
  675. else
  676. {
  677. // If the message doesn't contain a loaded_duration param, assume it's equal to duration
  678. mLoadedDuration = mDuration;
  679. }
  680. // Calculate a percentage based on the loaded duration and total duration.
  681. if(mDuration != 0.0f) // Don't divide by zero.
  682. {
  683. mProgressPercent = (int)((mLoadedDuration * 100.0f)/mDuration);
  684. }
  685. if(time_duration_updated)
  686. {
  687. mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_TIME_DURATION_UPDATED);
  688. }
  689. if(previous_percent != mProgressPercent)
  690. {
  691. mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PROGRESS_UPDATED);
  692. }
  693. }
  694. else if(message_name == "media_status")
  695. {
  696. std::string status = message.getValue("status");
  697. LL_DEBUGS("Plugin") << "Status changed to: " << status << LL_ENDL;
  698. if(status == "loading")
  699. {
  700. mStatus = LLPluginClassMediaOwner::MEDIA_LOADING;
  701. }
  702. else if(status == "loaded")
  703. {
  704. mStatus = LLPluginClassMediaOwner::MEDIA_LOADED;
  705. }
  706. else if(status == "error")
  707. {
  708. mStatus = LLPluginClassMediaOwner::MEDIA_ERROR;
  709. }
  710. else if(status == "playing")
  711. {
  712. mStatus = LLPluginClassMediaOwner::MEDIA_PLAYING;
  713. }
  714. else if(status == "paused")
  715. {
  716. mStatus = LLPluginClassMediaOwner::MEDIA_PAUSED;
  717. }
  718. else if(status == "done")
  719. {
  720. mStatus = LLPluginClassMediaOwner::MEDIA_DONE;
  721. }
  722. else
  723. {
  724. // empty string or any unknown string
  725. mStatus = LLPluginClassMediaOwner::MEDIA_NONE;
  726. }
  727. }
  728. else if(message_name == "size_change_request")
  729. {
  730. S32 width = message.getValueS32("width");
  731. S32 height = message.getValueS32("height");
  732. std::string name = message.getValue("name");
  733. // TODO: check that name matches?
  734. mNaturalMediaWidth = width;
  735. mNaturalMediaHeight = height;
  736. setSizeInternal();
  737. }
  738. else if(message_name == "size_change_response")
  739. {
  740. std::string name = message.getValue("name");
  741. // TODO: check that name matches?
  742. mTextureWidth = message.getValueS32("texture_width");
  743. mTextureHeight = message.getValueS32("texture_height");
  744. mMediaWidth = message.getValueS32("width");
  745. mMediaHeight = message.getValueS32("height");
  746. // This invalidates any existing dirty rect.
  747. resetDirty();
  748. // TODO: should we verify that the plugin sent back the right values?  
  749. // Two size changes in a row may cause them to not match, due to queueing, etc.
  750. mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_SIZE_CHANGED);
  751. }
  752. else if(message_name == "cursor_changed")
  753. {
  754. mCursorName = message.getValue("name");
  755. mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CURSOR_CHANGED);
  756. }
  757. else if(message_name == "edit_state")
  758. {
  759. if(message.hasValue("cut"))
  760. {
  761. mCanCut = message.getValueBoolean("cut");
  762. }
  763. if(message.hasValue("copy"))
  764. {
  765. mCanCopy = message.getValueBoolean("copy");
  766. }
  767. if(message.hasValue("paste"))
  768. {
  769. mCanPaste = message.getValueBoolean("paste");
  770. }
  771. }
  772. else if(message_name == "name_text")
  773. {
  774. mMediaName = message.getValue("name");
  775. mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAME_CHANGED);
  776. }
  777. else
  778. {
  779. LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL;
  780. }
  781. }
  782. else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER)
  783. {
  784. std::string message_name = message.getName();
  785. if(message_name == "navigate_begin")
  786. {
  787. mNavigateURI = message.getValue("uri");
  788. mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAVIGATE_BEGIN);
  789. }
  790. else if(message_name == "navigate_complete")
  791. {
  792. mNavigateURI = message.getValue("uri");
  793. mNavigateResultCode = message.getValueS32("result_code");
  794. mNavigateResultString = message.getValue("result_string");
  795. mHistoryBackAvailable = message.getValueBoolean("history_back_available");
  796. mHistoryForwardAvailable = message.getValueBoolean("history_forward_available");
  797. mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAVIGATE_COMPLETE);
  798. }
  799. else if(message_name == "progress")
  800. {
  801. mProgressPercent = message.getValueS32("percent");
  802. mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PROGRESS_UPDATED);
  803. }
  804. else if(message_name == "status_text")
  805. {
  806. mStatusText = message.getValue("status");
  807. mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_STATUS_TEXT_CHANGED);
  808. }
  809. else if(message_name == "location_changed")
  810. {
  811. mLocation = message.getValue("uri");
  812. mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_LOCATION_CHANGED);
  813. }
  814. else if(message_name == "click_href")
  815. {
  816. mClickURL = message.getValue("uri");
  817. mClickTarget = message.getValue("target");
  818. U32 target_type = message.getValueU32("target_type");
  819. mClickTargetType = ::getTargetTypeFromLLQtWebkit(target_type);
  820. mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CLICK_LINK_HREF);
  821. }
  822. else if(message_name == "click_nofollow")
  823. {
  824. mClickURL = message.getValue("uri");
  825. mClickTarget.clear();
  826. mClickTargetType = TARGET_NONE;
  827. mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CLICK_LINK_NOFOLLOW);
  828. }
  829. else
  830. {
  831. LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL;
  832. }
  833. }
  834. else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME)
  835. {
  836. std::string message_name = message.getName();
  837. // This class hasn't defined any incoming messages yet.
  838. // if(message_name == "message_name")
  839. // {
  840. // }
  841. // else 
  842. {
  843. LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL;
  844. }
  845. }
  846. }
  847. /* virtual */ 
  848. void LLPluginClassMedia::pluginLaunchFailed()
  849. {
  850. mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PLUGIN_FAILED_LAUNCH);
  851. }
  852. /* virtual */ 
  853. void LLPluginClassMedia::pluginDied()
  854. {
  855. mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PLUGIN_FAILED);
  856. }
  857. void LLPluginClassMedia::mediaEvent(LLPluginClassMediaOwner::EMediaEvent event)
  858. {
  859. if(mOwner)
  860. {
  861. mOwner->handleMediaEvent(this, event);
  862. }
  863. }
  864. void LLPluginClassMedia::sendMessage(const LLPluginMessage &message)
  865. {
  866. if(mPlugin && mPlugin->isRunning())
  867. {
  868. mPlugin->sendMessage(message);
  869. }
  870. else
  871. {
  872. // The plugin isn't set up yet -- queue this message to be sent after initialization.
  873. mSendQueue.push(message);
  874. }
  875. }
  876. ////////////////////////////////////////////////////////////
  877. // MARK: media_browser class functions
  878. bool LLPluginClassMedia::pluginSupportsMediaBrowser(void)
  879. {
  880. std::string version = mPlugin->getMessageClassVersion(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER);
  881. return !version.empty();
  882. }
  883. void LLPluginClassMedia::focus(bool focused)
  884. {
  885. LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "focus");
  886. message.setValueBoolean("focused", focused);
  887. sendMessage(message);
  888. }
  889. void LLPluginClassMedia::clear_cache()
  890. {
  891. LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "clear_cache");
  892. sendMessage(message);
  893. }
  894. void LLPluginClassMedia::clear_cookies()
  895. {
  896. LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "clear_cookies");
  897. sendMessage(message);
  898. }
  899. void LLPluginClassMedia::enable_cookies(bool enable)
  900. {
  901. LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "enable_cookies");
  902. sendMessage(message);
  903. }
  904. void LLPluginClassMedia::proxy_setup(bool enable, const std::string &host, int port)
  905. {
  906. LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "proxy_setup");
  907. message.setValueBoolean("enable", enable);
  908. message.setValue("host", host);
  909. message.setValueS32("port", port);
  910. sendMessage(message);
  911. }
  912. void LLPluginClassMedia::browse_stop()
  913. {
  914. LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_stop");
  915. sendMessage(message);
  916. }
  917. void LLPluginClassMedia::browse_reload(bool ignore_cache)
  918. {
  919. LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_reload");
  920. message.setValueBoolean("ignore_cache", ignore_cache);
  921. sendMessage(message);
  922. }
  923. void LLPluginClassMedia::browse_forward()
  924. {
  925. LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_forward");
  926. sendMessage(message);
  927. }
  928. void LLPluginClassMedia::browse_back()
  929. {
  930. LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_back");
  931. sendMessage(message);
  932. }
  933. void LLPluginClassMedia::set_status_redirect(int code, const std::string &url)
  934. {
  935. LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "set_status_redirect");
  936. message.setValueS32("code", code);
  937. message.setValue("url", url);
  938. sendMessage(message);
  939. }
  940. void LLPluginClassMedia::setBrowserUserAgent(const std::string& user_agent)
  941. {
  942. LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "set_user_agent");
  943. message.setValue("user_agent", user_agent);
  944. sendMessage(message);
  945. }
  946. void LLPluginClassMedia::crashPlugin()
  947. {
  948. LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "crash");
  949. sendMessage(message);
  950. }
  951. void LLPluginClassMedia::hangPlugin()
  952. {
  953. LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "hang");
  954. sendMessage(message);
  955. }
  956. ////////////////////////////////////////////////////////////
  957. // MARK: media_time class functions
  958. bool LLPluginClassMedia::pluginSupportsMediaTime(void)
  959. {
  960. std::string version = mPlugin->getMessageClassVersion(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME);
  961. return !version.empty();
  962. }
  963. void LLPluginClassMedia::stop()
  964. {
  965. LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "stop");
  966. sendMessage(message);
  967. }
  968. void LLPluginClassMedia::start(float rate)
  969. {
  970. LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "start");
  971. message.setValueReal("rate", rate);
  972. sendMessage(message);
  973. }
  974. void LLPluginClassMedia::pause()
  975. {
  976. LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "pause");
  977. sendMessage(message);
  978. }
  979. void LLPluginClassMedia::seek(float time)
  980. {
  981. LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "seek");
  982. message.setValueReal("time", time);
  983. sendMessage(message);
  984. }
  985. void LLPluginClassMedia::setLoop(bool loop)
  986. {
  987. LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "set_loop");
  988. message.setValueBoolean("loop", loop);
  989. sendMessage(message);
  990. }
  991. void LLPluginClassMedia::setVolume(float volume)
  992. {
  993. if(volume != mRequestedVolume)
  994. {
  995. mRequestedVolume = volume;
  996. LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "set_volume");
  997. message.setValueReal("volume", volume);
  998. sendMessage(message);
  999. }
  1000. }
  1001. float LLPluginClassMedia::getVolume()
  1002. {
  1003. return mRequestedVolume;
  1004. }
  1005. void LLPluginClassMedia::initializeUrlHistory(const LLSD& url_history)
  1006. {
  1007. // Send URL history to plugin
  1008. LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "init_history");
  1009. message.setValueLLSD("history", url_history);
  1010. sendMessage(message);
  1011. LL_DEBUGS("Plugin") << "Sending history" << LL_ENDL;
  1012. }