diff options
Diffstat (limited to '')
-rw-r--r-- | linden/indra/newview/llmediactrl.cpp | 1201 |
1 files changed, 1201 insertions, 0 deletions
diff --git a/linden/indra/newview/llmediactrl.cpp b/linden/indra/newview/llmediactrl.cpp new file mode 100644 index 0000000..1530598 --- /dev/null +++ b/linden/indra/newview/llmediactrl.cpp | |||
@@ -0,0 +1,1201 @@ | |||
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 | |||
33 | #include "llviewerprecompiledheaders.h" | ||
34 | |||
35 | |||
36 | #include "llmediactrl.h" | ||
37 | |||
38 | // viewer includes | ||
39 | #include "llfloaterhtml.h" | ||
40 | #include "llfloaterworldmap.h" | ||
41 | #include "lluictrlfactory.h" | ||
42 | #include "llurldispatcher.h" | ||
43 | #include "llurlsimstring.h" | ||
44 | #include "llviewborder.h" | ||
45 | #include "llviewercontrol.h" | ||
46 | #include "llviewermedia.h" | ||
47 | #include "llviewerwindow.h" | ||
48 | #include "llnotifications.h" | ||
49 | #include "llweb.h" | ||
50 | #include "llrender.h" | ||
51 | #include "llpluginclassmedia.h" | ||
52 | |||
53 | // linden library includes | ||
54 | #include "llfocusmgr.h" | ||
55 | |||
56 | extern BOOL gRestoreGL; | ||
57 | |||
58 | // Setting the mozilla buffer width to 2048 exactly doesn't work, since it pads its rowbytes a bit, pushing the texture width over 2048. | ||
59 | // 2000 should give enough headroom for any amount of padding it cares to add. | ||
60 | const S32 MAX_DIMENSION = 2000; | ||
61 | const S32 MAX_TEXTURE_DIMENSION = 2048; | ||
62 | |||
63 | static LLRegisterWidget<LLMediaCtrl> r("web_browser"); | ||
64 | |||
65 | LLMediaCtrl::LLMediaCtrl( const std::string& name, const LLRect& rect ) : | ||
66 | LLUICtrl( name, rect, FALSE, NULL, NULL ), | ||
67 | mTextureDepthBytes( 4 ), | ||
68 | mWebBrowserImage( 0 ), | ||
69 | mBorder(NULL), | ||
70 | mFrequentUpdates( true ), | ||
71 | mForceUpdate( false ), | ||
72 | mOpenLinksInExternalBrowser( false ), | ||
73 | mOpenLinksInInternalBrowser( false ), | ||
74 | mTrusted( false ), | ||
75 | mHomePageUrl( "" ), | ||
76 | mIgnoreUIScale( true ), | ||
77 | mAlwaysRefresh( false ), | ||
78 | mExternalUrl( "" ), | ||
79 | mMediaSource( 0 ), | ||
80 | mTakeFocusOnClick( true ), | ||
81 | mCurrentNavUrl( "about:blank" ), | ||
82 | mLastSetCursor( UI_CURSOR_ARROW ), | ||
83 | mStretchToFill( true ), | ||
84 | mMaintainAspectRatio ( true ), | ||
85 | mHideLoading (false) | ||
86 | { | ||
87 | S32 screen_width = mIgnoreUIScale ? | ||
88 | llround((F32)getRect().getWidth() * LLUI::sGLScaleFactor.mV[VX]) : getRect().getWidth(); | ||
89 | S32 screen_height = mIgnoreUIScale ? | ||
90 | llround((F32)getRect().getHeight() * LLUI::sGLScaleFactor.mV[VY]) : getRect().getHeight(); | ||
91 | |||
92 | mMediaSource = LLViewerMedia::newMediaImpl(mHomePageUrl, LLUUID::null, screen_width, screen_height, false, false, "text/html"); | ||
93 | if ( !mMediaSource ) | ||
94 | { | ||
95 | llwarns << "media source create failed " << llendl; | ||
96 | // return; | ||
97 | } | ||
98 | else | ||
99 | { | ||
100 | // create a new texture (based on LLDynamic texture) that will be used to display the output | ||
101 | mWebBrowserImage = new LLWebBrowserTexture( screen_width, screen_height, this, mMediaSource ); | ||
102 | } | ||
103 | |||
104 | mMediaSource->setVisible( getVisible() ); | ||
105 | |||
106 | mMediaSource->addObserver( this ); | ||
107 | |||
108 | LLRect border_rect( 0, getRect().getHeight() + 2, getRect().getWidth() + 2, 0 ); | ||
109 | mBorder = new LLViewBorder( std::string("web control border"), border_rect, LLViewBorder::BEVEL_IN ); | ||
110 | addChild( mBorder ); | ||
111 | } | ||
112 | |||
113 | //////////////////////////////////////////////////////////////////////////////// | ||
114 | // note: this is now a singleton and destruction happens via initClass() now | ||
115 | LLMediaCtrl::~LLMediaCtrl() | ||
116 | { | ||
117 | |||
118 | if (mMediaSource) | ||
119 | { | ||
120 | mMediaSource->remObserver( this ); | ||
121 | mMediaSource = NULL; | ||
122 | } | ||
123 | |||
124 | if ( mWebBrowserImage ) | ||
125 | { | ||
126 | delete mWebBrowserImage; | ||
127 | mWebBrowserImage = NULL; | ||
128 | } | ||
129 | } | ||
130 | |||
131 | //////////////////////////////////////////////////////////////////////////////// | ||
132 | // | ||
133 | void LLMediaCtrl::setBorderVisible( BOOL border_visible ) | ||
134 | { | ||
135 | if ( mBorder ) | ||
136 | { | ||
137 | mBorder->setVisible( border_visible ); | ||
138 | }; | ||
139 | }; | ||
140 | |||
141 | //////////////////////////////////////////////////////////////////////////////// | ||
142 | // | ||
143 | void LLMediaCtrl::setTakeFocusOnClick( bool take_focus ) | ||
144 | { | ||
145 | mTakeFocusOnClick = take_focus; | ||
146 | } | ||
147 | |||
148 | //////////////////////////////////////////////////////////////////////////////// | ||
149 | // set flag that forces the embedded browser to open links in the external system browser | ||
150 | void LLMediaCtrl::setOpenInExternalBrowser( bool valIn ) | ||
151 | { | ||
152 | mOpenLinksInExternalBrowser = valIn; | ||
153 | }; | ||
154 | |||
155 | //////////////////////////////////////////////////////////////////////////////// | ||
156 | // set flag that forces the embedded browser to open links in the internal browser floater | ||
157 | void LLMediaCtrl::setOpenInInternalBrowser( bool valIn ) | ||
158 | { | ||
159 | mOpenLinksInInternalBrowser = valIn; | ||
160 | }; | ||
161 | |||
162 | //////////////////////////////////////////////////////////////////////////////// | ||
163 | void LLMediaCtrl::setTrusted( bool valIn ) | ||
164 | { | ||
165 | mTrusted = valIn; | ||
166 | } | ||
167 | |||
168 | //////////////////////////////////////////////////////////////////////////////// | ||
169 | // | ||
170 | BOOL LLMediaCtrl::handleHover( S32 x, S32 y, MASK mask ) | ||
171 | { | ||
172 | convertInputCoords(x, y); | ||
173 | |||
174 | if (mMediaSource) | ||
175 | mMediaSource->mouseMove(x, y); | ||
176 | |||
177 | gViewerWindow->setCursor(mLastSetCursor); | ||
178 | |||
179 | return TRUE; | ||
180 | } | ||
181 | |||
182 | //////////////////////////////////////////////////////////////////////////////// | ||
183 | // | ||
184 | BOOL LLMediaCtrl::handleScrollWheel( S32 x, S32 y, S32 clicks ) | ||
185 | { | ||
186 | if (mMediaSource && mMediaSource->hasMedia()) | ||
187 | mMediaSource->getMediaPlugin()->scrollEvent(0, clicks, MASK_NONE); | ||
188 | |||
189 | return TRUE; | ||
190 | } | ||
191 | |||
192 | //////////////////////////////////////////////////////////////////////////////// | ||
193 | // | ||
194 | BOOL LLMediaCtrl::handleMouseUp( S32 x, S32 y, MASK mask ) | ||
195 | { | ||
196 | convertInputCoords(x, y); | ||
197 | |||
198 | if (mMediaSource) | ||
199 | { | ||
200 | mMediaSource->mouseUp(x, y); | ||
201 | |||
202 | // *HACK: LLMediaImplLLMozLib automatically takes focus on mouseup, | ||
203 | // in addition to the onFocusReceived() call below. Undo this. JC | ||
204 | if (!mTakeFocusOnClick) | ||
205 | { | ||
206 | mMediaSource->focus(false); | ||
207 | gViewerWindow->focusClient(); | ||
208 | } | ||
209 | } | ||
210 | |||
211 | gFocusMgr.setMouseCapture( NULL ); | ||
212 | |||
213 | return TRUE; | ||
214 | } | ||
215 | |||
216 | //////////////////////////////////////////////////////////////////////////////// | ||
217 | // | ||
218 | BOOL LLMediaCtrl::handleMouseDown( S32 x, S32 y, MASK mask ) | ||
219 | { | ||
220 | convertInputCoords(x, y); | ||
221 | |||
222 | if (mMediaSource) | ||
223 | mMediaSource->mouseDown(x, y); | ||
224 | |||
225 | gFocusMgr.setMouseCapture( this ); | ||
226 | |||
227 | if (mTakeFocusOnClick) | ||
228 | { | ||
229 | setFocus( TRUE ); | ||
230 | } | ||
231 | |||
232 | return TRUE; | ||
233 | } | ||
234 | |||
235 | //////////////////////////////////////////////////////////////////////////////// | ||
236 | // | ||
237 | BOOL LLMediaCtrl::handleDoubleClick( S32 x, S32 y, MASK mask ) | ||
238 | { | ||
239 | convertInputCoords(x, y); | ||
240 | |||
241 | if (mMediaSource) | ||
242 | mMediaSource->mouseLeftDoubleClick( x, y ); | ||
243 | |||
244 | gFocusMgr.setMouseCapture( this ); | ||
245 | |||
246 | if (mTakeFocusOnClick) | ||
247 | { | ||
248 | setFocus( TRUE ); | ||
249 | } | ||
250 | |||
251 | return TRUE; | ||
252 | } | ||
253 | |||
254 | //////////////////////////////////////////////////////////////////////////////// | ||
255 | // | ||
256 | void LLMediaCtrl::onFocusReceived() | ||
257 | { | ||
258 | if (mMediaSource) | ||
259 | { | ||
260 | mMediaSource->focus(true); | ||
261 | |||
262 | // Set focus for edit menu items | ||
263 | LLEditMenuHandler::gEditMenuHandler = mMediaSource; | ||
264 | } | ||
265 | |||
266 | LLUICtrl::onFocusReceived(); | ||
267 | } | ||
268 | |||
269 | //////////////////////////////////////////////////////////////////////////////// | ||
270 | // | ||
271 | void LLMediaCtrl::onFocusLost() | ||
272 | { | ||
273 | if (mMediaSource) | ||
274 | { | ||
275 | mMediaSource->focus(false); | ||
276 | |||
277 | if( LLEditMenuHandler::gEditMenuHandler == mMediaSource ) | ||
278 | { | ||
279 | // Clear focus for edit menu items | ||
280 | LLEditMenuHandler::gEditMenuHandler = NULL; | ||
281 | } | ||
282 | } | ||
283 | |||
284 | gViewerWindow->focusClient(); | ||
285 | |||
286 | LLUICtrl::onFocusLost(); | ||
287 | } | ||
288 | |||
289 | //////////////////////////////////////////////////////////////////////////////// | ||
290 | // | ||
291 | BOOL LLMediaCtrl::handleKeyHere( KEY key, MASK mask ) | ||
292 | { | ||
293 | BOOL result = FALSE; | ||
294 | |||
295 | // FIXME: THIS IS SO WRONG. | ||
296 | // Menu keys should be handled by the menu system and not passed to UI elements, but this is how LLTextEditor and LLLineEditor do it... | ||
297 | |||
298 | if (mMediaSource) | ||
299 | { | ||
300 | if( MASK_CONTROL & mask ) | ||
301 | { | ||
302 | if( 'C' == key ) | ||
303 | { | ||
304 | mMediaSource->copy(); | ||
305 | result = TRUE; | ||
306 | } | ||
307 | else | ||
308 | if( 'V' == key ) | ||
309 | { | ||
310 | mMediaSource->paste(); | ||
311 | result = TRUE; | ||
312 | } | ||
313 | else | ||
314 | if( 'X' == key ) | ||
315 | { | ||
316 | mMediaSource->cut(); | ||
317 | result = TRUE; | ||
318 | } | ||
319 | } | ||
320 | |||
321 | if(!result) | ||
322 | { | ||
323 | result = mMediaSource->handleKeyHere(key, mask); | ||
324 | } | ||
325 | } | ||
326 | |||
327 | return result; | ||
328 | } | ||
329 | |||
330 | //////////////////////////////////////////////////////////////////////////////// | ||
331 | // | ||
332 | void LLMediaCtrl::handleVisibilityChange ( BOOL new_visibility ) | ||
333 | { | ||
334 | llinfos << "visibility changed to " << (new_visibility?"true":"false") << llendl; | ||
335 | if(mMediaSource) | ||
336 | { | ||
337 | mMediaSource->setVisible( new_visibility ); | ||
338 | } | ||
339 | } | ||
340 | |||
341 | //////////////////////////////////////////////////////////////////////////////// | ||
342 | // | ||
343 | BOOL LLMediaCtrl::handleUnicodeCharHere(llwchar uni_char) | ||
344 | { | ||
345 | BOOL result = FALSE; | ||
346 | |||
347 | // only accept 'printable' characters, sigh... | ||
348 | if (uni_char >= 32 // discard 'control' characters | ||
349 | && uni_char != 127) // SDL thinks this is 'delete' - yuck. | ||
350 | { | ||
351 | if (mMediaSource) | ||
352 | result = mMediaSource->handleUnicodeCharHere(uni_char); | ||
353 | } | ||
354 | |||
355 | return result; | ||
356 | } | ||
357 | |||
358 | //////////////////////////////////////////////////////////////////////////////// | ||
359 | // | ||
360 | void LLMediaCtrl::onVisibilityChange ( BOOL new_visibility ) | ||
361 | { | ||
362 | // set state of frequent updates automatically if visibility changes | ||
363 | if ( new_visibility ) | ||
364 | { | ||
365 | mFrequentUpdates = true; | ||
366 | } | ||
367 | else | ||
368 | { | ||
369 | mFrequentUpdates = false; | ||
370 | } | ||
371 | LLUICtrl::onVisibilityChange(new_visibility); | ||
372 | } | ||
373 | |||
374 | //////////////////////////////////////////////////////////////////////////////// | ||
375 | // | ||
376 | void LLMediaCtrl::reshape( S32 width, S32 height, BOOL called_from_parent ) | ||
377 | { | ||
378 | S32 screen_width = mIgnoreUIScale ? llround((F32)width * LLUI::sGLScaleFactor.mV[VX]) : width; | ||
379 | S32 screen_height = mIgnoreUIScale ? llround((F32)height * LLUI::sGLScaleFactor.mV[VY]) : height; | ||
380 | |||
381 | // llinfos << "reshape called with width = " << width << ", height = " << height << llendl; | ||
382 | |||
383 | // when floater is minimized, these sizes are negative | ||
384 | if ( mWebBrowserImage && screen_height > 0 && screen_width > 0 ) | ||
385 | { | ||
386 | mWebBrowserImage->resize( screen_width, screen_height ); | ||
387 | mForceUpdate = true; | ||
388 | } | ||
389 | |||
390 | LLUICtrl::reshape( width, height, called_from_parent ); | ||
391 | } | ||
392 | |||
393 | //////////////////////////////////////////////////////////////////////////////// | ||
394 | // | ||
395 | void LLMediaCtrl::navigateBack() | ||
396 | { | ||
397 | if (mMediaSource && mMediaSource->hasMedia()) | ||
398 | { | ||
399 | mMediaSource->getMediaPlugin()->browse_back(); | ||
400 | } | ||
401 | } | ||
402 | |||
403 | //////////////////////////////////////////////////////////////////////////////// | ||
404 | // | ||
405 | void LLMediaCtrl::navigateForward() | ||
406 | { | ||
407 | if (mMediaSource && mMediaSource->hasMedia()) | ||
408 | { | ||
409 | mMediaSource->getMediaPlugin()->browse_forward(); | ||
410 | } | ||
411 | } | ||
412 | |||
413 | //////////////////////////////////////////////////////////////////////////////// | ||
414 | // | ||
415 | bool LLMediaCtrl::canNavigateBack() | ||
416 | { | ||
417 | if (mMediaSource) | ||
418 | return mMediaSource->canNavigateBack(); | ||
419 | else | ||
420 | return false; | ||
421 | } | ||
422 | |||
423 | //////////////////////////////////////////////////////////////////////////////// | ||
424 | // | ||
425 | bool LLMediaCtrl::canNavigateForward() | ||
426 | { | ||
427 | if (mMediaSource) | ||
428 | return mMediaSource->canNavigateForward(); | ||
429 | else | ||
430 | return false; | ||
431 | } | ||
432 | |||
433 | //////////////////////////////////////////////////////////////////////////////// | ||
434 | // | ||
435 | void LLMediaCtrl::set404RedirectUrl( std::string redirect_url ) | ||
436 | { | ||
437 | if(mMediaSource && mMediaSource->hasMedia()) | ||
438 | mMediaSource->getMediaPlugin()->set_status_redirect( 404, redirect_url ); | ||
439 | } | ||
440 | |||
441 | //////////////////////////////////////////////////////////////////////////////// | ||
442 | // | ||
443 | void LLMediaCtrl::clr404RedirectUrl() | ||
444 | { | ||
445 | if(mMediaSource && mMediaSource->hasMedia()) | ||
446 | mMediaSource->getMediaPlugin()->set_status_redirect(404, ""); | ||
447 | } | ||
448 | |||
449 | //////////////////////////////////////////////////////////////////////////////// | ||
450 | // | ||
451 | void LLMediaCtrl::navigateTo( std::string url_in, std::string mime_type) | ||
452 | { | ||
453 | // don't browse to anything that starts with secondlife:// or sl:// | ||
454 | const std::string protocol1 = "secondlife://"; | ||
455 | const std::string protocol2 = "sl://"; | ||
456 | if ((LLStringUtil::compareInsensitive(url_in.substr(0, protocol1.length()), protocol1) == 0) || | ||
457 | (LLStringUtil::compareInsensitive(url_in.substr(0, protocol2.length()), protocol2) == 0)) | ||
458 | { | ||
459 | // TODO: Print out/log this attempt? | ||
460 | // llinfos << "Rejecting attempt to load restricted website :" << urlIn << llendl; | ||
461 | return; | ||
462 | } | ||
463 | |||
464 | if (mMediaSource) | ||
465 | { | ||
466 | mCurrentNavUrl = url_in; | ||
467 | mMediaSource->navigateTo(url_in, mime_type, mime_type.empty()); | ||
468 | } | ||
469 | } | ||
470 | |||
471 | //////////////////////////////////////////////////////////////////////////////// | ||
472 | // | ||
473 | void LLMediaCtrl::navigateToLocalPage( const std::string& subdir, const std::string& filename_in ) | ||
474 | { | ||
475 | std::string language = LLUI::getLanguage(); | ||
476 | std::string delim = gDirUtilp->getDirDelimiter(); | ||
477 | std::string filename; | ||
478 | |||
479 | filename += subdir; | ||
480 | filename += delim; | ||
481 | filename += filename_in; | ||
482 | |||
483 | std::string expanded_filename = gDirUtilp->findSkinnedFilename("html", language, filename); | ||
484 | |||
485 | if (! gDirUtilp->fileExists(expanded_filename)) | ||
486 | { | ||
487 | if (language != "en-us") | ||
488 | { | ||
489 | expanded_filename = gDirUtilp->findSkinnedFilename("html", "en-us", filename); | ||
490 | if (! gDirUtilp->fileExists(expanded_filename)) | ||
491 | { | ||
492 | llwarns << "File " << subdir << delim << filename_in << "not found" << llendl; | ||
493 | return; | ||
494 | } | ||
495 | } | ||
496 | else | ||
497 | { | ||
498 | llwarns << "File " << subdir << delim << filename_in << "not found" << llendl; | ||
499 | return; | ||
500 | } | ||
501 | } | ||
502 | if (mMediaSource) | ||
503 | { | ||
504 | mCurrentNavUrl = expanded_filename; | ||
505 | mMediaSource->navigateTo(expanded_filename, "text/html", false); | ||
506 | } | ||
507 | |||
508 | } | ||
509 | |||
510 | //////////////////////////////////////////////////////////////////////////////// | ||
511 | // | ||
512 | void LLMediaCtrl::navigateHome() | ||
513 | { | ||
514 | if( mHomePageUrl.length() ) | ||
515 | { | ||
516 | if (mMediaSource) | ||
517 | mMediaSource->navigateTo(mHomePageUrl); | ||
518 | }; | ||
519 | } | ||
520 | |||
521 | //////////////////////////////////////////////////////////////////////////////// | ||
522 | // | ||
523 | void LLMediaCtrl::setHomePageUrl( const std::string urlIn ) | ||
524 | { | ||
525 | mHomePageUrl = urlIn; | ||
526 | } | ||
527 | |||
528 | //////////////////////////////////////////////////////////////////////////////// | ||
529 | // | ||
530 | bool LLMediaCtrl::setCaretColor(unsigned int red, unsigned int green, unsigned int blue) | ||
531 | { | ||
532 | //NOOP | ||
533 | return false; | ||
534 | } | ||
535 | //////////////////////////////////////////////////////////////////////////////// | ||
536 | // | ||
537 | std::string LLMediaCtrl::getHomePageUrl() | ||
538 | { | ||
539 | return mHomePageUrl; | ||
540 | } | ||
541 | |||
542 | //////////////////////////////////////////////////////////////////////////////// | ||
543 | // | ||
544 | LLPluginClassMedia* LLMediaCtrl::getMediaPlugin() | ||
545 | { | ||
546 | return mMediaSource.isNull() ? NULL : mMediaSource->getMediaPlugin(); | ||
547 | } | ||
548 | |||
549 | //////////////////////////////////////////////////////////////////////////////// | ||
550 | // | ||
551 | void LLMediaCtrl::draw() | ||
552 | { | ||
553 | if ( ! mWebBrowserImage ) | ||
554 | return; | ||
555 | |||
556 | if ( gRestoreGL == 1 ) | ||
557 | { | ||
558 | LLRect r = getRect(); | ||
559 | reshape( r.getWidth(), r.getHeight(), FALSE ); | ||
560 | return; | ||
561 | }; | ||
562 | |||
563 | // NOTE: optimization needed here - probably only need to do this once | ||
564 | // unless tearoffs change the parent which they probably do. | ||
565 | const LLUICtrl* ptr = findRootMostFocusRoot(); | ||
566 | if ( ptr && ptr->hasFocus() ) | ||
567 | { | ||
568 | setFrequentUpdates( true ); | ||
569 | } | ||
570 | else | ||
571 | { | ||
572 | setFrequentUpdates( false ); | ||
573 | }; | ||
574 | |||
575 | // alpha off for this | ||
576 | LLGLSUIDefault gls_ui; | ||
577 | LLGLDisable gls_alphaTest( GL_ALPHA_TEST ); | ||
578 | |||
579 | gGL.pushMatrix(); | ||
580 | { | ||
581 | if (mIgnoreUIScale) | ||
582 | { | ||
583 | glLoadIdentity(); | ||
584 | // font system stores true screen origin, need to scale this by UI scale factor | ||
585 | // to get render origin for this view (with unit scale) | ||
586 | gGL.translatef(floorf(LLFontGL::sCurOrigin.mX * LLUI::sGLScaleFactor.mV[VX]), | ||
587 | floorf(LLFontGL::sCurOrigin.mY * LLUI::sGLScaleFactor.mV[VY]), | ||
588 | LLFontGL::sCurOrigin.mZ); | ||
589 | } | ||
590 | |||
591 | // scale texture to fit the space using texture coords | ||
592 | gGL.getTexUnit(0)->bind(mWebBrowserImage->getTexture()); | ||
593 | gGL.color4fv( LLColor4::white.mV ); | ||
594 | F32 max_u = ( F32 )mWebBrowserImage->getMediaWidth() / ( F32 )mWebBrowserImage->getWidth(); | ||
595 | F32 max_v = ( F32 )mWebBrowserImage->getMediaHeight() / ( F32 )mWebBrowserImage->getHeight(); | ||
596 | |||
597 | LLRect r = getRect(); | ||
598 | S32 width, height; | ||
599 | S32 x_offset = 0; | ||
600 | S32 y_offset = 0; | ||
601 | |||
602 | if(mStretchToFill) | ||
603 | { | ||
604 | if(mMaintainAspectRatio) | ||
605 | { | ||
606 | F32 media_aspect = (F32)(mWebBrowserImage->getMediaWidth()) / (F32)(mWebBrowserImage->getMediaHeight()); | ||
607 | F32 view_aspect = (F32)(r.getWidth()) / (F32)(r.getHeight()); | ||
608 | if(media_aspect > view_aspect) | ||
609 | { | ||
610 | // max width, adjusted height | ||
611 | width = r.getWidth(); | ||
612 | height = llmin(llmax(S32(width / media_aspect), 0), r.getHeight()); | ||
613 | } | ||
614 | else | ||
615 | { | ||
616 | // max height, adjusted width | ||
617 | height = r.getHeight(); | ||
618 | width = llmin(llmax(S32(height * media_aspect), 0), r.getWidth()); | ||
619 | } | ||
620 | } | ||
621 | else | ||
622 | { | ||
623 | width = r.getWidth(); | ||
624 | height = r.getHeight(); | ||
625 | } | ||
626 | } | ||
627 | else | ||
628 | { | ||
629 | width = llmin(mWebBrowserImage->getMediaWidth(), r.getWidth()); | ||
630 | height = llmin(mWebBrowserImage->getMediaHeight(), r.getHeight()); | ||
631 | } | ||
632 | |||
633 | x_offset = (r.getWidth() - width) / 2; | ||
634 | y_offset = (r.getHeight() - height) / 2; | ||
635 | |||
636 | if (mIgnoreUIScale) | ||
637 | { | ||
638 | width = llround((F32)width * LLUI::sGLScaleFactor.mV[VX]); | ||
639 | height = llround((F32)height * LLUI::sGLScaleFactor.mV[VY]); | ||
640 | x_offset = llround((F32)x_offset * LLUI::sGLScaleFactor.mV[VX]); | ||
641 | y_offset = llround((F32)y_offset * LLUI::sGLScaleFactor.mV[VY]); | ||
642 | } | ||
643 | |||
644 | // draw the browser | ||
645 | gGL.setSceneBlendType(LLRender::BT_REPLACE); | ||
646 | gGL.begin( LLRender::QUADS ); | ||
647 | if (! mWebBrowserImage->getTextureCoordsOpenGL()) | ||
648 | { | ||
649 | // render using web browser reported width and height, instead of trying to invert GL scale | ||
650 | gGL.texCoord2f( max_u, 0.f ); | ||
651 | gGL.vertex2i( x_offset + width, y_offset + height ); | ||
652 | |||
653 | gGL.texCoord2f( 0.f, 0.f ); | ||
654 | gGL.vertex2i( x_offset, y_offset + height ); | ||
655 | |||
656 | gGL.texCoord2f( 0.f, max_v ); | ||
657 | gGL.vertex2i( x_offset, y_offset ); | ||
658 | |||
659 | gGL.texCoord2f( max_u, max_v ); | ||
660 | gGL.vertex2i( x_offset + width, y_offset ); | ||
661 | } | ||
662 | else | ||
663 | { | ||
664 | // render using web browser reported width and height, instead of trying to invert GL scale | ||
665 | gGL.texCoord2f( max_u, max_v ); | ||
666 | gGL.vertex2i( x_offset + width, y_offset + height ); | ||
667 | |||
668 | gGL.texCoord2f( 0.f, max_v ); | ||
669 | gGL.vertex2i( x_offset, y_offset + height ); | ||
670 | |||
671 | gGL.texCoord2f( 0.f, 0.f ); | ||
672 | gGL.vertex2i( x_offset, y_offset ); | ||
673 | |||
674 | gGL.texCoord2f( max_u, 0.f ); | ||
675 | gGL.vertex2i( x_offset + width, y_offset ); | ||
676 | } | ||
677 | gGL.end(); | ||
678 | gGL.setSceneBlendType(LLRender::BT_ALPHA); | ||
679 | } | ||
680 | gGL.popMatrix(); | ||
681 | |||
682 | // highlight if keyboard focus here. (TODO: this needs some work) | ||
683 | if ( mBorder->getVisible() ) | ||
684 | mBorder->setKeyboardFocusHighlight( gFocusMgr.childHasKeyboardFocus( this ) ); | ||
685 | |||
686 | |||
687 | LLUICtrl::draw(); | ||
688 | } | ||
689 | |||
690 | //////////////////////////////////////////////////////////////////////////////// | ||
691 | // | ||
692 | void LLMediaCtrl::convertInputCoords(S32& x, S32& y) | ||
693 | { | ||
694 | x = mIgnoreUIScale ? llround((F32)x * LLUI::sGLScaleFactor.mV[VX]) : x; | ||
695 | if ( ! mWebBrowserImage->getTextureCoordsOpenGL() ) | ||
696 | { | ||
697 | y = mIgnoreUIScale ? llround((F32)(y) * LLUI::sGLScaleFactor.mV[VY]) : y; | ||
698 | } | ||
699 | else | ||
700 | { | ||
701 | y = mIgnoreUIScale ? llround((F32)(getRect().getHeight() - y) * LLUI::sGLScaleFactor.mV[VY]) : getRect().getHeight() - y; | ||
702 | }; | ||
703 | } | ||
704 | |||
705 | //////////////////////////////////////////////////////////////////////////////// | ||
706 | // static | ||
707 | bool LLMediaCtrl::onClickLinkExternalTarget(const LLSD& notification, const LLSD& response ) | ||
708 | { | ||
709 | S32 option = LLNotification::getSelectedOption(notification, response); | ||
710 | if ( 0 == option ) | ||
711 | { | ||
712 | // open in external browser because we don't support | ||
713 | // creation of our own secondary browser windows | ||
714 | LLWeb::loadURLExternal( notification["payload"]["external_url"].asString() ); | ||
715 | } | ||
716 | return false; | ||
717 | } | ||
718 | |||
719 | //////////////////////////////////////////////////////////////////////////////// | ||
720 | // inherited from LLViewerMediaObserver | ||
721 | //virtual | ||
722 | void LLMediaCtrl::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event) | ||
723 | { | ||
724 | switch(event) | ||
725 | { | ||
726 | case MEDIA_EVENT_CONTENT_UPDATED: | ||
727 | { | ||
728 | // LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CONTENT_UPDATED " << LL_ENDL; | ||
729 | }; | ||
730 | break; | ||
731 | |||
732 | case MEDIA_EVENT_TIME_DURATION_UPDATED: | ||
733 | { | ||
734 | // LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_TIME_DURATION_UPDATED, time is " << self->getCurrentTime() << " of " << self->getDuration() << LL_ENDL; | ||
735 | }; | ||
736 | break; | ||
737 | |||
738 | case MEDIA_EVENT_SIZE_CHANGED: | ||
739 | { | ||
740 | LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_SIZE_CHANGED " << LL_ENDL; | ||
741 | LLRect r = getRect(); | ||
742 | reshape( r.getWidth(), r.getHeight(), FALSE ); | ||
743 | }; | ||
744 | break; | ||
745 | |||
746 | case MEDIA_EVENT_CURSOR_CHANGED: | ||
747 | { | ||
748 | LL_INFOS("Media") << "Media event: MEDIA_EVENT_CURSOR_CHANGED, new cursor is " << self->getCursorName() << LL_ENDL; | ||
749 | |||
750 | std::string cursor = self->getCursorName(); | ||
751 | |||
752 | if(cursor == "arrow") | ||
753 | mLastSetCursor = UI_CURSOR_ARROW; | ||
754 | else if(cursor == "ibeam") | ||
755 | mLastSetCursor = UI_CURSOR_IBEAM; | ||
756 | else if(cursor == "splith") | ||
757 | mLastSetCursor = UI_CURSOR_SIZEWE; | ||
758 | else if(cursor == "splitv") | ||
759 | mLastSetCursor = UI_CURSOR_SIZENS; | ||
760 | else if(cursor == "hand") | ||
761 | mLastSetCursor = UI_CURSOR_HAND; | ||
762 | else // for anything else, default to the arrow | ||
763 | mLastSetCursor = UI_CURSOR_ARROW; | ||
764 | }; | ||
765 | break; | ||
766 | |||
767 | case MEDIA_EVENT_NAVIGATE_BEGIN: | ||
768 | { | ||
769 | LL_INFOS("Media") << "Media event: MEDIA_EVENT_NAVIGATE_BEGIN, url is " << self->getNavigateURI() << LL_ENDL; | ||
770 | if(mMediaSource && mHideLoading) | ||
771 | { | ||
772 | mMediaSource->suspendUpdates(true); | ||
773 | } | ||
774 | }; | ||
775 | break; | ||
776 | |||
777 | case MEDIA_EVENT_NAVIGATE_COMPLETE: | ||
778 | { | ||
779 | LL_INFOS("Media") << "Media event: MEDIA_EVENT_NAVIGATE_COMPLETE, result string is: " << self->getNavigateResultString() << LL_ENDL; | ||
780 | if(mMediaSource && mHideLoading) | ||
781 | { | ||
782 | mMediaSource->suspendUpdates(false); | ||
783 | } | ||
784 | }; | ||
785 | break; | ||
786 | |||
787 | case MEDIA_EVENT_PROGRESS_UPDATED: | ||
788 | { | ||
789 | LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_PROGRESS_UPDATED, loading at " << self->getProgressPercent() << "%" << LL_ENDL; | ||
790 | }; | ||
791 | break; | ||
792 | |||
793 | case MEDIA_EVENT_STATUS_TEXT_CHANGED: | ||
794 | { | ||
795 | LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_STATUS_TEXT_CHANGED, new status text is: " << self->getStatusText() << LL_ENDL; | ||
796 | }; | ||
797 | break; | ||
798 | |||
799 | case MEDIA_EVENT_LOCATION_CHANGED: | ||
800 | { | ||
801 | LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_LOCATION_CHANGED, new uri is: " << self->getLocation() << LL_ENDL; | ||
802 | }; | ||
803 | break; | ||
804 | |||
805 | case MEDIA_EVENT_CLICK_LINK_HREF: | ||
806 | { | ||
807 | LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CLICK_LINK_HREF, target is \"" << self->getClickTarget() << "\", uri is " << self->getClickURL() << LL_ENDL; | ||
808 | onClickLinkHref(self); | ||
809 | }; | ||
810 | break; | ||
811 | |||
812 | case MEDIA_EVENT_CLICK_LINK_NOFOLLOW: | ||
813 | { | ||
814 | LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CLICK_LINK_NOFOLLOW, uri is " << self->getClickURL() << LL_ENDL; | ||
815 | onClickLinkNoFollow(self); | ||
816 | }; | ||
817 | break; | ||
818 | |||
819 | case MEDIA_EVENT_PLUGIN_FAILED: | ||
820 | { | ||
821 | LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_PLUGIN_FAILED" << LL_ENDL; | ||
822 | }; | ||
823 | break; | ||
824 | |||
825 | case MEDIA_EVENT_PLUGIN_FAILED_LAUNCH: | ||
826 | { | ||
827 | LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_PLUGIN_FAILED_LAUNCH" << LL_ENDL; | ||
828 | }; | ||
829 | break; | ||
830 | |||
831 | case MEDIA_EVENT_NAME_CHANGED: | ||
832 | { | ||
833 | LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_NAME_CHANGED" << LL_ENDL; | ||
834 | }; | ||
835 | break; | ||
836 | }; | ||
837 | |||
838 | // chain all events to any potential observers of this object. | ||
839 | emitEvent(self, event); | ||
840 | } | ||
841 | |||
842 | //////////////////////////////////////////////////////////////////////////////// | ||
843 | // | ||
844 | void LLMediaCtrl::onClickLinkHref( LLPluginClassMedia* self ) | ||
845 | { | ||
846 | // retrieve the event parameters | ||
847 | std::string target = self->getClickTarget(); | ||
848 | std::string url = self->getClickURL(); | ||
849 | |||
850 | // if there is a value for the target | ||
851 | if ( !target.empty() ) | ||
852 | { | ||
853 | if ( target == "_external" ) | ||
854 | { | ||
855 | mExternalUrl = url; | ||
856 | LLSD payload; | ||
857 | payload["external_url"] = mExternalUrl; | ||
858 | LLNotifications::instance().add( "WebLaunchExternalTarget", LLSD(), payload, onClickLinkExternalTarget); | ||
859 | return; | ||
860 | } | ||
861 | } | ||
862 | |||
863 | const std::string protocol1( "http://" ); | ||
864 | const std::string protocol2( "https://" ); | ||
865 | if( mOpenLinksInExternalBrowser ) | ||
866 | { | ||
867 | if ( !url.empty() ) | ||
868 | { | ||
869 | if ( LLStringUtil::compareInsensitive( url.substr( 0, protocol1.length() ), protocol1 ) == 0 || | ||
870 | LLStringUtil::compareInsensitive( url.substr( 0, protocol2.length() ), protocol2 ) == 0 ) | ||
871 | { | ||
872 | LLWeb::loadURLExternal( url ); | ||
873 | } | ||
874 | } | ||
875 | } | ||
876 | else | ||
877 | if( mOpenLinksInInternalBrowser ) | ||
878 | { | ||
879 | if ( !url.empty() ) | ||
880 | { | ||
881 | if ( LLStringUtil::compareInsensitive( url.substr( 0, protocol1.length() ), protocol1 ) == 0 || | ||
882 | LLStringUtil::compareInsensitive( url.substr( 0, protocol2.length() ), protocol2 ) == 0 ) | ||
883 | { | ||
884 | // If we spawn a new LLFloaterHTML, assume we want it to | ||
885 | // follow this LLMediaCtrl's trust for whether or | ||
886 | // not to open secondlife:///app/ links. JC. | ||
887 | // const bool open_links_externally = false; | ||
888 | // LLFloaterHtml::getInstance()->show( | ||
889 | // event_in.mStringPayload, | ||
890 | // "Second Life Browser", | ||
891 | // open_links_externally, | ||
892 | // mTrusted); | ||
893 | } | ||
894 | } | ||
895 | } | ||
896 | } | ||
897 | |||
898 | //////////////////////////////////////////////////////////////////////////////// | ||
899 | // | ||
900 | void LLMediaCtrl::onClickLinkNoFollow( LLPluginClassMedia* self ) | ||
901 | { | ||
902 | std::string url = self->getClickURL(); | ||
903 | if (LLURLDispatcher::isSLURLCommand(url) | ||
904 | && !mTrusted) | ||
905 | { | ||
906 | // block handling of this secondlife:///app/ URL | ||
907 | LLNotifications::instance().add("UnableToOpenCommandURL"); | ||
908 | return; | ||
909 | } | ||
910 | |||
911 | LLURLDispatcher::dispatch(url, this, mTrusted); | ||
912 | } | ||
913 | |||
914 | //////////////////////////////////////////////////////////////////////////////// | ||
915 | // | ||
916 | LLWebBrowserTexture::LLWebBrowserTexture( S32 width, S32 height, LLMediaCtrl* browserCtrl, viewer_media_t media_source ) : | ||
917 | LLDynamicTexture( 512, 512, 4, ORDER_FIRST, TRUE ), | ||
918 | mNeedsUpdate( true ), | ||
919 | mNeedsResize( false ), | ||
920 | mTextureCoordsOpenGL( true ), | ||
921 | mWebBrowserCtrl( browserCtrl ), | ||
922 | mMediaSource(media_source) | ||
923 | { | ||
924 | mElapsedTime.start(); | ||
925 | |||
926 | resize( width, height ); | ||
927 | } | ||
928 | |||
929 | //////////////////////////////////////////////////////////////////////////////// | ||
930 | // | ||
931 | LLWebBrowserTexture::~LLWebBrowserTexture() | ||
932 | { | ||
933 | mElapsedTime.stop(); | ||
934 | mMediaSource = NULL; | ||
935 | } | ||
936 | |||
937 | //////////////////////////////////////////////////////////////////////////////// | ||
938 | // | ||
939 | BOOL LLWebBrowserTexture::needsRender() | ||
940 | { | ||
941 | bool texture_dirty = false; | ||
942 | |||
943 | if ( mWebBrowserCtrl->getFrequentUpdates() || | ||
944 | mWebBrowserCtrl->getAlwaysRefresh() || | ||
945 | mWebBrowserCtrl->getForceUpdate() ) | ||
946 | { | ||
947 | // All of these force an update | ||
948 | return TRUE; | ||
949 | } | ||
950 | |||
951 | // If the texture needs updating, render needs to be called. | ||
952 | if (mMediaSource && mMediaSource->hasMedia()) | ||
953 | { | ||
954 | LLPluginClassMedia* media = mMediaSource->getMediaPlugin(); | ||
955 | |||
956 | if(media->textureValid() && media->getDirty()) | ||
957 | { | ||
958 | texture_dirty = true; | ||
959 | } | ||
960 | } | ||
961 | |||
962 | |||
963 | return texture_dirty; | ||
964 | } | ||
965 | |||
966 | //////////////////////////////////////////////////////////////////////////////// | ||
967 | // | ||
968 | BOOL LLWebBrowserTexture::render() | ||
969 | { | ||
970 | if(updateBrowserTexture()) | ||
971 | { | ||
972 | // updateBrowserTexture already verified that the media plugin is there and the texture is valid. | ||
973 | LLPluginClassMedia* media_plugin = mMediaSource->getMediaPlugin(); | ||
974 | LLRect dirty_rect; | ||
975 | |||
976 | if(mNeedsUpdate) | ||
977 | { | ||
978 | // If we need an update, use the whole rect instead of the dirty rect. | ||
979 | dirty_rect.mLeft = 0; | ||
980 | dirty_rect.mBottom = 0; | ||
981 | dirty_rect.mRight = media_plugin->getWidth(); | ||
982 | dirty_rect.mTop = media_plugin->getHeight(); | ||
983 | } | ||
984 | else | ||
985 | { | ||
986 | mNeedsUpdate = media_plugin->getDirty(&dirty_rect); | ||
987 | } | ||
988 | |||
989 | if ( mNeedsUpdate ) | ||
990 | { | ||
991 | mNeedsUpdate = false; | ||
992 | mWebBrowserCtrl->setForceUpdate(false); | ||
993 | |||
994 | // Constrain the dirty rect to be inside the texture | ||
995 | S32 x_pos = llmax(dirty_rect.mLeft, 0); | ||
996 | S32 y_pos = llmax(dirty_rect.mBottom, 0); | ||
997 | S32 width = llmin(dirty_rect.mRight, getWidth()) - x_pos; | ||
998 | S32 height = llmin(dirty_rect.mTop, getHeight()) - y_pos; | ||
999 | |||
1000 | if(width > 0 && height > 0) | ||
1001 | { | ||
1002 | U8* data = media_plugin->getBitsData(); | ||
1003 | |||
1004 | // Offset the pixels pointer to match x_pos and y_pos | ||
1005 | data += ( x_pos * media_plugin->getTextureDepth() * media_plugin->getBitsWidth() ); | ||
1006 | data += ( y_pos * media_plugin->getTextureDepth() ); | ||
1007 | |||
1008 | mTexture->setSubImage( | ||
1009 | data, | ||
1010 | media_plugin->getBitsWidth(), | ||
1011 | media_plugin->getBitsHeight(), | ||
1012 | x_pos, | ||
1013 | y_pos, | ||
1014 | width, | ||
1015 | height, | ||
1016 | TRUE); // force a fast update (i.e. don't call analyzeAlpha, etc.) | ||
1017 | } | ||
1018 | |||
1019 | media_plugin->resetDirty(); | ||
1020 | |||
1021 | return TRUE; | ||
1022 | }; | ||
1023 | }; | ||
1024 | |||
1025 | return FALSE; | ||
1026 | } | ||
1027 | |||
1028 | //////////////////////////////////////////////////////////////////////////////// | ||
1029 | // | ||
1030 | S32 LLWebBrowserTexture::getMediaWidth() | ||
1031 | { | ||
1032 | return mMediaWidth; | ||
1033 | } | ||
1034 | |||
1035 | //////////////////////////////////////////////////////////////////////////////// | ||
1036 | // | ||
1037 | S32 LLWebBrowserTexture::getMediaHeight() | ||
1038 | { | ||
1039 | return mMediaHeight; | ||
1040 | } | ||
1041 | |||
1042 | //////////////////////////////////////////////////////////////////////////////// | ||
1043 | // | ||
1044 | void LLWebBrowserTexture::setNeedsUpdate() | ||
1045 | { | ||
1046 | mNeedsUpdate = true; | ||
1047 | } | ||
1048 | |||
1049 | //////////////////////////////////////////////////////////////////////////////// | ||
1050 | // | ||
1051 | bool LLWebBrowserTexture::getNeedsUpdate() | ||
1052 | { | ||
1053 | return mNeedsUpdate; | ||
1054 | } | ||
1055 | |||
1056 | //////////////////////////////////////////////////////////////////////////////// | ||
1057 | // | ||
1058 | bool LLWebBrowserTexture::getTextureCoordsOpenGL() | ||
1059 | { | ||
1060 | return mTextureCoordsOpenGL; | ||
1061 | } | ||
1062 | |||
1063 | |||
1064 | //////////////////////////////////////////////////////////////////////////////// | ||
1065 | // | ||
1066 | void LLWebBrowserTexture::resize( S32 new_width, S32 new_height ) | ||
1067 | { | ||
1068 | F32 scale_ratio = 1.f; | ||
1069 | if (new_width > MAX_DIMENSION) | ||
1070 | { | ||
1071 | scale_ratio = (F32)MAX_DIMENSION / (F32)new_width; | ||
1072 | } | ||
1073 | if (new_height > MAX_DIMENSION) | ||
1074 | { | ||
1075 | scale_ratio = llmin(scale_ratio, (F32)MAX_DIMENSION / (F32)new_height); | ||
1076 | } | ||
1077 | |||
1078 | mMediaWidth = llround(scale_ratio * (F32)new_width); | ||
1079 | mMediaHeight = llround(scale_ratio * (F32)new_height); | ||
1080 | |||
1081 | adjustSize(); | ||
1082 | } | ||
1083 | |||
1084 | bool LLWebBrowserTexture::adjustSize() | ||
1085 | { | ||
1086 | if (mMediaSource && mMediaSource->hasMedia()) | ||
1087 | { | ||
1088 | int natural_width = mMediaSource->getMediaPlugin()->getNaturalWidth(); | ||
1089 | int natural_height = mMediaSource->getMediaPlugin()->getNaturalHeight(); | ||
1090 | |||
1091 | if(natural_width != 0) | ||
1092 | { | ||
1093 | // If the media has a "natural size", use it. | ||
1094 | mMediaWidth = natural_width; | ||
1095 | mMediaHeight = natural_height; | ||
1096 | } | ||
1097 | |||
1098 | mMediaSource->setSize(mMediaWidth, mMediaHeight); | ||
1099 | mNeedsResize = false; | ||
1100 | |||
1101 | return true; | ||
1102 | } | ||
1103 | else | ||
1104 | { | ||
1105 | // The media isn't fully initialized yet, delay the resize until later. | ||
1106 | mNeedsResize = true; | ||
1107 | } | ||
1108 | |||
1109 | return false; | ||
1110 | } | ||
1111 | |||
1112 | bool LLWebBrowserTexture::updateBrowserTexture() | ||
1113 | { | ||
1114 | if (!adjustSize()) | ||
1115 | return false; | ||
1116 | |||
1117 | LLPluginClassMedia* media = mMediaSource->getMediaPlugin(); | ||
1118 | |||
1119 | if(!media->textureValid()) | ||
1120 | return false; | ||
1121 | |||
1122 | if(mMediaSource->mNeedsNewTexture | ||
1123 | || media->getTextureWidth() != mWidth | ||
1124 | || media->getTextureHeight() != mHeight ) | ||
1125 | { | ||
1126 | releaseGLTexture(); | ||
1127 | |||
1128 | mWidth = media->getTextureWidth(); | ||
1129 | mHeight = media->getTextureHeight(); | ||
1130 | mTextureCoordsOpenGL = media->getTextureCoordsOpenGL(); | ||
1131 | |||
1132 | // will create mWidth * mHeight sized texture, using the texture params specified by the media. | ||
1133 | LLDynamicTexture::generateGLTexture( | ||
1134 | media->getTextureFormatInternal(), | ||
1135 | media->getTextureFormatPrimary(), | ||
1136 | media->getTextureFormatType(), | ||
1137 | media->getTextureFormatSwapBytes()); | ||
1138 | |||
1139 | |||
1140 | mMediaSource->mNeedsNewTexture = false; | ||
1141 | } | ||
1142 | |||
1143 | return true; | ||
1144 | } | ||
1145 | // virtual | ||
1146 | LLXMLNodePtr LLMediaCtrl::getXML(bool save_children) const | ||
1147 | { | ||
1148 | LLXMLNodePtr node = LLUICtrl::getXML(); | ||
1149 | |||
1150 | node->setName(LL_WEB_BROWSER_CTRL_TAG); | ||
1151 | |||
1152 | return node; | ||
1153 | } | ||
1154 | |||
1155 | LLView* LLMediaCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory) | ||
1156 | { | ||
1157 | std::string name("web_browser"); | ||
1158 | node->getAttributeString("name", name); | ||
1159 | |||
1160 | std::string start_url(""); | ||
1161 | node->getAttributeString("start_url", start_url ); | ||
1162 | |||
1163 | BOOL border_visible = true; | ||
1164 | node->getAttributeBOOL("border_visible", border_visible); | ||
1165 | |||
1166 | LLRect rect; | ||
1167 | createRect(node, rect, parent, LLRect()); | ||
1168 | |||
1169 | LLMediaCtrl* web_browser = new LLMediaCtrl( name, rect ); | ||
1170 | |||
1171 | if(node->hasAttribute("caret_color")) | ||
1172 | { | ||
1173 | LLColor4 color; | ||
1174 | LLUICtrlFactory::getAttributeColor(node, "caret_color", color); | ||
1175 | LLColor4U colorU = LLColor4U(color); | ||
1176 | web_browser->setCaretColor( colorU.mV[0], colorU.mV[1], colorU.mV[2] ); | ||
1177 | } | ||
1178 | |||
1179 | BOOL ignore_ui_scale = web_browser->getIgnoreUIScale(); | ||
1180 | node->getAttributeBOOL("ignore_ui_scale", ignore_ui_scale); | ||
1181 | web_browser->setIgnoreUIScale((bool)ignore_ui_scale); | ||
1182 | |||
1183 | web_browser->initFromXML(node, parent); | ||
1184 | |||
1185 | web_browser->setHomePageUrl( start_url ); | ||
1186 | |||
1187 | web_browser->setBorderVisible( border_visible ); | ||
1188 | |||
1189 | if(! start_url.empty()) | ||
1190 | { | ||
1191 | web_browser->navigateHome(); | ||
1192 | } | ||
1193 | |||
1194 | return web_browser; | ||
1195 | } | ||
1196 | |||
1197 | std::string LLMediaCtrl::getCurrentNavUrl() | ||
1198 | { | ||
1199 | return mCurrentNavUrl; | ||
1200 | } | ||
1201 | |||