blob: fb8e29584e882aa3ba318221a5610615ac229492 [file] [log] [blame]
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_RESOURCE_IMAGE_RESOURCE_CONTENT_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_RESOURCE_IMAGE_RESOURCE_CONTENT_H_
#include <memory>
#include "base/auto_reset.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/loader/resource/image_resource_observer.h"
#include "third_party/blink/renderer/platform/geometry/int_rect.h"
#include "third_party/blink/renderer/platform/graphics/image.h"
#include "third_party/blink/renderer/platform/graphics/image_observer.h"
#include "third_party/blink/renderer/platform/graphics/image_orientation.h"
#include "third_party/blink/renderer/platform/image-decoders/image_decoder.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_error.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_load_priority.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_status.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
#include "third_party/blink/renderer/platform/wtf/hash_counted_set.h"
#include "third_party/blink/renderer/platform/wtf/hash_map.h"
namespace blink {
class ExecutionContext;
class FetchParameters;
class ImageResourceInfo;
class ImageResourceObserver;
class ResourceError;
class ResourceFetcher;
class ResourceResponse;
class UseCounter;
// ImageResourceContent is a container that holds fetch result of
// an ImageResource in a decoded form.
// Classes that use the fetched images
// should hold onto this class and/or inherit ImageResourceObserver,
// instead of holding onto ImageResource or inheriting ResourceClient.
// https://docs.google.com/document/d/1O-fB83mrE0B_V8gzXNqHgmRLCvstTB4MMi3RnVLr8bE/edit?usp=sharing
// TODO(hiroshige): Make ImageResourceContent ResourceClient and remove the
// word 'observer' from ImageResource.
class CORE_EXPORT ImageResourceContent final
: public GarbageCollected<ImageResourceContent>,
public ImageObserver {
public:
// Used for loading.
// Returned content will be associated immediately later with ImageResource.
static ImageResourceContent* CreateNotStarted() {
return MakeGarbageCollected<ImageResourceContent>(nullptr);
}
// Creates ImageResourceContent from an already loaded image.
static ImageResourceContent* CreateLoaded(scoped_refptr<blink::Image>);
static ImageResourceContent* Fetch(FetchParameters&, ResourceFetcher*);
explicit ImageResourceContent(scoped_refptr<blink::Image> = nullptr);
// Returns the NullImage() if the image is not available yet.
blink::Image* GetImage() const;
bool HasImage() const { return image_.get(); }
// Returns true if enough of the image has been decoded to allow its size to
// be determined. If this returns true, so will HasImage().
bool IsSizeAvailable() const {
return size_available_ != Image::kSizeUnavailable;
}
// Returns the intrinsic width and height of the image, or 0x0 if no image
// exists. IsSizeAvailable() can be used to determine if the value returned is
// reliable. If the image is a BitmapImage, then this corresponds to the
// physical pixel dimensions of the image. If the image is an SVGImage, this
// does not quite return the intrinsic width/height, but rather a concrete
// object size resolved using a default object size of 300x150.
// TODO(fs): Make SVGImages return proper intrinsic width/height.
IntSize IntrinsicSize(
RespectImageOrientationEnum should_respect_image_orientation) const;
void AddObserver(ImageResourceObserver*);
void RemoveObserver(ImageResourceObserver*);
// The device pixel ratio we got from the server for this image, or 1.0.
float DevicePixelRatioHeaderValue() const;
bool HasDevicePixelRatioHeaderValue() const;
// Correct the image orientation preference for potentially cross-origin
// content.
RespectImageOrientationEnum ForceOrientationIfNecessary(
RespectImageOrientationEnum default_orientation) const;
void Trace(Visitor*) const override;
// Content status and deriving predicates.
// https://docs.google.com/document/d/1O-fB83mrE0B_V8gzXNqHgmRLCvstTB4MMi3RnVLr8bE/edit#heading=h.6cyqmir0f30h
// Normal transitions:
// kNotStarted -> kPending -> kCached|kLoadError|kDecodeError.
// Additional transitions in multipart images:
// kCached -> kLoadError|kDecodeError.
// Transitions due to revalidation:
// kCached -> kPending.
// Transitions due to reload:
// kCached|kLoadError|kDecodeError -> kPending.
//
// ImageResourceContent::GetContentStatus() can be different from
// ImageResource::GetStatus(). Use ImageResourceContent::GetContentStatus().
ResourceStatus GetContentStatus() const;
bool IsLoaded() const;
bool IsLoading() const;
bool ErrorOccurred() const;
bool LoadFailedOrCanceled() const;
// Redirecting methods to Resource.
const KURL& Url() const;
base::TimeTicks LoadResponseEnd() const;
bool IsAccessAllowed() const;
const ResourceResponse& GetResponse() const;
base::Optional<ResourceError> GetResourceError() const;
// DEPRECATED: ImageResourceContents consumers shouldn't need to worry about
// whether the underlying Resource is being revalidated.
bool IsCacheValidator() const;
// For FrameSerializer.
bool HasCacheControlNoStoreHeader() const;
void EmulateLoadStartedForInspector(ResourceFetcher*,
const KURL&,
const AtomicString& initiator_name);
void SetNotRefetchableDataFromDiskCache() {
is_refetchable_data_from_disk_cache_ = false;
}
// The following public methods should be called from ImageResource only.
// UpdateImage() is the single control point of image content modification
// from ImageResource that all image updates should call.
// We clear and/or update images in this single method
// (controlled by UpdateImageOption) rather than providing separate methods,
// in order to centralize state changes and
// not to expose the state in between to ImageResource.
enum UpdateImageOption {
// Updates the image (including placeholder and decode error handling
// and notifying observers) if needed.
kUpdateImage,
// Clears the image and then updates the image if needed.
kClearAndUpdateImage,
// Clears the image and always notifies observers (without updating).
kClearImageAndNotifyObservers,
};
enum class UpdateImageResult {
kNoDecodeError,
// Decode error occurred. Observers are not notified.
// Only occurs when UpdateImage or ClearAndUpdateImage is specified.
kShouldDecodeError,
};
WARN_UNUSED_RESULT UpdateImageResult UpdateImage(scoped_refptr<SharedBuffer>,
ResourceStatus,
UpdateImageOption,
bool all_data_received,
bool is_multipart);
void NotifyStartLoad();
void DestroyDecodedData();
void DoResetAnimation();
void SetImageResourceInfo(ImageResourceInfo*);
ResourcePriority PriorityFromObservers() const;
scoped_refptr<const SharedBuffer> ResourceBuffer() const;
bool ShouldUpdateImageImmediately() const;
bool HasObservers() const {
return !observers_.IsEmpty() || !finished_observers_.IsEmpty();
}
bool IsRefetchableDataFromDiskCache() const {
return is_refetchable_data_from_disk_cache_;
}
ImageDecoder::CompressionFormat GetCompressionFormat() const;
// Returns true if the image content is well-compressed (and not full of
// extraneous metadata). "well-compressed" is determined by comparing the
// image's compression ratio against a specific value that is defined by an
// unoptimized image feature policy on |context|.
bool IsAcceptableCompressionRatio(ExecutionContext& context);
void LoadDeferredImage(ResourceFetcher* fetcher);
// Returns whether the resource request has been tagged as an ad.
bool IsAdResource() const;
// Records the decoded image type in a UseCounter if the image is a
// BitmapImage. |use_counter| may be a null pointer.
void RecordDecodedImageType(UseCounter* use_counter);
private:
using CanDeferInvalidation = ImageResourceObserver::CanDeferInvalidation;
// ImageObserver
void DecodedSizeChangedTo(const blink::Image*, size_t new_size) override;
bool ShouldPauseAnimation(const blink::Image*) override;
void Changed(const blink::Image*) override;
void AsyncLoadCompleted(const blink::Image*) override;
scoped_refptr<Image> CreateImage(bool is_multipart);
void ClearImage();
enum NotifyFinishOption { kShouldNotifyFinish, kDoNotNotifyFinish };
void NotifyObservers(NotifyFinishOption, CanDeferInvalidation);
void HandleObserverFinished(ImageResourceObserver*);
void UpdateToLoadedContentStatus(ResourceStatus);
void UpdateImageAnimationPolicy();
class ProhibitAddRemoveObserverInScope : public base::AutoReset<bool> {
public:
ProhibitAddRemoveObserverInScope(const ImageResourceContent* content)
: AutoReset(&content->is_add_remove_observer_prohibited_, true) {}
};
ResourceStatus content_status_ = ResourceStatus::kNotStarted;
// Indicates if this resource's encoded image data can be purged and refetched
// from disk cache to save memory usage. See crbug/664437.
bool is_refetchable_data_from_disk_cache_;
mutable bool is_add_remove_observer_prohibited_ = false;
Image::SizeAvailability size_available_ = Image::kSizeUnavailable;
Member<ImageResourceInfo> info_;
float device_pixel_ratio_header_value_;
bool has_device_pixel_ratio_header_value_;
scoped_refptr<blink::Image> image_;
HashCountedSet<ImageResourceObserver*> observers_;
HashCountedSet<ImageResourceObserver*> finished_observers_;
#if DCHECK_IS_ON()
bool is_update_image_being_called_ = false;
#endif
};
} // namespace blink
#endif