2015-05-03 22:32:37 +03:00
|
|
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
2012-05-21 15:12:37 +04:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
2001-03-22 04:42:32 +03:00
|
|
|
|
2013-05-06 17:42:00 +04:00
|
|
|
#include "ImageDocument.h"
|
2018-01-08 16:05:06 +03:00
|
|
|
#include "mozilla/dom/DOMPrefs.h"
|
2013-05-06 17:42:00 +04:00
|
|
|
#include "mozilla/dom/ImageDocumentBinding.h"
|
2016-03-05 02:02:08 +03:00
|
|
|
#include "mozilla/dom/HTMLImageElement.h"
|
2003-01-18 13:17:58 +03:00
|
|
|
#include "nsRect.h"
|
2003-04-02 07:27:20 +04:00
|
|
|
#include "nsIImageLoadingContent.h"
|
2001-10-30 13:14:06 +03:00
|
|
|
#include "nsGenericHTMLElement.h"
|
2013-11-15 11:12:43 +04:00
|
|
|
#include "nsDocShell.h"
|
2013-01-13 01:53:01 +04:00
|
|
|
#include "nsIDocumentInlines.h"
|
2013-03-16 00:45:40 +04:00
|
|
|
#include "nsDOMTokenList.h"
|
2003-01-18 13:17:58 +03:00
|
|
|
#include "nsIDOMEvent.h"
|
2004-09-10 02:40:40 +04:00
|
|
|
#include "nsIDOMMouseEvent.h"
|
2003-01-18 13:17:58 +03:00
|
|
|
#include "nsIDOMEventListener.h"
|
2013-11-20 02:24:59 +04:00
|
|
|
#include "nsIFrame.h"
|
2006-12-26 20:47:52 +03:00
|
|
|
#include "nsGkAtoms.h"
|
2001-03-22 04:42:32 +03:00
|
|
|
#include "imgIRequest.h"
|
|
|
|
#include "imgILoader.h"
|
2001-04-24 03:46:50 +04:00
|
|
|
#include "imgIContainer.h"
|
2012-10-12 20:11:22 +04:00
|
|
|
#include "imgINotificationObserver.h"
|
1998-07-27 21:50:58 +04:00
|
|
|
#include "nsIPresShell.h"
|
2004-08-01 03:15:21 +04:00
|
|
|
#include "nsPresContext.h"
|
2003-02-22 03:32:13 +03:00
|
|
|
#include "nsStyleContext.h"
|
2004-07-18 23:40:44 +04:00
|
|
|
#include "nsIChannel.h"
|
|
|
|
#include "nsIContentPolicy.h"
|
|
|
|
#include "nsContentPolicyUtils.h"
|
|
|
|
#include "nsPIDOMWindow.h"
|
|
|
|
#include "nsIDOMElement.h"
|
2012-07-27 18:03:27 +04:00
|
|
|
#include "nsError.h"
|
2009-02-16 14:27:22 +03:00
|
|
|
#include "nsURILoader.h"
|
2008-02-07 22:58:05 +03:00
|
|
|
#include "nsIDocShell.h"
|
|
|
|
#include "nsIContentViewer.h"
|
2009-11-20 07:39:11 +03:00
|
|
|
#include "nsThreadUtils.h"
|
2010-01-12 00:45:04 +03:00
|
|
|
#include "nsIScrollableFrame.h"
|
2011-08-11 17:29:50 +04:00
|
|
|
#include "nsContentUtils.h"
|
2010-05-05 22:18:05 +04:00
|
|
|
#include "mozilla/dom/Element.h"
|
2011-05-25 10:31:59 +04:00
|
|
|
#include "mozilla/Preferences.h"
|
2013-01-15 16:22:03 +04:00
|
|
|
#include <algorithm>
|
2010-04-30 17:12:05 +04:00
|
|
|
|
2003-01-18 13:17:58 +03:00
|
|
|
#define AUTOMATIC_IMAGE_RESIZING_PREF "browser.enable_automatic_image_resizing"
|
2009-07-29 07:02:55 +04:00
|
|
|
#define CLICK_IMAGE_RESIZING_PREF "browser.enable_click_image_resizing"
|
2017-06-19 05:33:23 +03:00
|
|
|
|
2009-09-10 00:04:05 +04:00
|
|
|
//XXX A hack needed for Firefox's site specific zoom.
|
2017-06-19 05:33:23 +03:00
|
|
|
static bool IsSiteSpecific()
|
|
|
|
{
|
2018-01-08 16:05:06 +03:00
|
|
|
return !mozilla::dom::DOMPrefs::ResistFingerprintingEnabled() &&
|
2017-06-19 05:33:23 +03:00
|
|
|
mozilla::Preferences::GetBool("browser.zoom.siteSpecific", false);
|
|
|
|
}
|
1998-07-27 21:50:58 +04:00
|
|
|
|
2011-05-26 12:06:31 +04:00
|
|
|
namespace mozilla {
|
|
|
|
namespace dom {
|
2017-06-19 05:33:23 +03:00
|
|
|
|
2011-05-26 12:06:31 +04:00
|
|
|
class ImageListener : public MediaDocumentStreamListener
|
2003-02-18 03:18:44 +03:00
|
|
|
{
|
|
|
|
public:
|
2013-07-29 19:03:41 +04:00
|
|
|
NS_DECL_NSIREQUESTOBSERVER
|
|
|
|
|
2014-09-02 04:49:25 +04:00
|
|
|
explicit ImageListener(ImageDocument* aDocument);
|
2003-02-18 03:18:44 +03:00
|
|
|
virtual ~ImageListener();
|
|
|
|
};
|
1998-07-27 21:50:58 +04:00
|
|
|
|
2011-05-26 12:06:31 +04:00
|
|
|
ImageListener::ImageListener(ImageDocument* aDocument)
|
|
|
|
: MediaDocumentStreamListener(aDocument)
|
2003-02-18 03:18:44 +03:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
ImageListener::~ImageListener()
|
|
|
|
{
|
2003-09-08 01:50:21 +04:00
|
|
|
}
|
2003-02-18 03:18:44 +03:00
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
ImageListener::OnStartRequest(nsIRequest* request, nsISupports *ctxt)
|
|
|
|
{
|
2003-04-04 04:26:33 +04:00
|
|
|
NS_ENSURE_TRUE(mDocument, NS_ERROR_FAILURE);
|
|
|
|
|
2011-05-26 12:06:31 +04:00
|
|
|
ImageDocument *imgDoc = static_cast<ImageDocument*>(mDocument.get());
|
2003-02-18 03:18:44 +03:00
|
|
|
nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
|
|
|
|
if (!channel) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
2016-01-30 20:05:36 +03:00
|
|
|
nsCOMPtr<nsPIDOMWindowOuter> domWindow = imgDoc->GetWindow();
|
2004-07-18 23:40:44 +04:00
|
|
|
NS_ENSURE_TRUE(domWindow, NS_ERROR_UNEXPECTED);
|
|
|
|
|
|
|
|
// Do a ShouldProcess check to see whether to keep loading the image.
|
|
|
|
nsCOMPtr<nsIURI> channelURI;
|
|
|
|
channel->GetURI(getter_AddRefs(channelURI));
|
|
|
|
|
2012-09-02 06:35:17 +04:00
|
|
|
nsAutoCString mimeType;
|
2004-07-18 23:40:44 +04:00
|
|
|
channel->GetContentType(mimeType);
|
2007-08-08 05:16:09 +04:00
|
|
|
|
|
|
|
nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
|
|
|
|
nsCOMPtr<nsIPrincipal> channelPrincipal;
|
|
|
|
if (secMan) {
|
2014-08-07 03:05:40 +04:00
|
|
|
secMan->GetChannelResultPrincipal(channel, getter_AddRefs(channelPrincipal));
|
2007-08-08 05:16:09 +04:00
|
|
|
}
|
2013-07-29 19:03:41 +04:00
|
|
|
|
Bug 1407056: Part 1 - Provide more consistent principal/origin URL to content policies. r=bz,ckerschb
We're currently fairly vague and inconsistent about the values we provide to
content policy implementations for requestOrigin and requestPrincipal. In some
cases they're the triggering principal, sometimes the loading principal,
sometimes the channel principal.
Our existing content policy implementations which require or expect a loading
principal currently retrieve it from the context node. Since no current
callers require the principal to be the loading principal, and some already
expect it to be the triggering principal (which there's currently no other way
to retrieve), I chose to pass the triggering principal whenever possible, but
use the loading principal to determine the origin URL.
As a follow-up, I'd like to change the nsIContentPolicy interface to
explicitly receive loading and triggering principals, or possibly just
LoadInfo instances, rather than poorly-defined request
origin/principal/context args. But since that may cause trouble for
comm-central, I'd rather not do it as part of this bug.
MozReview-Commit-ID: LqD9GxdzMte
--HG--
extra : rebase_source : 41ce439912ae7b895e0a3b0e660fa6ba571eb50f
2017-10-13 01:43:55 +03:00
|
|
|
nsCOMPtr<nsILoadInfo> loadInfo = channel->GetLoadInfo();
|
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
int16_t decision = nsIContentPolicy::ACCEPT;
|
2015-09-21 00:55:59 +03:00
|
|
|
nsresult rv = NS_CheckContentProcessPolicy(nsIContentPolicy::TYPE_INTERNAL_IMAGE,
|
2004-07-18 23:40:44 +04:00
|
|
|
channelURI,
|
2007-08-08 05:16:09 +04:00
|
|
|
channelPrincipal,
|
Bug 1407056: Part 1 - Provide more consistent principal/origin URL to content policies. r=bz,ckerschb
We're currently fairly vague and inconsistent about the values we provide to
content policy implementations for requestOrigin and requestPrincipal. In some
cases they're the triggering principal, sometimes the loading principal,
sometimes the channel principal.
Our existing content policy implementations which require or expect a loading
principal currently retrieve it from the context node. Since no current
callers require the principal to be the loading principal, and some already
expect it to be the triggering principal (which there's currently no other way
to retrieve), I chose to pass the triggering principal whenever possible, but
use the loading principal to determine the origin URL.
As a follow-up, I'd like to change the nsIContentPolicy interface to
explicitly receive loading and triggering principals, or possibly just
LoadInfo instances, rather than poorly-defined request
origin/principal/context args. But since that may cause trouble for
comm-central, I'd rather not do it as part of this bug.
MozReview-Commit-ID: LqD9GxdzMte
--HG--
extra : rebase_source : 41ce439912ae7b895e0a3b0e660fa6ba571eb50f
2017-10-13 01:43:55 +03:00
|
|
|
loadInfo ? loadInfo->TriggeringPrincipal() : nullptr,
|
2004-07-18 23:40:44 +04:00
|
|
|
domWindow->GetFrameElementInternal(),
|
|
|
|
mimeType,
|
2012-07-30 18:20:58 +04:00
|
|
|
nullptr,
|
2005-08-19 19:00:01 +04:00
|
|
|
&decision,
|
2017-07-11 01:00:03 +03:00
|
|
|
nsContentUtils::GetContentPolicy());
|
2013-07-29 19:03:41 +04:00
|
|
|
|
2004-07-18 23:40:44 +04:00
|
|
|
if (NS_FAILED(rv) || NS_CP_REJECTED(decision)) {
|
|
|
|
request->Cancel(NS_ERROR_CONTENT_BLOCKED);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2014-07-30 02:23:22 +04:00
|
|
|
if (!imgDoc->mObservingImageLoader) {
|
|
|
|
nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(imgDoc->mImageContent);
|
|
|
|
NS_ENSURE_TRUE(imageLoader, NS_ERROR_UNEXPECTED);
|
2003-04-02 07:27:20 +04:00
|
|
|
|
2017-07-19 21:15:12 +03:00
|
|
|
imageLoader->AddNativeObserver(imgDoc);
|
2014-07-30 02:23:22 +04:00
|
|
|
imgDoc->mObservingImageLoader = true;
|
|
|
|
imageLoader->LoadImageWithChannel(channel, getter_AddRefs(mNextStream));
|
|
|
|
}
|
2003-02-18 03:18:44 +03:00
|
|
|
|
2011-05-26 12:06:31 +04:00
|
|
|
return MediaDocumentStreamListener::OnStartRequest(request, ctxt);
|
2003-02-18 03:18:44 +03:00
|
|
|
}
|
|
|
|
|
2013-07-29 19:03:41 +04:00
|
|
|
NS_IMETHODIMP
|
|
|
|
ImageListener::OnStopRequest(nsIRequest* aRequest, nsISupports* aCtxt, nsresult aStatus)
|
|
|
|
{
|
|
|
|
ImageDocument* imgDoc = static_cast<ImageDocument*>(mDocument.get());
|
|
|
|
nsContentUtils::DispatchChromeEvent(imgDoc, static_cast<nsIDocument*>(imgDoc),
|
|
|
|
NS_LITERAL_STRING("ImageContentLoaded"),
|
|
|
|
true, true);
|
|
|
|
return MediaDocumentStreamListener::OnStopRequest(aRequest, aCtxt, aStatus);
|
|
|
|
}
|
|
|
|
|
2011-05-26 12:06:31 +04:00
|
|
|
ImageDocument::ImageDocument()
|
2017-01-24 19:10:39 +03:00
|
|
|
: MediaDocument()
|
|
|
|
, mVisibleWidth(0.0)
|
|
|
|
, mVisibleHeight(0.0)
|
|
|
|
, mImageWidth(0)
|
|
|
|
, mImageHeight(0)
|
|
|
|
, mResizeImageByDefault(false)
|
|
|
|
, mClickResizingEnabled(false)
|
|
|
|
, mImageIsOverflowingHorizontally(false)
|
|
|
|
, mImageIsOverflowingVertically(false)
|
|
|
|
, mImageIsResized(false)
|
|
|
|
, mShouldResize(false)
|
|
|
|
, mFirstResize(false)
|
|
|
|
, mObservingImageLoader(false)
|
|
|
|
, mOriginalZoomLevel(1.0)
|
2003-01-18 13:17:58 +03:00
|
|
|
{
|
1998-07-27 21:50:58 +04:00
|
|
|
}
|
|
|
|
|
2011-05-26 12:06:31 +04:00
|
|
|
ImageDocument::~ImageDocument()
|
1998-07-27 21:50:58 +04:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2008-12-03 13:30:26 +03:00
|
|
|
|
2014-04-25 20:49:00 +04:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_INHERITED(ImageDocument, MediaDocument,
|
|
|
|
mImageContent)
|
2008-12-03 13:30:26 +03:00
|
|
|
|
2017-09-01 02:29:22 +03:00
|
|
|
NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED(ImageDocument,
|
|
|
|
MediaDocument,
|
|
|
|
nsIImageDocument,
|
|
|
|
imgINotificationObserver,
|
|
|
|
nsIDOMEventListener)
|
2002-01-25 09:37:35 +03:00
|
|
|
|
|
|
|
|
2003-01-18 13:17:58 +03:00
|
|
|
nsresult
|
2011-05-26 12:06:31 +04:00
|
|
|
ImageDocument::Init()
|
2003-01-18 13:17:58 +03:00
|
|
|
{
|
2011-05-26 12:06:31 +04:00
|
|
|
nsresult rv = MediaDocument::Init();
|
2003-01-18 13:17:58 +03:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2002-01-25 09:37:35 +03:00
|
|
|
|
2011-05-25 10:31:59 +04:00
|
|
|
mResizeImageByDefault = Preferences::GetBool(AUTOMATIC_IMAGE_RESIZING_PREF);
|
|
|
|
mClickResizingEnabled = Preferences::GetBool(CLICK_IMAGE_RESIZING_PREF);
|
2006-03-07 04:44:44 +03:00
|
|
|
mShouldResize = mResizeImageByDefault;
|
2011-10-17 18:59:28 +04:00
|
|
|
mFirstResize = true;
|
2002-01-25 09:37:35 +03:00
|
|
|
|
|
|
|
return NS_OK;
|
1998-07-27 21:50:58 +04:00
|
|
|
}
|
|
|
|
|
2013-05-06 17:42:00 +04:00
|
|
|
JSObject*
|
Bug 1117172 part 3. Change the wrappercached WrapObject methods to allow passing in aGivenProto. r=peterv
The only manual changes here are to BindingUtils.h, BindingUtils.cpp,
Codegen.py, Element.cpp, IDBFileRequest.cpp, IDBObjectStore.cpp,
dom/workers/Navigator.cpp, WorkerPrivate.cpp, DeviceStorageRequestChild.cpp,
Notification.cpp, nsGlobalWindow.cpp, MessagePort.cpp, nsJSEnvironment.cpp,
Sandbox.cpp, XPCConvert.cpp, ExportHelpers.cpp, and DataStoreService.cpp. The
rest of this diff was generated by running the following commands:
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapObjectInternal\(JSContext *\* *(?:aCx|cx|aContext|aCtx|js))\)/\1, JS::Handle<JSObject*> aGivenProto)/g'
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapObjectInternal\((?:aCx|cx|aContext|aCtx|js))\)/\1, aGivenProto)/g'
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapNode\(JSContext *\* *(?:aCx|cx|aContext|aCtx|js))\)/\1, JS::Handle<JSObject*> aGivenProto)/g'
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapNode\((?:aCx|cx|aContext|aCtx|js))\)/\1, aGivenProto)/g'
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapObject\(JSContext *\* *(?:aCx|cx|aContext|aCtx|js))\)/\1, JS::Handle<JSObject*> aGivenProto)/g'
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(Binding(?:_workers)?::Wrap\((?:aCx|cx|aContext|aCtx|js), [^,)]+)\)/\1, aGivenProto)/g'
2015-03-19 17:13:33 +03:00
|
|
|
ImageDocument::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
2013-05-06 17:42:00 +04:00
|
|
|
{
|
Bug 1117172 part 3. Change the wrappercached WrapObject methods to allow passing in aGivenProto. r=peterv
The only manual changes here are to BindingUtils.h, BindingUtils.cpp,
Codegen.py, Element.cpp, IDBFileRequest.cpp, IDBObjectStore.cpp,
dom/workers/Navigator.cpp, WorkerPrivate.cpp, DeviceStorageRequestChild.cpp,
Notification.cpp, nsGlobalWindow.cpp, MessagePort.cpp, nsJSEnvironment.cpp,
Sandbox.cpp, XPCConvert.cpp, ExportHelpers.cpp, and DataStoreService.cpp. The
rest of this diff was generated by running the following commands:
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapObjectInternal\(JSContext *\* *(?:aCx|cx|aContext|aCtx|js))\)/\1, JS::Handle<JSObject*> aGivenProto)/g'
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapObjectInternal\((?:aCx|cx|aContext|aCtx|js))\)/\1, aGivenProto)/g'
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapNode\(JSContext *\* *(?:aCx|cx|aContext|aCtx|js))\)/\1, JS::Handle<JSObject*> aGivenProto)/g'
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapNode\((?:aCx|cx|aContext|aCtx|js))\)/\1, aGivenProto)/g'
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapObject\(JSContext *\* *(?:aCx|cx|aContext|aCtx|js))\)/\1, JS::Handle<JSObject*> aGivenProto)/g'
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(Binding(?:_workers)?::Wrap\((?:aCx|cx|aContext|aCtx|js), [^,)]+)\)/\1, aGivenProto)/g'
2015-03-19 17:13:33 +03:00
|
|
|
return ImageDocumentBinding::Wrap(aCx, this, aGivenProto);
|
2013-05-06 17:42:00 +04:00
|
|
|
}
|
|
|
|
|
2004-01-10 02:54:21 +03:00
|
|
|
nsresult
|
2011-05-26 12:06:31 +04:00
|
|
|
ImageDocument::StartDocumentLoad(const char* aCommand,
|
|
|
|
nsIChannel* aChannel,
|
|
|
|
nsILoadGroup* aLoadGroup,
|
|
|
|
nsISupports* aContainer,
|
|
|
|
nsIStreamListener** aDocListener,
|
2011-09-29 10:19:26 +04:00
|
|
|
bool aReset,
|
2011-05-26 12:06:31 +04:00
|
|
|
nsIContentSink* aSink)
|
1998-07-27 21:50:58 +04:00
|
|
|
{
|
2003-03-26 10:41:30 +03:00
|
|
|
nsresult rv =
|
2011-05-26 12:06:31 +04:00
|
|
|
MediaDocument::StartDocumentLoad(aCommand, aChannel, aLoadGroup, aContainer,
|
|
|
|
aDocListener, aReset, aSink);
|
1998-12-11 05:47:25 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
2000-01-27 05:15:19 +03:00
|
|
|
|
2017-06-19 05:33:23 +03:00
|
|
|
mOriginalZoomLevel = IsSiteSpecific() ? 1.0 : GetZoomLevel();
|
2009-09-01 17:15:33 +04:00
|
|
|
|
2003-03-22 06:20:23 +03:00
|
|
|
NS_ASSERTION(aDocListener, "null aDocListener");
|
2003-04-04 04:26:33 +04:00
|
|
|
*aDocListener = new ImageListener(this);
|
|
|
|
NS_ADDREF(*aDocListener);
|
1998-07-27 21:50:58 +04:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2003-10-22 10:09:48 +04:00
|
|
|
void
|
2011-05-26 12:06:31 +04:00
|
|
|
ImageDocument::Destroy()
|
2002-12-14 02:53:43 +03:00
|
|
|
{
|
2005-05-20 05:31:26 +04:00
|
|
|
if (mImageContent) {
|
|
|
|
// Remove our event listener from the image content.
|
2013-04-06 04:44:15 +04:00
|
|
|
nsCOMPtr<EventTarget> target = do_QueryInterface(mImageContent);
|
2013-11-20 02:24:59 +04:00
|
|
|
target->RemoveEventListener(NS_LITERAL_STRING("load"), this, false);
|
2011-10-17 18:59:28 +04:00
|
|
|
target->RemoveEventListener(NS_LITERAL_STRING("click"), this, false);
|
2005-05-20 05:31:26 +04:00
|
|
|
|
|
|
|
// Break reference cycle with mImageContent, if we have one
|
2008-08-02 00:58:59 +04:00
|
|
|
if (mObservingImageLoader) {
|
|
|
|
nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mImageContent);
|
|
|
|
if (imageLoader) {
|
2017-07-19 21:15:12 +03:00
|
|
|
imageLoader->RemoveNativeObserver(this);
|
2008-08-02 00:58:59 +04:00
|
|
|
}
|
2005-05-20 05:31:26 +04:00
|
|
|
}
|
|
|
|
|
2012-07-30 18:20:58 +04:00
|
|
|
mImageContent = nullptr;
|
2005-05-05 00:22:32 +04:00
|
|
|
}
|
2003-01-18 13:17:58 +03:00
|
|
|
|
2011-05-26 12:06:31 +04:00
|
|
|
MediaDocument::Destroy();
|
2005-05-05 00:22:32 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2011-05-26 12:06:31 +04:00
|
|
|
ImageDocument::SetScriptGlobalObject(nsIScriptGlobalObject* aScriptGlobalObject)
|
2005-05-05 00:22:32 +04:00
|
|
|
{
|
|
|
|
// If the script global object is changing, we need to unhook our event
|
|
|
|
// listeners on the window.
|
2013-04-06 04:44:15 +04:00
|
|
|
nsCOMPtr<EventTarget> target;
|
2006-03-07 04:44:44 +03:00
|
|
|
if (mScriptGlobalObject &&
|
2005-05-05 00:22:32 +04:00
|
|
|
aScriptGlobalObject != mScriptGlobalObject) {
|
|
|
|
target = do_QueryInterface(mScriptGlobalObject);
|
2011-10-17 18:59:28 +04:00
|
|
|
target->RemoveEventListener(NS_LITERAL_STRING("resize"), this, false);
|
2005-05-05 00:22:32 +04:00
|
|
|
target->RemoveEventListener(NS_LITERAL_STRING("keypress"), this,
|
2011-10-17 18:59:28 +04:00
|
|
|
false);
|
2003-01-18 13:17:58 +03:00
|
|
|
}
|
2003-03-20 05:03:13 +03:00
|
|
|
|
|
|
|
// Set the script global object on the superclass before doing
|
|
|
|
// anything that might require it....
|
2011-12-15 19:10:36 +04:00
|
|
|
MediaDocument::SetScriptGlobalObject(aScriptGlobalObject);
|
2003-03-26 10:41:30 +03:00
|
|
|
|
2003-03-20 05:03:13 +03:00
|
|
|
if (aScriptGlobalObject) {
|
2010-04-30 17:12:05 +04:00
|
|
|
if (!GetRootElement()) {
|
2005-05-05 00:22:32 +04:00
|
|
|
// Create synthetic document
|
2008-09-24 08:37:56 +04:00
|
|
|
#ifdef DEBUG
|
|
|
|
nsresult rv =
|
|
|
|
#endif
|
|
|
|
CreateSyntheticDocument();
|
2005-05-05 00:22:32 +04:00
|
|
|
NS_ASSERTION(NS_SUCCEEDED(rv), "failed to create synthetic document");
|
|
|
|
|
2006-03-07 04:44:44 +03:00
|
|
|
target = do_QueryInterface(mImageContent);
|
2013-11-20 02:24:59 +04:00
|
|
|
target->AddEventListener(NS_LITERAL_STRING("load"), this, false);
|
2011-10-17 18:59:28 +04:00
|
|
|
target->AddEventListener(NS_LITERAL_STRING("click"), this, false);
|
2003-03-20 05:03:13 +03:00
|
|
|
}
|
|
|
|
|
2006-03-07 04:44:44 +03:00
|
|
|
target = do_QueryInterface(aScriptGlobalObject);
|
2011-10-17 18:59:28 +04:00
|
|
|
target->AddEventListener(NS_LITERAL_STRING("resize"), this, false);
|
|
|
|
target->AddEventListener(NS_LITERAL_STRING("keypress"), this, false);
|
2012-01-08 06:43:48 +04:00
|
|
|
|
2013-04-22 02:29:14 +04:00
|
|
|
if (GetReadyStateEnum() != nsIDocument::READYSTATE_COMPLETE) {
|
2017-06-08 12:52:46 +03:00
|
|
|
LinkStylesheet(NS_LITERAL_STRING("resource://content-accessible/ImageDocument.css"));
|
2013-04-22 02:29:14 +04:00
|
|
|
if (!nsContentUtils::IsChildOfSameType(this)) {
|
2017-06-08 12:52:46 +03:00
|
|
|
LinkStylesheet(NS_LITERAL_STRING("resource://content-accessible/TopLevelImageDocument.css"));
|
2013-04-22 02:29:14 +04:00
|
|
|
LinkStylesheet(NS_LITERAL_STRING("chrome://global/skin/media/TopLevelImageDocument.css"));
|
|
|
|
}
|
2012-01-08 06:43:48 +04:00
|
|
|
}
|
2012-07-27 17:35:09 +04:00
|
|
|
BecomeInteractive();
|
2002-12-14 02:53:43 +03:00
|
|
|
}
|
|
|
|
}
|
1998-09-09 20:19:30 +04:00
|
|
|
|
2009-09-01 17:15:33 +04:00
|
|
|
void
|
2011-09-29 10:19:26 +04:00
|
|
|
ImageDocument::OnPageShow(bool aPersisted,
|
2013-04-06 04:44:15 +04:00
|
|
|
EventTarget* aDispatchStartTarget)
|
2009-09-01 17:15:33 +04:00
|
|
|
{
|
|
|
|
if (aPersisted) {
|
2017-06-19 05:33:23 +03:00
|
|
|
mOriginalZoomLevel = IsSiteSpecific() ? 1.0 : GetZoomLevel();
|
2009-09-01 17:15:33 +04:00
|
|
|
}
|
2016-04-13 08:42:15 +03:00
|
|
|
RefPtr<ImageDocument> kungFuDeathGrip(this);
|
|
|
|
UpdateSizeFromLayout();
|
|
|
|
|
2011-05-26 12:06:31 +04:00
|
|
|
MediaDocument::OnPageShow(aPersisted, aDispatchStartTarget);
|
2009-09-01 17:15:33 +04:00
|
|
|
}
|
2003-01-18 13:17:58 +03:00
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2011-09-29 10:19:26 +04:00
|
|
|
ImageDocument::GetImageIsOverflowing(bool* aImageIsOverflowing)
|
2003-01-18 13:17:58 +03:00
|
|
|
{
|
2013-05-06 17:42:00 +04:00
|
|
|
*aImageIsOverflowing = ImageIsOverflowing();
|
2003-01-18 13:17:58 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2011-09-29 10:19:26 +04:00
|
|
|
ImageDocument::GetImageIsResized(bool* aImageIsResized)
|
2003-01-18 13:17:58 +03:00
|
|
|
{
|
2013-05-06 17:42:00 +04:00
|
|
|
*aImageIsResized = ImageIsResized();
|
2003-01-18 13:17:58 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2013-05-06 17:42:00 +04:00
|
|
|
already_AddRefed<imgIRequest>
|
|
|
|
ImageDocument::GetImageRequest(ErrorResult& aRv)
|
2005-08-26 00:05:24 +04:00
|
|
|
{
|
|
|
|
nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mImageContent);
|
2013-05-06 17:42:00 +04:00
|
|
|
nsCOMPtr<imgIRequest> imageRequest;
|
2005-08-26 00:05:24 +04:00
|
|
|
if (imageLoader) {
|
2013-05-06 17:42:00 +04:00
|
|
|
aRv = imageLoader->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
|
|
|
|
getter_AddRefs(imageRequest));
|
2005-08-26 00:05:24 +04:00
|
|
|
}
|
2013-05-06 17:42:00 +04:00
|
|
|
return imageRequest.forget();
|
2005-08-26 00:05:24 +04:00
|
|
|
}
|
|
|
|
|
2003-01-18 13:17:58 +03:00
|
|
|
NS_IMETHODIMP
|
2013-05-06 17:42:00 +04:00
|
|
|
ImageDocument::GetImageRequest(imgIRequest** aImageRequest)
|
|
|
|
{
|
|
|
|
ErrorResult rv;
|
2014-03-15 23:00:15 +04:00
|
|
|
*aImageRequest = GetImageRequest(rv).take();
|
2015-04-27 16:18:51 +03:00
|
|
|
return rv.StealNSResult();
|
2013-05-06 17:42:00 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2011-05-26 12:06:31 +04:00
|
|
|
ImageDocument::ShrinkToFit()
|
2003-01-18 13:17:58 +03:00
|
|
|
{
|
2010-10-15 08:03:33 +04:00
|
|
|
if (!mImageContent) {
|
2013-05-06 17:42:00 +04:00
|
|
|
return;
|
2010-10-15 08:03:33 +04:00
|
|
|
}
|
2009-10-15 06:20:50 +04:00
|
|
|
if (GetZoomLevel() != mOriginalZoomLevel && mImageIsResized &&
|
|
|
|
!nsContentUtils::IsChildOfSameType(this)) {
|
2016-03-05 02:02:08 +03:00
|
|
|
// If we're zoomed, so that we don't maintain the invariant that
|
|
|
|
// mImageIsResized if and only if its displayed width/height fit in
|
|
|
|
// mVisibleWidth/mVisibleHeight, then we may need to switch to/from the
|
|
|
|
// overflowingVertical class here, because our viewport size may have
|
|
|
|
// changed and we don't plan to adjust the image size to compensate. Since
|
|
|
|
// mImageIsResized it has a "height" attribute set, and we can just get the
|
|
|
|
// displayed image height by getting .height on the HTMLImageElement.
|
2017-07-14 06:46:59 +03:00
|
|
|
//
|
|
|
|
// Hold strong ref, because Height() can run script.
|
|
|
|
RefPtr<HTMLImageElement> img = HTMLImageElement::FromContent(mImageContent);
|
2016-03-05 02:02:08 +03:00
|
|
|
uint32_t imageHeight = img->Height();
|
|
|
|
nsDOMTokenList* classList = img->ClassList();
|
|
|
|
ErrorResult ignored;
|
|
|
|
if (imageHeight > mVisibleHeight) {
|
|
|
|
classList->Add(NS_LITERAL_STRING("overflowingVertical"), ignored);
|
|
|
|
} else {
|
|
|
|
classList->Remove(NS_LITERAL_STRING("overflowingVertical"), ignored);
|
|
|
|
}
|
|
|
|
ignored.SuppressException();
|
2013-05-06 17:42:00 +04:00
|
|
|
return;
|
2008-02-07 22:58:05 +03:00
|
|
|
}
|
|
|
|
|
2018-02-14 18:12:24 +03:00
|
|
|
uint32_t newWidth = std::max(1, NSToCoordFloor(GetRatio() * mImageWidth));
|
|
|
|
uint32_t newHeight = std::max(1, NSToCoordFloor(GetRatio() * mImageHeight));
|
|
|
|
|
2016-02-27 21:53:28 +03:00
|
|
|
// Keep image content alive while changing the attributes.
|
2017-07-14 06:46:12 +03:00
|
|
|
RefPtr<HTMLImageElement> image = HTMLImageElement::FromContent(mImageContent);
|
2018-02-14 18:12:24 +03:00
|
|
|
|
|
|
|
if (mImageIsResized &&
|
|
|
|
newWidth == image->Width() && newHeight == image->Height()) {
|
|
|
|
// Image has already been resized.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
image->SetWidth(newWidth, IgnoreErrors());
|
|
|
|
image->SetHeight(newHeight, IgnoreErrors());
|
2017-07-06 15:00:35 +03:00
|
|
|
|
2013-05-01 13:12:41 +04:00
|
|
|
// The view might have been scrolled when zooming in, scroll back to the
|
|
|
|
// origin now that we're showing a shrunk-to-window version.
|
2013-05-06 17:42:00 +04:00
|
|
|
ScrollImageTo(0, 0, false);
|
2008-04-22 08:41:38 +04:00
|
|
|
|
2013-08-09 02:04:58 +04:00
|
|
|
if (!mImageContent) {
|
|
|
|
// ScrollImageTo flush destroyed our content.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-03-16 00:45:40 +04:00
|
|
|
SetModeClass(eShrinkToFit);
|
2017-07-06 15:00:35 +03:00
|
|
|
|
2011-10-17 18:59:28 +04:00
|
|
|
mImageIsResized = true;
|
2017-07-06 15:00:35 +03:00
|
|
|
|
2006-03-07 04:44:44 +03:00
|
|
|
UpdateTitleAndCharset();
|
2013-05-06 17:42:00 +04:00
|
|
|
}
|
2003-04-22 02:45:28 +04:00
|
|
|
|
2013-05-06 17:42:00 +04:00
|
|
|
NS_IMETHODIMP
|
|
|
|
ImageDocument::DOMShrinkToFit()
|
|
|
|
{
|
|
|
|
ShrinkToFit();
|
2003-01-18 13:17:58 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2004-09-10 02:40:40 +04:00
|
|
|
NS_IMETHODIMP
|
2013-05-06 17:42:00 +04:00
|
|
|
ImageDocument::DOMRestoreImageTo(int32_t aX, int32_t aY)
|
2008-04-22 08:41:38 +04:00
|
|
|
{
|
2013-05-06 17:42:00 +04:00
|
|
|
RestoreImageTo(aX, aY);
|
|
|
|
return NS_OK;
|
2013-04-18 19:27:37 +04:00
|
|
|
}
|
2004-09-10 02:40:40 +04:00
|
|
|
|
2013-05-06 17:42:00 +04:00
|
|
|
void
|
2013-05-01 13:12:41 +04:00
|
|
|
ImageDocument::ScrollImageTo(int32_t aX, int32_t aY, bool restoreImage)
|
2013-04-18 19:27:37 +04:00
|
|
|
{
|
2013-05-01 13:12:41 +04:00
|
|
|
if (restoreImage) {
|
|
|
|
RestoreImage();
|
2017-01-05 10:31:56 +03:00
|
|
|
FlushPendingNotifications(FlushType::Layout);
|
2013-05-01 13:12:41 +04:00
|
|
|
}
|
2004-09-10 02:40:40 +04:00
|
|
|
|
2013-08-09 02:04:58 +04:00
|
|
|
nsCOMPtr<nsIPresShell> shell = GetShell();
|
2014-07-30 02:23:22 +04:00
|
|
|
if (!shell) {
|
2013-05-06 17:42:00 +04:00
|
|
|
return;
|
2014-07-30 02:23:22 +04:00
|
|
|
}
|
2004-09-10 02:40:40 +04:00
|
|
|
|
2010-01-12 00:45:04 +03:00
|
|
|
nsIScrollableFrame* sf = shell->GetRootScrollFrameAsScrollable();
|
2014-07-30 02:23:22 +04:00
|
|
|
if (!sf) {
|
2013-05-06 17:42:00 +04:00
|
|
|
return;
|
2014-07-30 02:23:22 +04:00
|
|
|
}
|
2004-09-10 02:40:40 +04:00
|
|
|
|
2017-11-07 12:51:13 +03:00
|
|
|
float ratio = GetRatio();
|
|
|
|
// Don't try to scroll image if the document is not visible (mVisibleWidth or
|
|
|
|
// mVisibleHeight is zero).
|
|
|
|
if (ratio <= 0.0) {
|
|
|
|
return;
|
|
|
|
}
|
2013-05-01 13:12:41 +04:00
|
|
|
nsRect portRect = sf->GetScrollPortRect();
|
2018-02-19 23:15:23 +03:00
|
|
|
sf->ScrollTo(nsPoint(nsPresContext::CSSPixelsToAppUnits(aX/ratio) - portRect.width/2,
|
|
|
|
nsPresContext::CSSPixelsToAppUnits(aY/ratio) - portRect.height/2),
|
2013-05-01 13:12:41 +04:00
|
|
|
nsIScrollableFrame::INSTANT);
|
2004-09-10 02:40:40 +04:00
|
|
|
}
|
|
|
|
|
2013-05-06 17:42:00 +04:00
|
|
|
void
|
2011-05-26 12:06:31 +04:00
|
|
|
ImageDocument::RestoreImage()
|
2003-01-18 13:17:58 +03:00
|
|
|
{
|
2010-10-15 08:03:33 +04:00
|
|
|
if (!mImageContent) {
|
2013-05-06 17:42:00 +04:00
|
|
|
return;
|
2010-10-15 08:03:33 +04:00
|
|
|
}
|
2007-08-05 17:24:30 +04:00
|
|
|
// Keep image content alive while changing the attributes.
|
2016-03-03 20:55:54 +03:00
|
|
|
nsCOMPtr<Element> imageContent = mImageContent;
|
2011-10-17 18:59:28 +04:00
|
|
|
imageContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::width, true);
|
|
|
|
imageContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::height, true);
|
2017-07-06 15:00:35 +03:00
|
|
|
|
2016-02-06 07:31:09 +03:00
|
|
|
if (ImageIsOverflowing()) {
|
2016-02-06 07:31:19 +03:00
|
|
|
if (!mImageIsOverflowingVertically) {
|
|
|
|
SetModeClass(eOverflowingHorizontalOnly);
|
|
|
|
} else {
|
|
|
|
SetModeClass(eOverflowingVertical);
|
|
|
|
}
|
2003-01-18 13:17:58 +03:00
|
|
|
}
|
2006-03-07 04:44:44 +03:00
|
|
|
else {
|
2013-03-16 00:45:40 +04:00
|
|
|
SetModeClass(eNone);
|
2006-03-07 04:44:44 +03:00
|
|
|
}
|
2017-07-06 15:00:35 +03:00
|
|
|
|
2013-04-18 19:27:37 +04:00
|
|
|
mImageIsResized = false;
|
2017-07-06 15:00:35 +03:00
|
|
|
|
2006-03-07 04:44:44 +03:00
|
|
|
UpdateTitleAndCharset();
|
2013-05-06 17:42:00 +04:00
|
|
|
}
|
2003-01-18 13:17:58 +03:00
|
|
|
|
2013-05-06 17:42:00 +04:00
|
|
|
NS_IMETHODIMP
|
|
|
|
ImageDocument::DOMRestoreImage()
|
|
|
|
{
|
|
|
|
RestoreImage();
|
2003-01-18 13:17:58 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2013-05-06 17:42:00 +04:00
|
|
|
void
|
2011-05-26 12:06:31 +04:00
|
|
|
ImageDocument::ToggleImageSize()
|
2003-01-18 13:17:58 +03:00
|
|
|
{
|
2011-10-17 18:59:28 +04:00
|
|
|
mShouldResize = true;
|
2006-03-07 04:44:44 +03:00
|
|
|
if (mImageIsResized) {
|
2011-10-17 18:59:28 +04:00
|
|
|
mShouldResize = false;
|
2009-09-01 17:15:33 +04:00
|
|
|
ResetZoomLevel();
|
2006-03-07 04:44:44 +03:00
|
|
|
RestoreImage();
|
2013-05-01 13:12:41 +04:00
|
|
|
}
|
2016-02-06 07:31:09 +03:00
|
|
|
else if (ImageIsOverflowing()) {
|
2009-09-01 17:15:33 +04:00
|
|
|
ResetZoomLevel();
|
2006-03-07 04:44:44 +03:00
|
|
|
ShrinkToFit();
|
2003-01-18 13:17:58 +03:00
|
|
|
}
|
2013-05-06 17:42:00 +04:00
|
|
|
}
|
2003-01-18 13:17:58 +03:00
|
|
|
|
2013-05-06 17:42:00 +04:00
|
|
|
NS_IMETHODIMP
|
|
|
|
ImageDocument::DOMToggleImageSize()
|
|
|
|
{
|
|
|
|
ToggleImageSize();
|
2003-01-18 13:17:58 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2012-10-12 20:11:22 +04:00
|
|
|
ImageDocument::Notify(imgIRequest* aRequest, int32_t aType, const nsIntRect* aData)
|
|
|
|
{
|
2012-10-12 20:11:23 +04:00
|
|
|
if (aType == imgINotificationObserver::SIZE_AVAILABLE) {
|
2012-10-12 20:11:22 +04:00
|
|
|
nsCOMPtr<imgIContainer> image;
|
|
|
|
aRequest->GetImage(getter_AddRefs(image));
|
2014-11-18 01:29:56 +03:00
|
|
|
return OnSizeAvailable(aRequest, image);
|
2012-10-12 20:11:22 +04:00
|
|
|
}
|
|
|
|
|
2014-11-17 22:16:45 +03:00
|
|
|
// Run this using a script runner because HAS_TRANSPARENCY notifications can
|
|
|
|
// come during painting and this will trigger invalidation.
|
|
|
|
if (aType == imgINotificationObserver::HAS_TRANSPARENCY) {
|
2014-08-10 22:01:40 +04:00
|
|
|
nsCOMPtr<nsIRunnable> runnable =
|
2017-06-12 22:34:10 +03:00
|
|
|
NewRunnableMethod("dom::ImageDocument::OnHasTransparency",
|
|
|
|
this,
|
|
|
|
&ImageDocument::OnHasTransparency);
|
2014-08-10 22:01:40 +04:00
|
|
|
nsContentUtils::AddScriptRunner(runnable);
|
2012-10-12 20:11:22 +04:00
|
|
|
}
|
|
|
|
|
2012-10-12 20:11:23 +04:00
|
|
|
if (aType == imgINotificationObserver::LOAD_COMPLETE) {
|
2012-10-12 20:11:22 +04:00
|
|
|
uint32_t reqStatus;
|
|
|
|
aRequest->GetImageStatus(&reqStatus);
|
|
|
|
nsresult status =
|
|
|
|
reqStatus & imgIRequest::STATUS_ERROR ? NS_ERROR_FAILURE : NS_OK;
|
2014-11-18 01:29:56 +03:00
|
|
|
return OnLoadComplete(aRequest, status);
|
2012-10-12 20:11:22 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2014-08-10 22:01:40 +04:00
|
|
|
void
|
2014-11-17 22:16:45 +03:00
|
|
|
ImageDocument::OnHasTransparency()
|
2014-08-10 22:01:40 +04:00
|
|
|
{
|
|
|
|
if (!mImageContent || nsContentUtils::IsChildOfSameType(this)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-03-03 20:55:54 +03:00
|
|
|
nsDOMTokenList* classList = mImageContent->ClassList();
|
2014-08-10 22:01:40 +04:00
|
|
|
mozilla::ErrorResult rv;
|
2014-11-17 22:16:45 +03:00
|
|
|
classList->Add(NS_LITERAL_STRING("transparent"), rv);
|
2014-08-10 22:01:40 +04:00
|
|
|
}
|
|
|
|
|
2013-03-16 00:45:40 +04:00
|
|
|
void
|
|
|
|
ImageDocument::SetModeClass(eModeClasses mode)
|
|
|
|
{
|
2016-03-03 20:55:54 +03:00
|
|
|
nsDOMTokenList* classList = mImageContent->ClassList();
|
2016-03-05 02:02:08 +03:00
|
|
|
ErrorResult rv;
|
2013-03-16 00:45:40 +04:00
|
|
|
|
|
|
|
if (mode == eShrinkToFit) {
|
|
|
|
classList->Add(NS_LITERAL_STRING("shrinkToFit"), rv);
|
|
|
|
} else {
|
|
|
|
classList->Remove(NS_LITERAL_STRING("shrinkToFit"), rv);
|
|
|
|
}
|
|
|
|
|
2016-02-06 07:31:19 +03:00
|
|
|
if (mode == eOverflowingVertical) {
|
|
|
|
classList->Add(NS_LITERAL_STRING("overflowingVertical"), rv);
|
2013-03-16 00:45:40 +04:00
|
|
|
} else {
|
2016-02-06 07:31:19 +03:00
|
|
|
classList->Remove(NS_LITERAL_STRING("overflowingVertical"), rv);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mode == eOverflowingHorizontalOnly) {
|
|
|
|
classList->Add(NS_LITERAL_STRING("overflowingHorizontalOnly"), rv);
|
|
|
|
} else {
|
|
|
|
classList->Remove(NS_LITERAL_STRING("overflowingHorizontalOnly"), rv);
|
2013-03-16 00:45:40 +04:00
|
|
|
}
|
2016-03-05 02:02:08 +03:00
|
|
|
|
|
|
|
rv.SuppressException();
|
2013-03-16 00:45:40 +04:00
|
|
|
}
|
|
|
|
|
2012-10-12 20:11:22 +04:00
|
|
|
nsresult
|
2014-11-18 01:29:56 +03:00
|
|
|
ImageDocument::OnSizeAvailable(imgIRequest* aRequest, imgIContainer* aImage)
|
2003-01-18 13:17:58 +03:00
|
|
|
{
|
2017-02-14 01:46:47 +03:00
|
|
|
int32_t oldWidth = mImageWidth;
|
|
|
|
int32_t oldHeight = mImageHeight;
|
|
|
|
|
2013-11-20 02:24:59 +04:00
|
|
|
// Styles have not yet been applied, so we don't know the final size. For now,
|
|
|
|
// default to the image's intrinsic size.
|
2003-01-18 13:17:58 +03:00
|
|
|
aImage->GetWidth(&mImageWidth);
|
|
|
|
aImage->GetHeight(&mImageHeight);
|
2013-11-20 02:24:59 +04:00
|
|
|
|
2017-02-14 01:46:47 +03:00
|
|
|
// Multipart images send size available for each part; ignore them if it
|
|
|
|
// doesn't change our size. (We may not even support changing size in
|
|
|
|
// multipart images in the future.)
|
|
|
|
if (oldWidth == mImageWidth && oldHeight == mImageHeight) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2009-11-20 07:39:11 +03:00
|
|
|
nsCOMPtr<nsIRunnable> runnable =
|
2017-06-12 22:34:10 +03:00
|
|
|
NewRunnableMethod("dom::ImageDocument::DefaultCheckOverflowing",
|
|
|
|
this,
|
|
|
|
&ImageDocument::DefaultCheckOverflowing);
|
2009-11-20 07:39:11 +03:00
|
|
|
nsContentUtils::AddScriptRunner(runnable);
|
2004-02-08 23:58:38 +03:00
|
|
|
UpdateTitleAndCharset();
|
2003-01-18 13:17:58 +03:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2012-10-12 20:11:22 +04:00
|
|
|
nsresult
|
2014-11-18 01:29:56 +03:00
|
|
|
ImageDocument::OnLoadComplete(imgIRequest* aRequest, nsresult aStatus)
|
2010-09-12 19:22:26 +04:00
|
|
|
{
|
|
|
|
UpdateTitleAndCharset();
|
|
|
|
|
|
|
|
// mImageContent can be null if the document is already destroyed
|
|
|
|
if (NS_FAILED(aStatus) && mStringBundle && mImageContent) {
|
2012-09-02 06:35:17 +04:00
|
|
|
nsAutoCString src;
|
2010-09-12 19:22:26 +04:00
|
|
|
mDocumentURI->GetSpec(src);
|
|
|
|
NS_ConvertUTF8toUTF16 srcString(src);
|
2014-01-04 19:02:17 +04:00
|
|
|
const char16_t* formatString[] = { srcString.get() };
|
2017-08-04 07:40:52 +03:00
|
|
|
nsAutoString errorMsg;
|
2017-07-12 08:13:37 +03:00
|
|
|
mStringBundle->FormatStringFromName("InvalidImage", formatString, 1,
|
2017-08-04 07:40:52 +03:00
|
|
|
errorMsg);
|
2010-09-12 19:22:26 +04:00
|
|
|
|
2011-10-17 18:59:28 +04:00
|
|
|
mImageContent->SetAttr(kNameSpaceID_None, nsGkAtoms::alt, errorMsg, false);
|
2010-09-12 19:22:26 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2003-01-18 13:17:58 +03:00
|
|
|
NS_IMETHODIMP
|
2011-05-26 12:06:31 +04:00
|
|
|
ImageDocument::HandleEvent(nsIDOMEvent* aEvent)
|
2003-01-18 13:17:58 +03:00
|
|
|
{
|
|
|
|
nsAutoString eventType;
|
|
|
|
aEvent->GetType(eventType);
|
2004-05-23 02:15:22 +04:00
|
|
|
if (eventType.EqualsLiteral("resize")) {
|
2011-10-17 18:59:28 +04:00
|
|
|
CheckOverflowing(false);
|
2003-01-18 13:17:58 +03:00
|
|
|
}
|
2013-05-01 13:12:41 +04:00
|
|
|
else if (eventType.EqualsLiteral("click") && mClickResizingEnabled) {
|
2009-09-01 17:15:33 +04:00
|
|
|
ResetZoomLevel();
|
2011-10-17 18:59:28 +04:00
|
|
|
mShouldResize = true;
|
2013-05-01 13:12:41 +04:00
|
|
|
if (mImageIsResized) {
|
|
|
|
int32_t x = 0, y = 0;
|
|
|
|
nsCOMPtr<nsIDOMMouseEvent> event(do_QueryInterface(aEvent));
|
|
|
|
if (event) {
|
|
|
|
event->GetClientX(&x);
|
|
|
|
event->GetClientY(&y);
|
2017-07-14 06:45:50 +03:00
|
|
|
RefPtr<HTMLImageElement> img =
|
|
|
|
HTMLImageElement::FromContent(mImageContent);
|
|
|
|
x -= img->OffsetLeft();
|
|
|
|
y -= img->OffsetTop();
|
2013-04-18 19:27:37 +04:00
|
|
|
}
|
|
|
|
mShouldResize = false;
|
2013-05-01 13:12:41 +04:00
|
|
|
RestoreImageTo(x, y);
|
|
|
|
}
|
2016-02-06 07:31:09 +03:00
|
|
|
else if (ImageIsOverflowing()) {
|
2013-05-01 13:12:41 +04:00
|
|
|
ShrinkToFit();
|
2004-09-10 02:40:40 +04:00
|
|
|
}
|
2013-11-20 02:24:59 +04:00
|
|
|
} else if (eventType.EqualsLiteral("load")) {
|
|
|
|
UpdateSizeFromLayout();
|
2003-01-18 13:17:58 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2013-11-20 02:24:59 +04:00
|
|
|
void
|
|
|
|
ImageDocument::UpdateSizeFromLayout()
|
|
|
|
{
|
|
|
|
// Pull an updated size from the content frame to account for any size
|
|
|
|
// change due to CSS properties like |image-orientation|.
|
2016-03-03 20:55:54 +03:00
|
|
|
if (!mImageContent) {
|
2013-11-20 02:24:59 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-07-14 06:46:59 +03:00
|
|
|
// Need strong ref, because GetPrimaryFrame can run script.
|
|
|
|
nsCOMPtr<Element> imageContent = mImageContent;
|
|
|
|
nsIFrame* contentFrame = imageContent->GetPrimaryFrame(FlushType::Frames);
|
2013-11-20 02:24:59 +04:00
|
|
|
if (!contentFrame) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIntSize oldSize(mImageWidth, mImageHeight);
|
|
|
|
IntrinsicSize newSize = contentFrame->GetIntrinsicSize();
|
|
|
|
|
|
|
|
if (newSize.width.GetUnit() == eStyleUnit_Coord) {
|
|
|
|
mImageWidth = nsPresContext::AppUnitsToFloatCSSPixels(newSize.width.GetCoordValue());
|
|
|
|
}
|
|
|
|
if (newSize.height.GetUnit() == eStyleUnit_Coord) {
|
|
|
|
mImageHeight = nsPresContext::AppUnitsToFloatCSSPixels(newSize.height.GetCoordValue());
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ensure that our information about overflow is up-to-date if needed.
|
|
|
|
if (mImageWidth != oldSize.width || mImageHeight != oldSize.height) {
|
|
|
|
CheckOverflowing(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-07-27 21:50:58 +04:00
|
|
|
nsresult
|
2011-05-26 12:06:31 +04:00
|
|
|
ImageDocument::CreateSyntheticDocument()
|
1998-07-27 21:50:58 +04:00
|
|
|
{
|
|
|
|
// Synthesize an html document that refers to the image
|
2011-05-26 12:06:31 +04:00
|
|
|
nsresult rv = MediaDocument::CreateSyntheticDocument();
|
2000-05-10 17:13:39 +04:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2011-07-07 08:04:04 +04:00
|
|
|
// Add the image element
|
2011-08-11 08:23:00 +04:00
|
|
|
Element* body = GetBodyElement();
|
|
|
|
if (!body) {
|
|
|
|
NS_WARNING("no body on image document!");
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<mozilla::dom::NodeInfo> nodeInfo;
|
2012-07-30 18:20:58 +04:00
|
|
|
nodeInfo = mNodeInfoManager->GetNodeInfo(nsGkAtoms::img, nullptr,
|
2011-06-14 11:56:49 +04:00
|
|
|
kNameSpaceID_XHTML,
|
2018-01-30 07:10:53 +03:00
|
|
|
nsINode::ELEMENT_NODE);
|
2000-05-10 17:13:39 +04:00
|
|
|
|
2010-07-23 13:49:57 +04:00
|
|
|
mImageContent = NS_NewHTMLImageElement(nodeInfo.forget());
|
2004-09-10 02:40:40 +04:00
|
|
|
if (!mImageContent) {
|
2004-06-06 06:38:32 +04:00
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
1998-07-27 21:50:58 +04:00
|
|
|
}
|
2004-09-10 02:40:40 +04:00
|
|
|
nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mImageContent);
|
2003-04-02 07:27:20 +04:00
|
|
|
NS_ENSURE_TRUE(imageLoader, NS_ERROR_UNEXPECTED);
|
1998-09-09 20:19:30 +04:00
|
|
|
|
2012-09-02 06:35:17 +04:00
|
|
|
nsAutoCString src;
|
2004-01-10 02:54:21 +03:00
|
|
|
mDocumentURI->GetSpec(src);
|
2000-04-16 15:19:26 +04:00
|
|
|
|
2006-02-03 17:18:39 +03:00
|
|
|
NS_ConvertUTF8toUTF16 srcString(src);
|
2003-04-02 07:27:20 +04:00
|
|
|
// Make sure not to start the image load from here...
|
2011-10-17 18:59:28 +04:00
|
|
|
imageLoader->SetLoadingEnabled(false);
|
|
|
|
mImageContent->SetAttr(kNameSpaceID_None, nsGkAtoms::src, srcString, false);
|
|
|
|
mImageContent->SetAttr(kNameSpaceID_None, nsGkAtoms::alt, srcString, false);
|
1998-07-27 21:50:58 +04:00
|
|
|
|
2011-10-17 18:59:28 +04:00
|
|
|
body->AppendChildTo(mImageContent, false);
|
|
|
|
imageLoader->SetLoadingEnabled(true);
|
2003-01-18 13:17:58 +03:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2011-09-29 10:19:26 +04:00
|
|
|
ImageDocument::CheckOverflowing(bool changeState)
|
2003-01-18 13:17:58 +03:00
|
|
|
{
|
2007-07-27 00:20:30 +04:00
|
|
|
/* Create a scope so that the style context gets destroyed before we might
|
2008-01-09 12:38:28 +03:00
|
|
|
* call RebuildStyleData. Also, holding onto pointers to the
|
2012-03-08 10:11:45 +04:00
|
|
|
* presentation through style resolution is potentially dangerous.
|
2007-07-27 00:20:30 +04:00
|
|
|
*/
|
|
|
|
{
|
2018-02-21 01:00:10 +03:00
|
|
|
nsPresContext* context = GetPresContext();
|
|
|
|
if (!context) {
|
2007-07-27 00:20:30 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2003-01-18 13:17:58 +03:00
|
|
|
|
2007-07-27 00:20:30 +04:00
|
|
|
nsRect visibleArea = context->GetVisibleArea();
|
2003-01-18 13:17:58 +03:00
|
|
|
|
2018-02-19 23:15:23 +03:00
|
|
|
mVisibleWidth = nsPresContext::AppUnitsToFloatCSSPixels(visibleArea.width);
|
|
|
|
mVisibleHeight = nsPresContext::AppUnitsToFloatCSSPixels(visibleArea.height);
|
2007-07-27 00:20:30 +04:00
|
|
|
}
|
1998-07-27 21:50:58 +04:00
|
|
|
|
2016-02-06 07:31:09 +03:00
|
|
|
bool imageWasOverflowing = ImageIsOverflowing();
|
2016-02-06 07:31:19 +03:00
|
|
|
bool imageWasOverflowingVertically = mImageIsOverflowingVertically;
|
2016-02-06 07:31:09 +03:00
|
|
|
mImageIsOverflowingHorizontally = mImageWidth > mVisibleWidth;
|
|
|
|
mImageIsOverflowingVertically = mImageHeight > mVisibleHeight;
|
|
|
|
bool windowBecameBigEnough = imageWasOverflowing && !ImageIsOverflowing();
|
2016-02-06 07:31:19 +03:00
|
|
|
bool verticalOverflowChanged =
|
|
|
|
mImageIsOverflowingVertically != imageWasOverflowingVertically;
|
2003-01-18 13:17:58 +03:00
|
|
|
|
2006-12-14 05:06:49 +03:00
|
|
|
if (changeState || mShouldResize || mFirstResize ||
|
2016-02-06 07:31:19 +03:00
|
|
|
windowBecameBigEnough || verticalOverflowChanged) {
|
2016-02-06 07:31:09 +03:00
|
|
|
if (ImageIsOverflowing() && (changeState || mShouldResize)) {
|
2005-04-05 22:59:22 +04:00
|
|
|
ShrinkToFit();
|
|
|
|
}
|
2006-12-14 05:06:49 +03:00
|
|
|
else if (mImageIsResized || mFirstResize || windowBecameBigEnough) {
|
2005-04-05 22:59:22 +04:00
|
|
|
RestoreImage();
|
2016-02-06 07:31:19 +03:00
|
|
|
} else if (!mImageIsResized && verticalOverflowChanged) {
|
|
|
|
if (mImageIsOverflowingVertically) {
|
|
|
|
SetModeClass(eOverflowingVertical);
|
|
|
|
} else {
|
|
|
|
SetModeClass(eOverflowingHorizontalOnly);
|
|
|
|
}
|
2005-04-05 22:59:22 +04:00
|
|
|
}
|
2003-01-18 13:17:58 +03:00
|
|
|
}
|
2011-10-17 18:59:28 +04:00
|
|
|
mFirstResize = false;
|
1998-07-27 21:50:58 +04:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2017-07-06 15:00:35 +03:00
|
|
|
void
|
2011-05-26 12:06:31 +04:00
|
|
|
ImageDocument::UpdateTitleAndCharset()
|
2000-01-27 05:15:19 +03:00
|
|
|
{
|
2012-09-02 06:35:17 +04:00
|
|
|
nsAutoCString typeStr;
|
2003-04-13 04:40:26 +04:00
|
|
|
nsCOMPtr<imgIRequest> imageRequest;
|
2004-09-10 02:40:40 +04:00
|
|
|
nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mImageContent);
|
2003-04-13 04:40:26 +04:00
|
|
|
if (imageLoader) {
|
|
|
|
imageLoader->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
|
|
|
|
getter_AddRefs(imageRequest));
|
|
|
|
}
|
2017-07-06 15:00:35 +03:00
|
|
|
|
2003-04-13 04:40:26 +04:00
|
|
|
if (imageRequest) {
|
2017-08-16 06:58:35 +03:00
|
|
|
nsCString mimeType;
|
2003-04-13 04:40:26 +04:00
|
|
|
imageRequest->GetMimeType(getter_Copies(mimeType));
|
|
|
|
ToUpperCase(mimeType);
|
2017-08-16 06:58:35 +03:00
|
|
|
nsCString::const_iterator start, end;
|
2003-04-13 04:40:26 +04:00
|
|
|
mimeType.BeginReading(start);
|
|
|
|
mimeType.EndReading(end);
|
2017-08-16 06:58:35 +03:00
|
|
|
nsCString::const_iterator iter = end;
|
2017-07-06 15:00:35 +03:00
|
|
|
if (FindInReadable(NS_LITERAL_CSTRING("IMAGE/"), start, iter) &&
|
2003-04-13 04:40:26 +04:00
|
|
|
iter != end) {
|
|
|
|
// strip out "X-" if any
|
|
|
|
if (*iter == 'X') {
|
|
|
|
++iter;
|
|
|
|
if (iter != end && *iter == '-') {
|
2002-02-07 00:05:52 +03:00
|
|
|
++iter;
|
2003-04-13 04:40:26 +04:00
|
|
|
if (iter == end) {
|
|
|
|
// looks like "IMAGE/X-" is the type?? Bail out of here.
|
|
|
|
mimeType.BeginReading(iter);
|
2002-02-07 00:05:52 +03:00
|
|
|
}
|
2003-04-13 04:40:26 +04:00
|
|
|
} else {
|
|
|
|
--iter;
|
2002-02-07 00:05:52 +03:00
|
|
|
}
|
2002-01-16 02:34:32 +03:00
|
|
|
}
|
2003-04-13 04:40:26 +04:00
|
|
|
typeStr = Substring(iter, end);
|
2002-01-16 02:34:32 +03:00
|
|
|
} else {
|
2003-04-13 04:40:26 +04:00
|
|
|
typeStr = mimeType;
|
2001-02-07 02:39:46 +03:00
|
|
|
}
|
|
|
|
}
|
2003-04-22 02:45:28 +04:00
|
|
|
|
2017-08-04 07:40:52 +03:00
|
|
|
nsAutoString status;
|
2013-05-01 13:12:41 +04:00
|
|
|
if (mImageIsResized) {
|
2003-04-22 02:45:28 +04:00
|
|
|
nsAutoString ratioStr;
|
2013-05-01 13:12:41 +04:00
|
|
|
ratioStr.AppendInt(NSToCoordFloor(GetRatio() * 100));
|
2003-04-22 02:45:28 +04:00
|
|
|
|
2014-01-04 19:02:17 +04:00
|
|
|
const char16_t* formatString[1] = { ratioStr.get() };
|
2017-08-04 07:40:52 +03:00
|
|
|
mStringBundle->FormatStringFromName("ScaledImage", formatString, 1, status);
|
2003-04-22 02:45:28 +04:00
|
|
|
}
|
|
|
|
|
2017-07-06 15:00:35 +03:00
|
|
|
static const char* const formatNames[4] =
|
2003-04-13 04:40:26 +04:00
|
|
|
{
|
|
|
|
"ImageTitleWithNeitherDimensionsNorFile",
|
|
|
|
"ImageTitleWithoutDimensions",
|
2013-09-04 20:52:25 +04:00
|
|
|
"ImageTitleWithDimensions2",
|
|
|
|
"ImageTitleWithDimensions2AndFile",
|
2003-04-13 04:40:26 +04:00
|
|
|
};
|
|
|
|
|
2014-10-30 08:08:00 +03:00
|
|
|
MediaDocument::UpdateTitleAndCharset(typeStr, mChannel, formatNames,
|
2011-05-26 12:06:31 +04:00
|
|
|
mImageWidth, mImageHeight, status);
|
2003-01-18 13:17:58 +03:00
|
|
|
}
|
|
|
|
|
2008-02-07 22:58:05 +03:00
|
|
|
void
|
2011-05-26 12:06:31 +04:00
|
|
|
ImageDocument::ResetZoomLevel()
|
2008-02-07 22:58:05 +03:00
|
|
|
{
|
2013-11-15 11:12:43 +04:00
|
|
|
nsCOMPtr<nsIDocShell> docShell(mDocumentContainer);
|
2008-02-07 22:58:05 +03:00
|
|
|
if (docShell) {
|
2009-10-15 06:20:50 +04:00
|
|
|
if (nsContentUtils::IsChildOfSameType(this)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2008-02-07 22:58:05 +03:00
|
|
|
nsCOMPtr<nsIContentViewer> cv;
|
|
|
|
docShell->GetContentViewer(getter_AddRefs(cv));
|
2014-07-10 01:27:49 +04:00
|
|
|
if (cv) {
|
|
|
|
cv->SetFullZoom(mOriginalZoomLevel);
|
2008-02-07 22:58:05 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
float
|
2011-05-26 12:06:31 +04:00
|
|
|
ImageDocument::GetZoomLevel()
|
2008-02-07 22:58:05 +03:00
|
|
|
{
|
2009-09-01 17:15:33 +04:00
|
|
|
float zoomLevel = mOriginalZoomLevel;
|
2013-11-15 11:12:43 +04:00
|
|
|
nsCOMPtr<nsIDocShell> docShell(mDocumentContainer);
|
2008-02-07 22:58:05 +03:00
|
|
|
if (docShell) {
|
|
|
|
nsCOMPtr<nsIContentViewer> cv;
|
|
|
|
docShell->GetContentViewer(getter_AddRefs(cv));
|
2014-07-10 01:27:49 +04:00
|
|
|
if (cv) {
|
|
|
|
cv->GetFullZoom(&zoomLevel);
|
2008-02-07 22:58:05 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return zoomLevel;
|
|
|
|
}
|
2003-01-18 13:17:58 +03:00
|
|
|
|
2011-05-26 12:06:31 +04:00
|
|
|
} // namespace dom
|
|
|
|
} // namespace mozilla
|
|
|
|
|
2003-01-18 13:17:58 +03:00
|
|
|
nsresult
|
|
|
|
NS_NewImageDocument(nsIDocument** aResult)
|
|
|
|
{
|
2011-05-26 12:06:31 +04:00
|
|
|
mozilla::dom::ImageDocument* doc = new mozilla::dom::ImageDocument();
|
2005-04-28 21:16:19 +04:00
|
|
|
NS_ADDREF(doc);
|
2003-01-18 13:17:58 +03:00
|
|
|
|
2011-05-26 12:06:31 +04:00
|
|
|
nsresult rv = doc->Init();
|
2003-01-18 13:17:58 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
2005-04-28 21:16:19 +04:00
|
|
|
NS_RELEASE(doc);
|
2003-01-18 13:17:58 +03:00
|
|
|
}
|
|
|
|
|
2005-04-28 21:16:19 +04:00
|
|
|
*aResult = doc;
|
2003-01-18 13:17:58 +03:00
|
|
|
|
2005-04-28 21:16:19 +04:00
|
|
|
return rv;
|
1999-07-07 11:31:24 +04:00
|
|
|
}
|