diff options
| author | Maxim Nikolenko <maximnproductengine@lindenlab.com> | 2026-05-05 00:06:15 +0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-05-05 00:06:15 +0300 |
| commit | d70047880d8d4e1d8e37ca6dfdc4a622837184f8 (patch) | |
| tree | b61dc5e47498f3e5168d645d9815a5ec18f8aa0b | |
| parent | fa7b2292bb5ea3b75fc5b18a468c5ca80c9530ee (diff) | |
#5682 add LEAP API to get info about web_browser widget
| -rw-r--r-- | indra/newview/llmediactrl.cpp | 184 | ||||
| -rw-r--r-- | indra/newview/llmediactrl.h | 14 |
2 files changed, 198 insertions, 0 deletions
diff --git a/indra/newview/llmediactrl.cpp b/indra/newview/llmediactrl.cpp index 4a808ba052..679157dc1e 100644 --- a/indra/newview/llmediactrl.cpp +++ b/indra/newview/llmediactrl.cpp @@ -62,9 +62,15 @@ #include "lllineeditor.h" #include "llfloaterwebcontent.h" #include "llwindowshade.h" +#include "lleventapi.h" +#include "llui.h" extern bool gRestoreGL; +const std::string PAGE_TEXT_EXTRACT_MARKER = "PAGE_TEXT_EXTRACT:"; + +class LLMediaCtrlListener; + static LLDefaultChildRegistry::Register<LLMediaCtrl> r("web_browser"); LLMediaCtrl::Params::Params() @@ -100,6 +106,7 @@ LLMediaCtrl::LLMediaCtrl( const Params& p) : mUpdateScrolls( false ), mTextureWidth ( 1024 ), mTextureHeight ( 1024 ), + mLoadingState( LOADING_STATE_INITIALIZING ), mClearCache(false), mHomePageMimeType(p.initial_mime_type), mErrorPageURL(p.error_page_url), @@ -1024,6 +1031,7 @@ void LLMediaCtrl::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event) { LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_NAVIGATE_BEGIN, url is " << self->getNavigateURI() << LL_ENDL; hideNotification(); + mLoadingState = LOADING_STATE_LOADING; }; break; @@ -1034,6 +1042,7 @@ void LLMediaCtrl::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event) { mHidingInitialLoad = false; } + mLoadingState = LOADING_STATE_LOADED; }; break; @@ -1062,6 +1071,7 @@ void LLMediaCtrl::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event) { navigateTo(mErrorPageURL, HTTP_CONTENT_TEXT_HTML); }; + mLoadingState = LOADING_STATE_ERROR; }; break; @@ -1106,12 +1116,14 @@ void LLMediaCtrl::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event) case MEDIA_EVENT_PLUGIN_FAILED: { LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_PLUGIN_FAILED" << LL_ENDL; + mLoadingState = LOADING_STATE_ERROR; }; break; case MEDIA_EVENT_PLUGIN_FAILED_LAUNCH: { LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_PLUGIN_FAILED_LAUNCH" << LL_ENDL; + mLoadingState = LOADING_STATE_ERROR; }; break; @@ -1194,6 +1206,33 @@ void LLMediaCtrl::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event) case MEDIA_EVENT_DEBUG_MESSAGE: { LL_INFOS("media") << self->getDebugMessageText() << LL_ENDL; + + // Handle text extraction responses + std::string debug_text = self->getDebugMessageText(); + if (debug_text.find(PAGE_TEXT_EXTRACT_MARKER) != std::string::npos) + { + if (LLPluginClassMedia* plugin = getMediaPlugin()) + { + // Disable plugin debugging if it was used just for text extraction + static LLCachedControl<bool> media_debugging(gSavedSettings, "MediaPluginDebugging", false); + plugin->enableMediaPluginDebugging(media_debugging); + } + // Extract the pump name and page text + size_t marker_pos = debug_text.find(PAGE_TEXT_EXTRACT_MARKER); + if (marker_pos != std::string::npos) + { + std::string remaining = debug_text.substr(marker_pos + PAGE_TEXT_EXTRACT_MARKER.length()); + size_t colon_pos = remaining.find(':'); + if (colon_pos != std::string::npos) + { + std::string pump_name = remaining.substr(0, colon_pos); + std::string page_text = remaining.substr(colon_pos + 1); + + // Send the response directly to the specified pump + LLEventPumps::instance().obtain(pump_name).post(LLSD().with("text", page_text)); + } + } + } }; break; }; @@ -1274,3 +1313,148 @@ bool LLMediaCtrl::wantsReturnKey() const { return true; } + +std::string LLMediaCtrl::getMediaMimeType() +{ + return mMediaSource ? mMediaSource->getMimeType() : "unknown"; +} + +std::string LLMediaCtrl::getMediaLoadingStatus() +{ + if (!mMediaSource) + { + return "error"; + } + + switch (mLoadingState) + { + case LOADING_STATE_INITIALIZING: + return "initializing"; + case LOADING_STATE_LOADING: + return "loading"; + case LOADING_STATE_LOADED: + return "loaded"; + case LOADING_STATE_ERROR: + default: + return "error"; + } +} + +std::string LLMediaCtrl::getMediaTitle() +{ + if (mMediaSource) + { + if (LLPluginClassMedia* plugin = mMediaSource->getMediaPlugin()) + { + return plugin->getMediaName(); + } + } + return "unknown"; +} + +bool LLMediaCtrl::executeJavaScript(const std::string& script) +{ + if (mMediaSource && mMediaSource->hasMedia()) + { + mMediaSource->executeJavaScript(script); + return true; + } + return false; +} + +class LLMediaCtrlListener: public LLEventAPI +{ +public: + LLMediaCtrlListener(); + +private: + void getMediaInfo(const LLSD& request); + void getMediaText(const LLSD& request); + void replyError(const LLSD& request, const std::string& error); + LLMediaCtrl* findMediaCtrl(const std::string& path); +}; + +LLMediaCtrlListener::LLMediaCtrlListener(): + LLEventAPI("LLMediaAPI", "Acces to LLMediaCtrl(web_browse widget) info") +{ + add("getMediaInfo", + "Get information about the web_browser widget specified by [\"path\"].\n" + "Returns URL, MIME type, and loading status of the widget.", + &LLMediaCtrlListener::getMediaInfo, + llsd::map("path", LLSD(), "reply", LLSD())); + + add("getMediaText", + "Get text content from the web_browser widget specified by [\"path\"].\n" + "Returns the text content of the page or a portion of it.", + &LLMediaCtrlListener::getMediaText, + llsd::map("path", LLSD(), "reply", LLSD())); +} + +LLMediaCtrl* LLMediaCtrlListener::findMediaCtrl(const std::string& path) +{ + LLView* view = LLUI::getInstance()->resolvePath(LLUI::getInstance()->getRootView(), path); + if (!view) + { + return nullptr; + } + return dynamic_cast<LLMediaCtrl*>(view); +} + +void LLMediaCtrlListener::getMediaInfo(const LLSD& request) +{ + Response reply(LLSD(), request); + std::string path = request["path"]; + + LLMediaCtrl* media_ctrl = findMediaCtrl(path); + if (!media_ctrl) + { + reply["error"] = "Could not find web_browser widget at path: " + path; + return; + } + + reply["url"] = media_ctrl->getCurrentNavUrl(); + reply["mime_type"] = media_ctrl->getMediaMimeType(); + reply["status"] = media_ctrl->getMediaLoadingStatus(); + reply["title"] = media_ctrl->getMediaTitle(); +} + +void LLMediaCtrlListener::replyError(const LLSD& request, const std::string& error) +{ + Response reply(LLSD(), request); + reply["error"] = error; +} + +void LLMediaCtrlListener::getMediaText(const LLSD& request) +{ + std::string path = request["path"]; + + LLMediaCtrl* media_ctrl = findMediaCtrl(path); + if (!media_ctrl) + { + replyError(request, "Could not find web_browser widget at path: " + path); + return; + } + + LLPluginClassMedia* plugin = media_ctrl->getMediaPlugin(); + if (!plugin) + { + replyError(request, "Media plugin is not available for widget at path: " + path); + return; + } + + // Enable plugin debugging to capture console messages + plugin->enableMediaPluginDebugging(true); + std::string pump_name = request["reply"].asString(); + + // Execute JavaScript to extract page text, embedding pump name in the marker + const std::string text_extract_script = "console.log('" + PAGE_TEXT_EXTRACT_MARKER + pump_name + ":' + " + "(document.body ? (document.body.innerText ? document.body.innerText.substring(0, 1000).replace(/\\s+/g, ' ').trim() : " + "'No text content') : 'Document body not ready'));"; + + if (!media_ctrl->executeJavaScript(text_extract_script)) + { + replyError(request, "Failed to execute JavaScript for text extraction"); + } +} + +static LLMediaCtrlListener sMediaCtrlListener; diff --git a/indra/newview/llmediactrl.h b/indra/newview/llmediactrl.h index a644ef3071..e407bfbbcb 100644 --- a/indra/newview/llmediactrl.h +++ b/indra/newview/llmediactrl.h @@ -77,6 +77,14 @@ protected: public: virtual ~LLMediaCtrl(); + enum ELoadingState + { + LOADING_STATE_INITIALIZING = 0, + LOADING_STATE_LOADING = 1, + LOADING_STATE_LOADED = 2, + LOADING_STATE_ERROR = 3 + }; + void setBorderVisible( bool border_visible ); // For the tutorial window, we don't want to take focus on clicks, @@ -181,6 +189,11 @@ public: virtual bool acceptsTextInput() const { return true; } + std::string getMediaMimeType(); + std::string getMediaLoadingStatus(); + std::string getMediaTitle(); + bool executeJavaScript(const std::string& script); + protected: void convertInputCoords(S32& x, S32& y); @@ -217,6 +230,7 @@ public: viewer_media_t mMediaSource; S32 mTextureWidth, mTextureHeight; + ELoadingState mLoadingState; class LLWindowShade* mWindowShade; LLHandle<LLContextMenu> mContextMenuHandle; |
