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