From 8095d6c48c0db84f78a1f7a7ab0636d33a373e80 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Sat, 22 Dec 2012 19:07:08 +0100 Subject: [PATCH] Large snapshot update (part 3) --- indra/llmessage/aicurl.cpp | 8 +- indra/llmessage/aicurlprivate.h | 8 +- indra/llmessage/aicurlthread.cpp | 2 +- indra/llmessage/llhttpclient.cpp | 27 +- indra/llmessage/llhttpclient.h | 44 +- indra/llmessage/llurlrequest.cpp | 6 +- indra/llmessage/llurlrequest.h | 3 +- indra/newview/llfloatersnapshot.cpp | 403 +++++++++++------- indra/newview/llfloatersnapshot.h | 2 + indra/newview/llviewermedia.cpp | 27 ++ indra/newview/llviewerobjectlist.cpp | 2 +- indra/newview/llvoavatar.h | 1 + indra/newview/llwebprofile.cpp | 46 +- .../default/xui/en-us/floater_snapshot.xml | 56 +-- 14 files changed, 396 insertions(+), 239 deletions(-) diff --git a/indra/llmessage/aicurl.cpp b/indra/llmessage/aicurl.cpp index 754083286..8396b195c 100644 --- a/indra/llmessage/aicurl.cpp +++ b/indra/llmessage/aicurl.cpp @@ -760,17 +760,17 @@ void CurlEasyRequest::setoptString(CURLoption option, std::string const& value) setopt(option, value.c_str()); } -void CurlEasyRequest::setPost(AIPostFieldPtr const& postdata, U32 size) +void CurlEasyRequest::setPost(AIPostFieldPtr const& postdata, U32 size, bool keepalive) { llassert_always(postdata->data()); DoutCurl("POST size is " << size << " bytes: \"" << libcwd::buf2str(postdata->data(), size) << "\"."); setPostField(postdata); // Make sure the data stays around until we don't need it anymore. - setPost_raw(size, postdata->data()); + setPost_raw(size, postdata->data(), keepalive); } -void CurlEasyRequest::setPost_raw(U32 size, char const* data) +void CurlEasyRequest::setPost_raw(U32 size, char const* data, bool keepalive) { if (!data) { @@ -780,7 +780,7 @@ void CurlEasyRequest::setPost_raw(U32 size, char const* data) // The server never replies with 100-continue, so suppress the "Expect: 100-continue" header that libcurl adds by default. addHeader("Expect:"); - if (size > 0) + if (size > 0 && keepalive) { addHeader("Connection: keep-alive"); addHeader("Keep-alive: 300"); diff --git a/indra/llmessage/aicurlprivate.h b/indra/llmessage/aicurlprivate.h index ee28ae849..86ae1321c 100644 --- a/indra/llmessage/aicurlprivate.h +++ b/indra/llmessage/aicurlprivate.h @@ -270,11 +270,11 @@ class CurlEasyHandle : public boost::noncopyable, protected AICurlEasyHandleEven // and the CurlEasyRequest destructed. class CurlEasyRequest : public CurlEasyHandle { private: - void setPost_raw(U32 size, char const* data); + void setPost_raw(U32 size, char const* data, bool keepalive); public: - void setPost(U32 size) { setPost_raw(size, NULL); } - void setPost(AIPostFieldPtr const& postdata, U32 size); - void setPost(char const* data, U32 size) { setPost(new AIPostField(data), size); } + void setPost(U32 size, bool keepalive = true) { setPost_raw(size, NULL, keepalive); } + void setPost(AIPostFieldPtr const& postdata, U32 size, bool keepalive = true); + void setPost(char const* data, U32 size, bool keepalive = true) { setPost(new AIPostField(data), size, keepalive); } void setoptString(CURLoption option, std::string const& value); void addHeader(char const* str); void addHeaders(AIHTTPHeaders const& headers); diff --git a/indra/llmessage/aicurlthread.cpp b/indra/llmessage/aicurlthread.cpp index b8c700997..7553dd574 100644 --- a/indra/llmessage/aicurlthread.cpp +++ b/indra/llmessage/aicurlthread.cpp @@ -2174,7 +2174,7 @@ void BufferedCurlEasyRequest::setStatusAndReason(U32 status, std::string const& AICurlInterface::Stats::status_count[AICurlInterface::Stats::status2index(mStatus)]++; // Sanity check. If the server replies with a redirect status then we better have that option turned on! - if ((status >= 300 && status < 400) && mResponder && !mResponder->followRedir()) + if ((status >= 300 && status < 400) && mResponder && !mResponder->redirect_status_ok()) { llerrs << "Received " << status << " (" << reason << ") for responder \"" << mTimeoutPolicy->name() << "\" which has no followRedir()!" << llendl; } diff --git a/indra/llmessage/llhttpclient.cpp b/indra/llmessage/llhttpclient.cpp index b7871556e..d72a6e646 100644 --- a/indra/llmessage/llhttpclient.cpp +++ b/indra/llmessage/llhttpclient.cpp @@ -201,6 +201,7 @@ static void request( Injector* body_injector, LLHTTPClient::ResponderPtr responder, AIHTTPHeaders& headers, + EKeepAlive keepalive = keep_alive, bool is_auth = false, bool no_compression = false) { @@ -213,7 +214,7 @@ static void request( LLURLRequest* req; try { - req = new LLURLRequest(method, url, body_injector, responder, headers, is_auth, no_compression); + req = new LLURLRequest(method, url, body_injector, responder, headers, keepalive, is_auth, no_compression); } catch(AICurlNoEasyHandle& error) { @@ -657,17 +658,17 @@ void LLHTTPClient::put(std::string const& url, LLSD const& body, ResponderPtr re request(url, LLURLRequest::HTTP_PUT, new LLSDInjector(body), responder, headers); } -void LLHTTPClient::post(std::string const& url, LLSD const& body, ResponderPtr responder, AIHTTPHeaders& headers) +void LLHTTPClient::post(std::string const& url, LLSD const& body, ResponderPtr responder, AIHTTPHeaders& headers, EKeepAlive keepalive) { - request(url, LLURLRequest::HTTP_POST, new LLSDInjector(body), responder, headers); + request(url, LLURLRequest::HTTP_POST, new LLSDInjector(body), responder, headers, keepalive); } -void LLHTTPClient::postXMLRPC(std::string const& url, XMLRPC_REQUEST xmlrpc_request, ResponderPtr responder, AIHTTPHeaders& headers) +void LLHTTPClient::postXMLRPC(std::string const& url, XMLRPC_REQUEST xmlrpc_request, ResponderPtr responder, AIHTTPHeaders& headers, EKeepAlive keepalive) { - request(url, LLURLRequest::HTTP_POST, new XMLRPCInjector(xmlrpc_request), responder, headers, true, false); // Does use compression. + request(url, LLURLRequest::HTTP_POST, new XMLRPCInjector(xmlrpc_request), responder, headers, keepalive, true, false); // Does use compression. } -void LLHTTPClient::postXMLRPC(std::string const& url, char const* method, XMLRPC_VALUE value, ResponderPtr responder, AIHTTPHeaders& headers) +void LLHTTPClient::postXMLRPC(std::string const& url, char const* method, XMLRPC_VALUE value, ResponderPtr responder, AIHTTPHeaders& headers, EKeepAlive keepalive) { XMLRPC_REQUEST xmlrpc_request = XMLRPC_RequestNew(); XMLRPC_RequestSetMethodName(xmlrpc_request, method); @@ -675,22 +676,22 @@ void LLHTTPClient::postXMLRPC(std::string const& url, char const* method, XMLRPC XMLRPC_RequestSetData(xmlrpc_request, value); // XMLRPCInjector takes ownership of xmlrpc_request and will free it when done. // LLURLRequest takes ownership of the XMLRPCInjector object and will free it when done. - request(url, LLURLRequest::HTTP_POST, new XMLRPCInjector(xmlrpc_request), responder, headers, true, true); // Does not use compression. + request(url, LLURLRequest::HTTP_POST, new XMLRPCInjector(xmlrpc_request), responder, headers, keepalive, true, true); // Does not use compression. } -void LLHTTPClient::postRaw(std::string const& url, char const* data, S32 size, ResponderPtr responder, AIHTTPHeaders& headers) +void LLHTTPClient::postRaw(std::string const& url, char const* data, S32 size, ResponderPtr responder, AIHTTPHeaders& headers, EKeepAlive keepalive) { - request(url, LLURLRequest::HTTP_POST, new RawInjector(data, size), responder, headers); + request(url, LLURLRequest::HTTP_POST, new RawInjector(data, size), responder, headers, keepalive); } -void LLHTTPClient::postFile(std::string const& url, std::string const& filename, ResponderPtr responder, AIHTTPHeaders& headers) +void LLHTTPClient::postFile(std::string const& url, std::string const& filename, ResponderPtr responder, AIHTTPHeaders& headers, EKeepAlive keepalive) { - request(url, LLURLRequest::HTTP_POST, new FileInjector(filename), responder, headers); + request(url, LLURLRequest::HTTP_POST, new FileInjector(filename), responder, headers, keepalive); } -void LLHTTPClient::postFile(std::string const& url, LLUUID const& uuid, LLAssetType::EType asset_type, ResponderPtr responder, AIHTTPHeaders& headers) +void LLHTTPClient::postFile(std::string const& url, LLUUID const& uuid, LLAssetType::EType asset_type, ResponderPtr responder, AIHTTPHeaders& headers, EKeepAlive keepalive) { - request(url, LLURLRequest::HTTP_POST, new VFileInjector(uuid, asset_type), responder, headers); + request(url, LLURLRequest::HTTP_POST, new VFileInjector(uuid, asset_type), responder, headers, keepalive); } // static diff --git a/indra/llmessage/llhttpclient.h b/indra/llmessage/llhttpclient.h index ec4e88955..8a3eba2b5 100644 --- a/indra/llmessage/llhttpclient.h +++ b/indra/llmessage/llhttpclient.h @@ -66,6 +66,11 @@ struct AIBufferedCurlEasyRequestEvents { virtual void completed_headers(U32 status, std::string const& reason, AITransferInfo* info) = 0; // Transaction completed. }; +enum EKeepAlive { + no_keep_alive = 0, + keep_alive +}; + class LLHTTPClient { public: @@ -163,6 +168,9 @@ public: // The default is not to follow redirections. virtual bool followRedir(void) const { return false; } + // If this function returns false then we generate an error when a redirect status (300..399) is received. + virtual bool redirect_status_ok(void) const { return followRedir(); } + // Timeout policy to use. virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const = 0; @@ -382,31 +390,31 @@ public: static void getHeaderOnly(std::string const& url, ResponderHeadersOnly* responder) { AIHTTPHeaders headers; getHeaderOnly(url, responder, headers); } - static void post(std::string const& url, LLSD const& body, ResponderPtr responder, AIHTTPHeaders& headers); - static void post(std::string const& url, LLSD const& body, ResponderPtr responder) - { AIHTTPHeaders headers; post(url, body, responder, headers); } + static void post(std::string const& url, LLSD const& body, ResponderPtr responder, AIHTTPHeaders& headers, EKeepAlive keepalive = keep_alive); + static void post(std::string const& url, LLSD const& body, ResponderPtr responder, EKeepAlive keepalive = keep_alive) + { AIHTTPHeaders headers; post(url, body, responder, headers, keepalive); } /** Takes ownership of request and deletes it when sent */ - static void postXMLRPC(std::string const& url, XMLRPC_REQUEST request, ResponderPtr responder, AIHTTPHeaders& headers); - static void postXMLRPC(std::string const& url, XMLRPC_REQUEST request, ResponderPtr responder) - { AIHTTPHeaders headers; postXMLRPC(url, request, responder, headers); } + static void postXMLRPC(std::string const& url, XMLRPC_REQUEST request, ResponderPtr responder, AIHTTPHeaders& headers, EKeepAlive keepalive = keep_alive); + static void postXMLRPC(std::string const& url, XMLRPC_REQUEST request, ResponderPtr responder, EKeepAlive keepalive = keep_alive) + { AIHTTPHeaders headers; postXMLRPC(url, request, responder, headers, keepalive); } - static void postXMLRPC(std::string const& url, char const* method, XMLRPC_VALUE value, ResponderPtr responder, AIHTTPHeaders& headers); - static void postXMLRPC(std::string const& url, char const* method, XMLRPC_VALUE value, ResponderPtr responder) - { AIHTTPHeaders headers; postXMLRPC(url, method, value, responder, headers); } + static void postXMLRPC(std::string const& url, char const* method, XMLRPC_VALUE value, ResponderPtr responder, AIHTTPHeaders& headers, EKeepAlive keepalive = keep_alive); + static void postXMLRPC(std::string const& url, char const* method, XMLRPC_VALUE value, ResponderPtr responder, EKeepAlive keepalive = keep_alive) + { AIHTTPHeaders headers; postXMLRPC(url, method, value, responder, headers, keepalive); } /** Takes ownership of data and deletes it when sent */ - static void postRaw(std::string const& url, const char* data, S32 size, ResponderPtr responder, AIHTTPHeaders& headers); - static void postRaw(std::string const& url, const char* data, S32 size, ResponderPtr responder) - { AIHTTPHeaders headers; postRaw(url, data, size, responder, headers); } + static void postRaw(std::string const& url, const char* data, S32 size, ResponderPtr responder, AIHTTPHeaders& headers, EKeepAlive keepalive = keep_alive); + static void postRaw(std::string const& url, const char* data, S32 size, ResponderPtr responder, EKeepAlive keepalive = keep_alive) + { AIHTTPHeaders headers; postRaw(url, data, size, responder, headers, keepalive); } - static void postFile(std::string const& url, std::string const& filename, ResponderPtr responder, AIHTTPHeaders& headers); - static void postFile(std::string const& url, std::string const& filename, ResponderPtr responder) - { AIHTTPHeaders headers; postFile(url, filename, responder, headers); } + static void postFile(std::string const& url, std::string const& filename, ResponderPtr responder, AIHTTPHeaders& headers, EKeepAlive keepalive = keep_alive); + static void postFile(std::string const& url, std::string const& filename, ResponderPtr responder, EKeepAlive keepalive = keep_alive) + { AIHTTPHeaders headers; postFile(url, filename, responder, headers, keepalive); } - static void postFile(std::string const& url, const LLUUID& uuid, LLAssetType::EType asset_type, ResponderPtr responder, AIHTTPHeaders& headers); - static void postFile(std::string const& url, const LLUUID& uuid, LLAssetType::EType asset_type, ResponderPtr responder) - { AIHTTPHeaders headers; postFile(url, uuid, asset_type, responder, headers); } + static void postFile(std::string const& url, const LLUUID& uuid, LLAssetType::EType asset_type, ResponderPtr responder, AIHTTPHeaders& headers, EKeepAlive keepalive = keep_alive); + static void postFile(std::string const& url, const LLUUID& uuid, LLAssetType::EType asset_type, ResponderPtr responder, EKeepAlive keepalive = keep_alive) + { AIHTTPHeaders headers; postFile(url, uuid, asset_type, responder, headers, keepalive); } static void del(std::string const& url, ResponderPtr responder, AIHTTPHeaders& headers); static void del(std::string const& url, ResponderPtr responder) diff --git a/indra/llmessage/llurlrequest.cpp b/indra/llmessage/llurlrequest.cpp index 3ffb9e5cc..429a93627 100644 --- a/indra/llmessage/llurlrequest.cpp +++ b/indra/llmessage/llurlrequest.cpp @@ -77,8 +77,8 @@ std::string LLURLRequest::actionAsVerb(LLURLRequest::ERequestAction action) // This might throw AICurlNoEasyHandle. LLURLRequest::LLURLRequest(LLURLRequest::ERequestAction action, std::string const& url, Injector* body, - LLHTTPClient::ResponderPtr responder, AIHTTPHeaders& headers, bool is_auth, bool no_compression) : - mAction(action), mURL(url), mIsAuth(is_auth), mNoCompression(no_compression), + LLHTTPClient::ResponderPtr responder, AIHTTPHeaders& headers, bool keepalive, bool is_auth, bool no_compression) : + mAction(action), mURL(url), mKeepAlive(keepalive), mIsAuth(is_auth), mNoCompression(no_compression), mBody(body), mResponder(responder), mHeaders(headers) { } @@ -226,7 +226,7 @@ bool LLURLRequest::configure(AICurlEasyRequest_wat const& curlEasyRequest_w) case HTTP_POST: { // Set the handle for an http post - curlEasyRequest_w->setPost(mBodySize); + curlEasyRequest_w->setPost(mBodySize, mKeepAlive); // Set Accept-Encoding to allow response compression curlEasyRequest_w->setoptString(CURLOPT_ENCODING, mNoCompression ? "identity" : ""); diff --git a/indra/llmessage/llurlrequest.h b/indra/llmessage/llurlrequest.h index fbe97c22f..9cdb132bb 100644 --- a/indra/llmessage/llurlrequest.h +++ b/indra/llmessage/llurlrequest.h @@ -77,7 +77,7 @@ class LLURLRequest : public AICurlEasyRequestStateMachine { * @param action One of the ERequestAction enumerations. * @param url The url of the request. It should already be encoded. */ - LLURLRequest(ERequestAction action, std::string const& url, Injector* body, LLHTTPClient::ResponderPtr responder, AIHTTPHeaders& headers, bool is_auth, bool no_compression); + LLURLRequest(ERequestAction action, std::string const& url, Injector* body, LLHTTPClient::ResponderPtr responder, AIHTTPHeaders& headers, bool keepalive, bool is_auth, bool no_compression); protected: // Call abort(), not delete. @@ -111,6 +111,7 @@ class LLURLRequest : public AICurlEasyRequestStateMachine { private: ERequestAction mAction; std::string mURL; + bool mKeepAlive; // Set to false only when explicitely requested. bool mIsAuth; // Set for authentication messages (login, buy land, buy currency). bool mNoCompression; // Set to disable using gzip. Injector* mBody; // Non-zero iff the action is HTTP_POST and HTTP_PUT. diff --git a/indra/newview/llfloatersnapshot.cpp b/indra/newview/llfloatersnapshot.cpp index db2e90ab9..e9b325967 100644 --- a/indra/newview/llfloatersnapshot.cpp +++ b/indra/newview/llfloatersnapshot.cpp @@ -89,8 +89,8 @@ ///---------------------------------------------------------------------------- /// Local function declarations, constants, enums, and typedefs ///---------------------------------------------------------------------------- -S32 LLFloaterSnapshot::sUIWinHeightLong = 609 ; -S32 LLFloaterSnapshot::sUIWinHeightShort = LLFloaterSnapshot::sUIWinHeightLong - 250 ; +S32 LLFloaterSnapshot::sUIWinHeightLong = 619 ; +S32 LLFloaterSnapshot::sUIWinHeightShort = LLFloaterSnapshot::sUIWinHeightLong - 260 ; S32 LLFloaterSnapshot::sUIWinWidth = 219 ; S32 const THUMBHEIGHT = 159; @@ -123,6 +123,15 @@ public: SNAPSHOT_LOCAL }; + enum EAspectSizeProblem + { + ASPECTSIZE_OK, + CANNOT_CROP_HORIZONTALLY, + CANNOT_CROP_VERTICALLY, + SIZE_TOO_LARGE, + CANNOT_RESIZE + }; + U32 typeToMask(ESnapshotType type) const { return 1 << type; } void addUsedBy(ESnapshotType type) { mUsedBy |= typeToMask(type); } bool isUsedBy(ESnapshotType type) const { return (mUsedBy & typeToMask(type)) != 0; } @@ -140,7 +149,7 @@ public: void getSize(S32& w, S32& h) const; void setAspect(F32 a); F32 getAspect() const; - void getUsedSize(S32& w, S32& h) const; + void getRawSize(S32& w, S32& h) const; S32 getDataSize() const { return mFormattedDataSize; } void setMaxImageSize(S32 size) ; S32 getMaxImageSize() {return mMaxImageSize ;} @@ -178,11 +187,12 @@ public: BOOL setThumbnailImageSize(); void generateThumbnailImage(); + EAspectSizeProblem getAspectSizeProblem(S32& width_out, S32& height_out, bool& crop_vertically_out, S32& crop_offset_out); void generateFormattedAndFullscreenPreview(bool delayed_formatted = false); void drawPreviewRect(S32 offset_x, S32 offset_y) ; // Returns TRUE when snapshot generated, FALSE otherwise. - static BOOL onIdle( void* snapshot_preview ); + static BOOL onIdle(LLSnapshotLivePreview* previewp); private: LLColor4 mColor; @@ -320,7 +330,6 @@ LLSnapshotLivePreview::LLSnapshotLivePreview (const LLRect& rect) : DoutEntering(dc::notice, "LLSnapshotLivePreview() [" << (void*)this << "]"); setSnapshotQuality(gSavedSettings.getS32("SnapshotQuality")); mSnapshotDelayTimer.start(); -// gIdleCallbacks.addFunction( &LLSnapshotLivePreview::onIdle, (void*)this ); sList.insert(this); setFollowsAll(); mWidth = gViewerWindow->getWindowDisplayWidth(); @@ -343,8 +352,6 @@ LLSnapshotLivePreview::~LLSnapshotLivePreview() // delete images mRawSnapshot = NULL; mFormattedImage = NULL; - -// gIdleCallbacks.deleteFunction( &LLSnapshotLivePreview::onIdle, (void*)this ); sList.erase(this); } @@ -766,10 +773,8 @@ void LLSnapshotLivePreview::generateThumbnailImage(void) // Called often. Checks whether it's time to grab a new snapshot and if so, does it. // Returns TRUE if new snapshot generated, FALSE otherwise. //static -BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview ) +BOOL LLSnapshotLivePreview::onIdle(LLSnapshotLivePreview* previewp) { - LLSnapshotLivePreview* previewp = (LLSnapshotLivePreview*)snapshot_preview; - LLVector3 new_camera_pos = LLViewerCamera::getInstance()->getOrigin(); LLQuaternion new_camera_rot = LLViewerCamera::getInstance()->getQuaternion(); static const LLCachedControl freeze_time("FreezeTime",false); @@ -796,7 +801,7 @@ BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview ) if (previewp->mFormattedDelayTimer.getStarted() && previewp->mFormattedDelayTimer.hasExpired()) { previewp->mFormattedDelayTimer.stop(); - previewp->generateFormattedAndFullscreenPreview(); + LLFloaterSnapshot::updateControls(); } return FALSE; } @@ -861,71 +866,85 @@ BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview ) return TRUE; } -void LLSnapshotLivePreview::generateFormattedAndFullscreenPreview(bool delayed) +LLSnapshotLivePreview::EAspectSizeProblem LLSnapshotLivePreview::getAspectSizeProblem(S32& width_out, S32& height_out, bool& crop_vertically_out, S32& crop_offset_out) { - DoutEntering(dc::notice, "LLSnapshotLivePreview::generateFormattedAndFullscreenPreview(" << delayed << ")"); - - mFormattedUpToDate = false; S32 const window_width = gViewerWindow->getWindowWidthRaw(); S32 const window_height = gViewerWindow->getWindowHeightRaw(); // We need an image with the aspect mAspectRatio (from which mWidth and mHeight were derived). // The current aspect ratio of mRawSnapshot is: - F32 raw_aspect = (F32)mRawSnapshotWidth / mRawSnapshotHeight; + F32 const raw_aspect = (F32)mRawSnapshotWidth / mRawSnapshotHeight; // Find out if mRawSnapshot was cropped already. - bool allow_vertical_crop = window_height * raw_aspect >= window_width; // mRawSnapshot was cropped horizontally. - bool allow_horizontal_crop = window_width / raw_aspect >= window_height; // mRawSnapshot was cropped vertically. - bool crop_vertically = true; // Prefer this, as it is faster. - S32 crop_offset = 0; // The number of columns or rows to cut off on the left or bottom. + bool const allow_vertical_crop = window_height * raw_aspect >= window_width; // mRawSnapshot was cropped horizontally. + bool const allow_horizontal_crop = window_width / raw_aspect >= window_height; // mRawSnapshot was cropped vertically. + crop_vertically_out = true; // Prefer this, as it is faster. + crop_offset_out = 0; // The number of columns or rows to cut off on the left or bottom. // Construct a rectangle size w,h that fits inside mRawSnapshot but has the correct aspect. - S32 w = mRawSnapshotWidth; - S32 h = mRawSnapshotHeight; + width_out = mRawSnapshotWidth; + height_out = mRawSnapshotHeight; if (mAspectRatio < raw_aspect) { - w = llround(w * mAspectRatio / raw_aspect); - if (w < mRawSnapshotWidth) + width_out = llround(width_out * mAspectRatio / raw_aspect); + if (width_out < mRawSnapshotWidth) { // Only set this to false when there is actually something to crop. - crop_vertically = false; + crop_vertically_out = false; if (!allow_horizontal_crop) { Dout(dc::notice, "NOT up to date: required aspect " << mAspectRatio << " is less than raw aspect " << raw_aspect << " which is already vertically cropped."); - return; + return CANNOT_CROP_HORIZONTALLY; } - crop_offset = (mRawSnapshotWidth - w) / 2; + crop_offset_out = (mRawSnapshotWidth - width_out) / 2; } } else if (mAspectRatio > raw_aspect) { - h = llround(h * raw_aspect / mAspectRatio); - if (h < mRawSnapshotHeight) + height_out = llround(height_out * raw_aspect / mAspectRatio); + if (height_out < mRawSnapshotHeight) { if (!allow_vertical_crop) { Dout(dc::notice, "NOT up to date: required aspect " << mAspectRatio << " is larger than raw aspect " << raw_aspect << " which is already horizontally cropped."); - return; + return CANNOT_CROP_VERTICALLY; } - crop_offset = (mRawSnapshotHeight - h) / 2; + crop_offset_out = (mRawSnapshotHeight - height_out) / 2; } } // Never allow upscaling of the existing snapshot, of course. - if (mWidth > w || mHeight > h) + if (mWidth > width_out || mHeight > height_out) { Dout(dc::notice, "NOT up to date: required target size " << mWidth << "x" << mHeight << - " is larger than (cropped) raw snapshot with size " << w << "x" << h << "!"); - return; + " is larger than (cropped) raw snapshot with size " << width_out << "x" << height_out << "!"); + return SIZE_TOO_LARGE; } // Do not allow any resizing for target images that are equal or larger than the current window, when the target is the harddisk. - // If the target size is smaller, than a resize would occur anyway, so in that case we allow resizing whatever we have. - if (mSnapshotType == SNAPSHOT_LOCAL && (mWidth >= window_width || mHeight >= window_height) && (mWidth != w || mHeight != h)) + // If the target size is smaller, than a resize would occur anyway, so in that case we allow resizing whatever we have, + // unless the aspect is different in which case we have to allow resizing in one direction. + if (mSnapshotType == SNAPSHOT_LOCAL && (mWidth >= window_width || mHeight >= window_height) && mWidth != width_out && mHeight != height_out) { Dout(dc::notice, "NOT up to date: required target size " << mWidth << "x" << mHeight << " is larger or equal the window size (" << window_width << "x" << window_height << ")" - " but unequal the (cropped) raw snapshot size (" << w << "x" << h << ")" + " but unequal the (cropped) raw snapshot size (" << width_out << "x" << height_out << ")" " and target is disk!"); + return CANNOT_RESIZE; + } + return ASPECTSIZE_OK; +} + +void LLSnapshotLivePreview::generateFormattedAndFullscreenPreview(bool delayed) +{ + DoutEntering(dc::notice, "LLSnapshotLivePreview::generateFormattedAndFullscreenPreview(" << delayed << ")"); + mFormattedUpToDate = false; + + S32 w, h, crop_offset; + bool crop_vertically; + EAspectSizeProblem ret = getAspectSizeProblem(w, h, crop_vertically, crop_offset); + if (ret != ASPECTSIZE_OK) + { + // Current raw snapshot cannot be used. return; } @@ -933,16 +952,20 @@ void LLSnapshotLivePreview::generateFormattedAndFullscreenPreview(bool delayed) LLFloaterSnapshot::ESnapshotFormat format; switch (mSnapshotType) { + case SNAPSHOT_FEED: + // Feeds hardcoded to always use png. + format = LLFloaterSnapshot::SNAPSHOT_FORMAT_PNG; + break; + case SNAPSHOT_POSTCARD: + // Postcards hardcoded to always use jpeg. + format = LLFloaterSnapshot::SNAPSHOT_FORMAT_JPEG; + break; case SNAPSHOT_TEXTURE: format = LLFloaterSnapshot::SNAPSHOT_FORMAT_J2C; break; case SNAPSHOT_LOCAL: format = mSnapshotFormat; break; - default: - // Feeds and postcards hardcoded to always use jpeg. - format = LLFloaterSnapshot::SNAPSHOT_FORMAT_JPEG; - break; } if (mFormattedImage && @@ -1151,7 +1174,7 @@ F32 LLSnapshotLivePreview::getAspect() const return mAspectRatio; } -void LLSnapshotLivePreview::getUsedSize(S32& w, S32& h) const +void LLSnapshotLivePreview::getRawSize(S32& w, S32& h) const { w = mRawSnapshotWidth; h = mRawSnapshotHeight; @@ -1391,7 +1414,7 @@ public: static void onQualityMouseUp(void* data); static LLSnapshotLivePreview* getPreviewView(LLFloaterSnapshot *floater); - static void setResolution(LLFloaterSnapshot* floater, const std::string& comboname, bool update_controls = true); + static void setResolution(LLFloaterSnapshot* floater, const std::string& comboname, bool visible, bool update_controls = true); static void setAspect(LLFloaterSnapshot* floater, const std::string& comboname, bool update_controls = true); static void updateControls(LLFloaterSnapshot* floater, bool delayed_formatted = false); static void updateLayout(LLFloaterSnapshot* floater); @@ -1455,10 +1478,10 @@ LLFloaterSnapshot::ESnapshotFormat LLFloaterSnapshot::Impl::getFormatIndex(LLFlo } // static -void LLFloaterSnapshot::Impl::setResolution(LLFloaterSnapshot* floater, const std::string& comboname, bool update_controls) +void LLFloaterSnapshot::Impl::setResolution(LLFloaterSnapshot* floater, const std::string& comboname, bool visible, bool update_controls) { LLComboBox* combo = floater->getChild(comboname); - combo->setVisible(TRUE); + combo->setVisible(visible); updateResolution(combo, floater, update_controls); // to sync spinners with combo } @@ -1479,34 +1502,27 @@ void LLFloaterSnapshot::Impl::updateLayout(LLFloaterSnapshot* floaterp) if(!gSavedSettings.getBOOL("AdvanceSnapshot")) //set to original window resolution { - floaterp->getChild("feed_size_combo")->setCurrentByIndex(0); - gSavedSettings.setS32("SnapshotFeedLastResolution", 0); - floaterp->getChild("feed_aspect_combo")->setCurrentByIndex(0); // 4:3 + floaterp->getChild("feed_size_combo")->setCurrentByIndex(2); // 500x375 + gSavedSettings.setS32("SnapshotFeedLastResolution", 2); + floaterp->getChild("feed_aspect_combo")->setCurrentByIndex(0); // Default (500x375) gSavedSettings.setS32("SnapshotFeedLastAspect", 0); - floaterp->getChild("postcard_size_combo")->setCurrentByIndex(0); + floaterp->getChild("postcard_size_combo")->setCurrentByIndex(0); // Current window gSavedSettings.setS32("SnapshotPostcardLastResolution", 0); floaterp->getChild("postcard_aspect_combo")->setCurrentByIndex(0); // Default (current window) gSavedSettings.setS32("SnapshotPostcardLastAspect", 0); - floaterp->getChild("texture_size_combo")->setCurrentByIndex(0); + floaterp->getChild("texture_size_combo")->setCurrentByIndex(0); // 512x512 (most likely result for current window). gSavedSettings.setS32("SnapshotTextureLastResolution", 0); floaterp->getChild("texture_aspect_combo")->setCurrentByIndex(0); // Current window gSavedSettings.setS32("SnapshotTextureLastAspect", 0); - floaterp->getChild("local_size_combo")->setCurrentByIndex(0); + floaterp->getChild("local_size_combo")->setCurrentByIndex(0); // Current window gSavedSettings.setS32("SnapshotLocalLastResolution", 0); floaterp->getChild("local_aspect_combo")->setCurrentByIndex(0); // Current window gSavedSettings.setS32("SnapshotLocalLastAspect", 0); - LLSnapshotLivePreview* previewp = getPreviewView(floaterp); - S32 w, h; - previewp->getSize(w, h); - if (gViewerWindow->getWindowDisplayWidth() != w || gViewerWindow->getWindowDisplayHeight() != h) - { - previewp->setSize(gViewerWindow->getWindowDisplayWidth(), gViewerWindow->getWindowDisplayHeight()); - updateControls(floaterp); - } + updateControls(floaterp); } if (gSavedSettings.getBOOL("UseFreezeTime")) @@ -1629,26 +1645,21 @@ void LLFloaterSnapshot::Impl::updateControls(LLFloaterSnapshot* floater, bool de previewp->setSnapshotBufferType(floater, layer_type); } BOOL is_advance = gSavedSettings.getBOOL("AdvanceSnapshot"); - if (is_advance) + switch(shot_type) { - switch(shot_type) - { - case LLSnapshotLivePreview::SNAPSHOT_FEED: - setResolution(floater, "feed_size_combo", false); - break; - case LLSnapshotLivePreview::SNAPSHOT_POSTCARD: - setResolution(floater, "postcard_size_combo", false); - break; - case LLSnapshotLivePreview::SNAPSHOT_TEXTURE: - setResolution(floater, "texture_size_combo", false); - break; - case LLSnapshotLivePreview::SNAPSHOT_LOCAL: - setResolution(floater, "local_size_combo", false); - break; - } - floater->getChild(previewp->aspectComboName())->setVisible(TRUE); + case LLSnapshotLivePreview::SNAPSHOT_FEED: + setResolution(floater, "feed_size_combo", is_advance, false); + break; + case LLSnapshotLivePreview::SNAPSHOT_POSTCARD: + setResolution(floater, "postcard_size_combo", is_advance, false); + break; + case LLSnapshotLivePreview::SNAPSHOT_TEXTURE: + setResolution(floater, "texture_size_combo", is_advance, false); + break; + case LLSnapshotLivePreview::SNAPSHOT_LOCAL: + setResolution(floater, "local_size_combo", is_advance, false); + break; } - floater->getChild("local_format_combo")->selectNthItem(shot_format); floater->childSetVisible("upload_btn", shot_type == LLSnapshotLivePreview::SNAPSHOT_TEXTURE); @@ -1658,11 +1669,11 @@ void LLFloaterSnapshot::Impl::updateControls(LLFloaterSnapshot* floater, bool de floater->childSetEnabled("layer_types", shot_type == LLSnapshotLivePreview::SNAPSHOT_LOCAL); BOOL is_local = shot_type == LLSnapshotLivePreview::SNAPSHOT_LOCAL; - BOOL show_slider = - shot_type == LLSnapshotLivePreview::SNAPSHOT_FEED || + BOOL show_slider = shot_type == LLSnapshotLivePreview::SNAPSHOT_POSTCARD || (is_local && shot_format == LLFloaterSnapshot::SNAPSHOT_FORMAT_JPEG); + floater->getChild(previewp->aspectComboName())->setVisible(is_advance); floater->childSetVisible("more_btn", !is_advance); // the only item hidden in advanced mode floater->childSetVisible("less_btn", is_advance); floater->childSetVisible("type_label2", is_advance); @@ -1671,6 +1682,7 @@ void LLFloaterSnapshot::Impl::updateControls(LLFloaterSnapshot* floater, bool de floater->childSetVisible("local_format_combo", is_local); floater->childSetVisible("layer_types", is_advance); floater->childSetVisible("layer_type_label", is_advance); + floater->childSetVisible("aspect_one_label", is_advance); floater->childSetVisible("snapshot_width", is_advance); floater->childSetVisible("snapshot_height", is_advance); floater->childSetVisible("aspect_ratio", is_advance); @@ -2136,59 +2148,128 @@ void LLFloaterSnapshot::Impl::updateResolution(LLUICtrl* ctrl, void* data, bool return; } - S32 used_w = 0; - S32 used_h = 0; + S32 new_width = 0; + S32 new_height = 0; + F32 new_aspect = 0; LLSnapshotLivePreview* previewp = getPreviewView(view); LLSnapshotLivePreview::ESnapshotType shot_type = (LLSnapshotLivePreview::ESnapshotType)gSavedSettings.getS32("LastSnapshotType"); -#if 0 // AIFIXME - bool up_to_date_now = false; - bool up_to_date_after_toggling = false; - if (previewp && previewp->isUsed() && !previewp->isOverriddenBy(shot_type)) + // Is the snapshot was already used (saved or uploaded) and no manual changes + // have been made since to the current destination type, and the raw snapshot + // is still up to date with regard to visibility of UI, HUD and BufferType etc? + if (previewp && previewp->isUsed() && !previewp->isOverriddenBy(shot_type) && previewp->getRawSnapshotUpToDate()) { - up_to_date_now = previewp->getSnapshotUpToDateExceptForSize(); - previewp->mScaleInsteadOfCrop = !previewp->mScaleInsteadOfCrop; - up_to_date_after_toggling = previewp->getSnapshotUpToDateExceptForSize(); - previewp->mScaleInsteadOfCrop = !previewp->mScaleInsteadOfCrop; - } - if (up_to_date_now || up_to_date_after_toggling) - { - // need_keep_aspect is set when mScaleInsteadOfCrop makes a difference. - bool need_keep_aspect = up_to_date_now != up_to_date_after_toggling; - - // Force the size, and possibly mScaleInsteadOfCrop, to be the one of the existing snapshot. - previewp->getUsedSize(used_w, used_h); - LLComboBox* size_combo_box = NULL; - LLComboBox* aspect_combo_box = NULL; - switch(shot_type) + previewp->getSize(new_width, new_height); + new_aspect = previewp->getAspect(); + S32 const old_width = new_width; + S32 const old_height = new_height; + F32 const old_aspect = new_aspect; + S32 raw_width; + S32 raw_height; + previewp->getRawSize(raw_width, raw_height); + F32 const raw_aspect = (F32)raw_width / raw_height; + bool fixed_crop = false; + bool fixed_size = false; + bool fixed_scale = false; + bool done = false; + bool fail = false; + while (!done) { - case LLSnapshotLivePreview::SNAPSHOT_FEED: - size_combo_box = view->getChild("feed_size_combo"); - aspect_combo_box = view->getChild("feed_aspect_combo"); + // Attempt to change the size and aspect so the raw snapshot can also be used for this new destination. + S32 w, h, crop_offset; + bool crop_vertically; + previewp->setSize(new_width, new_height); + previewp->setAspect(new_aspect); + LLSnapshotLivePreview::EAspectSizeProblem ret = previewp->getAspectSizeProblem(w, h, crop_vertically, crop_offset); + switch(ret) + { + case LLSnapshotLivePreview::ASPECTSIZE_OK: + done = true; // Don't change anything (else) if the current settings are usable. break; - case LLSnapshotLivePreview::SNAPSHOT_POSTCARD: - size_combo_box = view->getChild("postcard_size_combo"); - aspect_combo_box = view->getChild("postcard_aspect_combo"); + case LLSnapshotLivePreview::CANNOT_CROP_HORIZONTALLY: + case LLSnapshotLivePreview::CANNOT_CROP_VERTICALLY: + if (fixed_crop) + { + done = fail = true; + } + else + { + // Set target aspect to aspect of the raw snapshot we have (no reason to crop anything). + new_aspect = raw_aspect; + fixed_crop = true; + } break; - case LLSnapshotLivePreview::SNAPSHOT_TEXTURE: - size_combo_box = view->getChild("texture_size_combo"); - aspect_combo_box = view->getChild("texture_aspect_combo"); + case LLSnapshotLivePreview::SIZE_TOO_LARGE: + if (fixed_size) + { + done = fail = true; + } + else + { + if (new_width > w) + { + new_width = w; + new_height = llround(new_width / new_aspect); + } + if (new_height > h) + { + new_width = llmin(w, llround(h * new_aspect)); + new_height = llmin(h, llround(new_width / new_aspect)); + } + fixed_size = true; + } break; - case LLSnapshotLivePreview::SNAPSHOT_LOCAL: - size_combo_box = view->getChild("local_size_combo"); - aspect_combo_box = view->getChild("local_aspect_combo"); + case LLSnapshotLivePreview::CANNOT_RESIZE: + if (fixed_scale) + { + done = fail = true; + } + else + { + F32 ratio = llmin((F32)w / new_width, (F32)h / new_height); + new_width = llround(new_width * ratio); + new_height = llround(new_height * ratio); + fixed_scale = true; + } break; + } } - S32 index = 0; - bool keep_aspect = true; - bool needed_keep_aspect = up_to_date_now ? previewp->mScaleInsteadOfCrop : !previewp->mScaleInsteadOfCrop; // Only valid if need_keep_aspect is true. - S32 const custom = size_combo_box->getItemCount() - (shot_type == LLSnapshotLivePreview::SNAPSHOT_TEXTURE ? 0 : 1); // Texture does not end on 'Custom'. - while (index < custom) + previewp->setAspect(old_aspect); + previewp->setSize(old_width, old_height); + if (fail) { - if (!need_keep_aspect || keep_aspect == needed_keep_aspect) + new_aspect = 0; + new_width = new_height = 0; + } + else + { + LLComboBox* size_combo_box = NULL; + LLComboBox* aspect_combo_box = NULL; + switch(shot_type) + { + case LLSnapshotLivePreview::SNAPSHOT_FEED: + size_combo_box = view->getChild("feed_size_combo"); + aspect_combo_box = view->getChild("feed_aspect_combo"); + break; + case LLSnapshotLivePreview::SNAPSHOT_POSTCARD: + size_combo_box = view->getChild("postcard_size_combo"); + aspect_combo_box = view->getChild("postcard_aspect_combo"); + break; + case LLSnapshotLivePreview::SNAPSHOT_TEXTURE: + size_combo_box = view->getChild("texture_size_combo"); + aspect_combo_box = view->getChild("texture_aspect_combo"); + break; + case LLSnapshotLivePreview::SNAPSHOT_LOCAL: + size_combo_box = view->getChild("local_size_combo"); + aspect_combo_box = view->getChild("local_aspect_combo"); + break; + } + S32 index = 0; + S32 const size_custom = size_combo_box->getItemCount() - (shot_type == LLSnapshotLivePreview::SNAPSHOT_TEXTURE ? 0 : 1); // Texture does not end on 'Custom'. + while (index < size_custom) { size_combo_box->setCurrentByIndex(index); - std::string sdstring = combobox->getSelectedValue(); + std::string sdstring = size_combo_box->getSelectedValue(); LLSD sdres; std::stringstream sstream(sdstring); LLSDSerialize::fromNotation(sdres, sstream, sdstring.size()); @@ -2199,35 +2280,57 @@ void LLFloaterSnapshot::Impl::updateResolution(LLUICtrl* ctrl, void* data, bool width = gViewerWindow->getWindowDisplayWidth(); height = gViewerWindow->getWindowDisplayHeight(); } - if (width == used_w && height == used_h) + if (width == new_width && height == new_height) { break; } + ++index; } - ++index; - keep_aspect = false; - } - if (index == custom) - { - size_combo_box->setCurrentByIndex(index); - if (need_keep_aspect) + if (index == size_custom && shot_type != LLSnapshotLivePreview::SNAPSHOT_TEXTURE) { - // Change mScaleInsteadOfCrop to needed_keep_aspect. - gSavedSettings.setBOOL("KeepAspectForSnapshot", needed_keep_aspect); + size_combo_box->setCurrentByIndex(index); + } + index = 0; + S32 const aspect_custom = aspect_combo_box->getItemCount() - 1; + while (index < aspect_custom) + { + aspect_combo_box->setCurrentByIndex(index); + std::string sdstring = aspect_combo_box->getSelectedValue(); + std::stringstream sstream; + sstream << sdstring; + F32 aspect; + sstream >> aspect; + if (aspect == -2) // Default + { + aspect = (F32)new_width / new_height; + } + if (aspect == 0) // Current window + { + aspect = (F32)gViewerWindow->getWindowDisplayWidth() / gViewerWindow->getWindowDisplayHeight(); + } + if (llabs(aspect - new_aspect) < 0.0001) + { + break; + } + ++index; + } + if (index == aspect_custom) + { + aspect_combo_box->setCurrentByIndex(index); + setAspect(view, previewp->aspectComboName(), update_controls); } } } else -#endif { - view->getChild("feed_size_combo")->selectNthItem(gSavedSettings.getS32("SnapshotFeedLastResolution")); - view->getChild("feed_aspect_combo")->selectNthItem(gSavedSettings.getS32("SnapshotFeedLastAspect")); - view->getChild("postcard_size_combo")->selectNthItem(gSavedSettings.getS32("SnapshotPostcardLastResolution")); - view->getChild("postcard_aspect_combo")->selectNthItem(gSavedSettings.getS32("SnapshotPostcardLastAspect")); - view->getChild("texture_size_combo")->selectNthItem(gSavedSettings.getS32("SnapshotTextureLastResolution")); - view->getChild("texture_aspect_combo")->selectNthItem(gSavedSettings.getS32("SnapshotTextureLastAspect")); - view->getChild("local_size_combo")->selectNthItem(gSavedSettings.getS32("SnapshotLocalLastResolution")); - view->getChild("local_aspect_combo")->selectNthItem(gSavedSettings.getS32("SnapshotLocalLastAspect")); + view->getChild("feed_size_combo")->selectNthItem(gSavedSettings.getS32("SnapshotFeedLastResolution")); + view->getChild("feed_aspect_combo")->selectNthItem(gSavedSettings.getS32("SnapshotFeedLastAspect")); + view->getChild("postcard_size_combo")->selectNthItem(gSavedSettings.getS32("SnapshotPostcardLastResolution")); + view->getChild("postcard_aspect_combo")->selectNthItem(gSavedSettings.getS32("SnapshotPostcardLastAspect")); + view->getChild("texture_size_combo")->selectNthItem(gSavedSettings.getS32("SnapshotTextureLastResolution")); + view->getChild("texture_aspect_combo")->selectNthItem(gSavedSettings.getS32("SnapshotTextureLastAspect")); + view->getChild("local_size_combo")->selectNthItem(gSavedSettings.getS32("SnapshotLocalLastResolution")); + view->getChild("local_aspect_combo")->selectNthItem(gSavedSettings.getS32("SnapshotLocalLastAspect")); } std::string sdstring = combobox->getSelectedValue(); @@ -2249,9 +2352,9 @@ void LLFloaterSnapshot::Impl::updateResolution(LLUICtrl* ctrl, void* data, bool } else if (width == -1 || height == -1) { - if (previewp->isUsed() && used_w != 0 && used_h != 0) + if (previewp->isUsed() && new_width != 0 && new_height != 0) { - previewp->setSize(used_w, used_h); + previewp->setSize(new_width, new_height); } else { @@ -2299,8 +2402,17 @@ void LLFloaterSnapshot::Impl::updateResolution(LLUICtrl* ctrl, void* data, bool if (previewp) { - // In case the aspect is 'Default', need to update aspect (which will call updateControls, if necessary). - setAspect(view, previewp->aspectComboName(), update_controls); + if (new_aspect == 0) + { + // In case the aspect is 'Default', need to update aspect (which will call updateControls, if necessary). + setAspect(view, previewp->aspectComboName(), update_controls); + } + else + { + LLSpinCtrl* aspect_spinner = view->getChild("aspect_ratio"); + aspect_spinner->set(new_aspect); + previewp->setAspect(new_aspect); + } } } @@ -2316,7 +2428,6 @@ void LLFloaterSnapshot::Impl::updateAspect(LLUICtrl* ctrl, void* data, bool upda } LLSnapshotLivePreview* previewp = getPreviewView(view); - //LLSnapshotLivePreview::ESnapshotType shot_type = (LLSnapshotLivePreview::ESnapshotType)gSavedSettings.getS32("LastSnapshotType"); view->getChild("feed_aspect_combo")->selectNthItem(gSavedSettings.getS32("SnapshotFeedLastAspect")); view->getChild("postcard_aspect_combo")->selectNthItem(gSavedSettings.getS32("SnapshotPostcardLastAspect")); @@ -2742,6 +2853,12 @@ void LLFloaterSnapshot::update() } } +//static +void LLFloaterSnapshot::updateControls() +{ + Impl::updateControls(sInstance); +} + BOOL LLFloaterSnapshot::handleKeyHere(KEY key, MASK mask) { static const LLCachedControl freeze_time("FreezeTime",false); diff --git a/indra/newview/llfloatersnapshot.h b/indra/newview/llfloatersnapshot.h index 2ca66c1cd..3c0bc4a81 100644 --- a/indra/newview/llfloatersnapshot.h +++ b/indra/newview/llfloatersnapshot.h @@ -75,6 +75,8 @@ public: static void saveLocalDone(bool success); static void saveFeedDone(bool success); + static void updateControls(); + private: class Impl; Impl& impl; diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 13381f167..d68b64253 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -55,6 +55,7 @@ #include "llwindow.h" #include "llvieweraudio.h" #include "llweb.h" +#include "llwebprofile.h" #include "llfloateravatarinfo.h" // for getProfileURL() function //#include "viewerversion.h" @@ -182,11 +183,37 @@ public: LL_INFOS("MediaAuth") << "status = " << status << ", reason = " << reason << LL_ENDL; LL_INFOS("MediaAuth") << headers << LL_ENDL; + bool found = false; AIHTTPReceivedHeaders::range_type cookies; if (headers.getValues("set-cookie", cookies)) { for (AIHTTPReceivedHeaders::iterator_type cookie = cookies.first; cookie != cookies.second; ++cookie) + { LLViewerMedia::getCookieStore()->setCookiesFromHost(cookie->second, mHost); + // The should be only one set-cookie header, and the key should be '_my_secondlife_session'. + // However, lets be a little more flexible. We look for the first header with a key that + // contains the string 'session'. + std::string key = cookie->second.substr(0, cookie->second.find('=')); + if (key.find("session") != std::string::npos) + { + // Set cookie for snapshot publishing. + std::string auth_cookie = cookie->second.substr(0, cookie->second.find(";")); // strip path + if (found) + { + llwarns << "LLViewerMediaWebProfileResponder received more than one *session* cookie!?!" << llendl; + } + else + { + LL_INFOS("MediaAuth") << "Setting openID auth cookie \"" << auth_cookie << "\"." << LL_ENDL; + LLWebProfile::setAuthCookie(auth_cookie); + found = true; + } + } + } + } + if (!found) + { + llwarns << "LLViewerMediaWebProfileResponder did not receive a session ID cookie! OpenID authentications will fail!" << llendl; } } diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index 2934596e1..3f1c023df 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -1340,7 +1340,7 @@ void LLViewerObjectList::killAllObjects() killObject(objectp); // Object must be dead, or it's the LLVOAvatarSelf which never dies. - llassert((objectp == gAgentAvatarp) || objectp->isDead()); + llassert((objectp == gAgentAvatarp) || objectp->isDead() || (objectp->asAvatar() && objectp->asAvatar()->isFrozenDead())); } cleanDeadObjects(FALSE); diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index f152d3bd9..789d69590 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -341,6 +341,7 @@ public: BOOL hasGray() const; S32 getRezzedStatus() const; // 0 = cloud, 1 = gray, 2 = fully textured. void updateRezzedStatusTimers(); + bool isFrozenDead() const { return mFreezeTimeDead; } S32 mLastRezzedStatus; protected: diff --git a/indra/newview/llwebprofile.cpp b/indra/newview/llwebprofile.cpp index 69c1bf0e5..cc605e40e 100644 --- a/indra/newview/llwebprofile.cpp +++ b/indra/newview/llwebprofile.cpp @@ -114,7 +114,7 @@ public: config["caption"] = data.get("caption", "").asString(); // Do the actual image upload using the configuration. - LL_DEBUGS("Snapshots") << "Got upload config, POSTing image to " << upload_url << ", config=[" << config << "]" << llendl; + LL_DEBUGS("Snapshots") << "Got upload config, POSTing image to " << upload_url << ", config=[" << config << "]" << LL_ENDL; LLWebProfile::post(mImagep, config, upload_url); } @@ -151,7 +151,7 @@ public: strstrm << istr.rdbuf(); const std::string body = strstrm.str(); llinfos << "Image uploaded." << llendl; - LL_DEBUGS("Snapshots") << "Uploading image succeeded. Response: [" << body << "]" << llendl; + LL_DEBUGS("Snapshots") << "Uploading image succeeded. Response: [" << body << "]" << LL_ENDL; LLWebProfile::reportImageUploadStatus(true); } @@ -173,10 +173,11 @@ class LLWebProfileResponders::PostImageResponder : public LLHTTPClient::Responde public: /*virtual*/ bool needsHeaders(void) const { return true; } - /*virtual*/ void completedHeader(U32 status, const std::string& reason, const LLSD& content) + /*virtual*/ void completedHeaders(U32 status, std::string const& reason, AIHTTPReceivedHeaders const& received_headers) { - // Viewer seems to fail to follow a 303 redirect on POST request - // (URLRequest Error: 65, Send failed since rewinding of the data stream failed). + // Server abuses 303 status; Curl can't handle it because it tries to resent + // the just uploaded data, which fails + // (CURLE_SEND_FAIL_REWIND: Send failed since rewinding of the data stream failed). // Handle it manually. if (status == 303) { @@ -184,14 +185,15 @@ public: headers.addHeader("Accept", "*/*"); headers.addHeader("Cookie", LLWebProfile::getAuthCookie()); headers.addHeader("User-Agent", LLViewerMedia::getCurrentUserAgent()); - const std::string& redir_url = content["location"]; - LL_DEBUGS("Snapshots") << "Got redirection URL: " << redir_url << llendl; + std::string redir_url; + received_headers.getFirstValue("location", redir_url); + LL_DEBUGS("Snapshots") << "Got redirection URL: " << redir_url << LL_ENDL; LLHTTPClient::get(redir_url, new LLWebProfileResponders::PostImageRedirectResponder, headers); } else { llwarns << "Unexpected POST status: " << status << " " << reason << llendl; - LL_DEBUGS("Snapshots") << "headers: [" << content << "]" << llendl; + LL_DEBUGS("Snapshots") << "received_headers: [" << received_headers << "]" << LL_ENDL; LLWebProfile::reportImageUploadStatus(false); } } @@ -205,7 +207,7 @@ public: protected: /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return webProfileResponders_timeout; } - /*virtual*/ bool followRedir(void) const { return true; } + /*virtual*/ bool redirect_status_ok(void) const { return true; } }; /////////////////////////////////////////////////////////////////////////////// @@ -222,7 +224,7 @@ void LLWebProfile::uploadImage(LLPointer image, const std::str config_url += "?caption=" + LLURI::escape(caption); config_url += "&add_loc=" + std::string(add_location ? "1" : "0"); - LL_DEBUGS("Snapshots") << "Requesting " << config_url << llendl; + LL_DEBUGS("Snapshots") << "Requesting " << config_url << LL_ENDL; AIHTTPHeaders headers; headers.addHeader("Accept", "*/*"); headers.addHeader("Cookie", LLWebProfile::getAuthCookie()); @@ -233,7 +235,7 @@ void LLWebProfile::uploadImage(LLPointer image, const std::str // static void LLWebProfile::setAuthCookie(const std::string& cookie) { - LL_DEBUGS("Snapshots") << "Setting auth cookie: " << cookie << llendl; + LL_DEBUGS("Snapshots") << "Setting auth cookie: " << cookie << LL_ENDL; sAuthCookie = cookie; } @@ -289,24 +291,22 @@ void LLWebProfile::post(LLPointer image, const LLSD& config, c body << "--" << boundary << "\r\n" << "Content-Disposition: form-data; name=\"file\"; filename=\"snapshot.png\"\r\n" << "Content-Type: image/png\r\n\r\n"; + size_t const body_size = body.str().size(); - // Insert the image data. - // *FIX: Treating this as a string will probably screw it up ... - U8* image_data = image->getData(); - for (S32 i = 0; i < image->getDataSize(); ++i) - { - body << image_data[i]; - } - - body << "\r\n--" << boundary << "--\r\n"; + std::ostringstream footer; + footer << "\r\n--" << boundary << "--\r\n"; + size_t const footer_size = footer.str().size(); + size_t size = body_size + image->getDataSize() + footer_size; // postRaw() takes ownership of the buffer and releases it later. - size_t size = body.str().size(); char* data = new char [size]; - memcpy(data, body.str().data(), size); + memcpy(data, body.str().data(), body_size); + // Insert the image data. + memcpy(data + body_size, image->getData(), image->getDataSize()); + memcpy(data + body_size + image->getDataSize(), footer.str().data(), footer_size); // Send request, successful upload will trigger posting metadata. - LLHTTPClient::postRaw(url, data, size, new LLWebProfileResponders::PostImageResponder(), headers); + LLHTTPClient::postRaw(url, data, size, new LLWebProfileResponders::PostImageResponder(), headers, no_keep_alive); } // static diff --git a/indra/newview/skins/default/xui/en-us/floater_snapshot.xml b/indra/newview/skins/default/xui/en-us/floater_snapshot.xml index 91d3de89e..b1c810961 100644 --- a/indra/newview/skins/default/xui/en-us/floater_snapshot.xml +++ b/indra/newview/skins/default/xui/en-us/floater_snapshot.xml @@ -53,11 +53,11 @@