blob: 47fe67ce9a539d720de115549c84921fa434f04a [file] [log] [blame]
/*
* Copyright (C) 2000 Lars Knoll (knoll@kde.org)
* (C) 2000 Antti Koivisto (koivisto@kde.org)
* (C) 2000 Dirk Mueller (mueller@kde.org)
* Copyright (C) 2003, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
* Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.com)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#ifndef FillLayer_h
#define FillLayer_h
#include "base/memory/scoped_refptr.h"
#include "core/CoreExport.h"
#include "core/style/ComputedStyleConstants.h"
#include "core/style/StyleImage.h"
#include "platform/Length.h"
#include "platform/LengthSize.h"
#include "platform/graphics/GraphicsTypes.h"
#include "platform/wtf/Allocator.h"
namespace blink {
struct FillSize {
DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
FillSize() : type(EFillSizeType::kSizeLength) {}
FillSize(EFillSizeType t, const LengthSize& l) : type(t), size(l) {}
bool operator==(const FillSize& o) const {
return type == o.type && size == o.size;
}
bool operator!=(const FillSize& o) const { return !(*this == o); }
EFillSizeType type;
LengthSize size;
};
// FIXME(Oilpan): Move FillLayer to Oilpan's heap.
class CORE_EXPORT FillLayer {
USING_FAST_MALLOC(FillLayer);
public:
FillLayer(EFillLayerType, bool use_initial_values = false);
~FillLayer();
StyleImage* GetImage() const { return image_.Get(); }
const Length& PositionX() const { return position_x_; }
const Length& PositionY() const { return position_y_; }
BackgroundEdgeOrigin BackgroundXOrigin() const {
return static_cast<BackgroundEdgeOrigin>(background_x_origin_);
}
BackgroundEdgeOrigin BackgroundYOrigin() const {
return static_cast<BackgroundEdgeOrigin>(background_y_origin_);
}
EFillAttachment Attachment() const {
return static_cast<EFillAttachment>(attachment_);
}
EFillBox Clip() const { return static_cast<EFillBox>(clip_); }
EFillBox Origin() const { return static_cast<EFillBox>(origin_); }
EFillRepeat RepeatX() const { return static_cast<EFillRepeat>(repeat_x_); }
EFillRepeat RepeatY() const { return static_cast<EFillRepeat>(repeat_y_); }
CompositeOperator Composite() const {
return static_cast<CompositeOperator>(composite_);
}
WebBlendMode BlendMode() const {
return static_cast<WebBlendMode>(blend_mode_);
}
const LengthSize& SizeLength() const { return size_length_; }
EFillSizeType SizeType() const {
return static_cast<EFillSizeType>(size_type_);
}
FillSize Size() const {
return FillSize(static_cast<EFillSizeType>(size_type_), size_length_);
}
EMaskSourceType MaskSourceType() const {
return static_cast<EMaskSourceType>(mask_source_type_);
}
const FillLayer* Next() const { return next_; }
FillLayer* Next() { return next_; }
FillLayer* EnsureNext() {
if (!next_)
next_ = new FillLayer(GetType());
return next_;
}
bool IsImageSet() const { return image_set_; }
bool IsPositionXSet() const { return pos_x_set_; }
bool IsPositionYSet() const { return pos_y_set_; }
bool IsBackgroundXOriginSet() const { return background_x_origin_set_; }
bool IsBackgroundYOriginSet() const { return background_y_origin_set_; }
bool IsAttachmentSet() const { return attachment_set_; }
bool IsClipSet() const { return clip_set_; }
bool IsOriginSet() const { return origin_set_; }
bool IsRepeatXSet() const { return repeat_x_set_; }
bool IsRepeatYSet() const { return repeat_y_set_; }
bool IsCompositeSet() const { return composite_set_; }
bool IsBlendModeSet() const { return blend_mode_set_; }
bool IsSizeSet() const {
return size_type_ != static_cast<unsigned>(EFillSizeType::kSizeNone);
}
bool IsMaskSourceTypeSet() const { return mask_source_type_set_; }
void SetImage(StyleImage* i) {
image_ = i;
image_set_ = true;
}
void SetPositionX(const Length& position) {
position_x_ = position;
pos_x_set_ = true;
background_x_origin_set_ = false;
background_x_origin_ = static_cast<unsigned>(BackgroundEdgeOrigin::kLeft);
}
void SetPositionY(const Length& position) {
position_y_ = position;
pos_y_set_ = true;
background_y_origin_set_ = false;
background_y_origin_ = static_cast<unsigned>(BackgroundEdgeOrigin::kTop);
}
void SetBackgroundXOrigin(BackgroundEdgeOrigin origin) {
background_x_origin_ = static_cast<unsigned>(origin);
background_x_origin_set_ = true;
}
void SetBackgroundYOrigin(BackgroundEdgeOrigin origin) {
background_y_origin_ = static_cast<unsigned>(origin);
background_y_origin_set_ = true;
}
void SetAttachment(EFillAttachment attachment) {
DCHECK(!cached_properties_computed_);
attachment_ = static_cast<unsigned>(attachment);
attachment_set_ = true;
}
void SetClip(EFillBox b) {
DCHECK(!cached_properties_computed_);
clip_ = static_cast<unsigned>(b);
clip_set_ = true;
}
void SetOrigin(EFillBox b) {
DCHECK(!cached_properties_computed_);
origin_ = static_cast<unsigned>(b);
origin_set_ = true;
}
void SetRepeatX(EFillRepeat r) {
repeat_x_ = static_cast<unsigned>(r);
repeat_x_set_ = true;
}
void SetRepeatY(EFillRepeat r) {
repeat_y_ = static_cast<unsigned>(r);
repeat_y_set_ = true;
}
void SetComposite(CompositeOperator c) {
composite_ = c;
composite_set_ = true;
}
void SetBlendMode(WebBlendMode b) {
blend_mode_ = static_cast<unsigned>(b);
blend_mode_set_ = true;
}
void SetSizeType(EFillSizeType b) { size_type_ = static_cast<unsigned>(b); }
void SetSizeLength(const LengthSize& length) { size_length_ = length; }
void SetSize(const FillSize& f) {
size_type_ = static_cast<unsigned>(f.type);
size_length_ = f.size;
}
void SetMaskSourceType(EMaskSourceType m) {
mask_source_type_ = static_cast<unsigned>(m);
mask_source_type_set_ = true;
}
void ClearImage() {
image_.Clear();
image_set_ = false;
}
void ClearPositionX() {
pos_x_set_ = false;
background_x_origin_set_ = false;
}
void ClearPositionY() {
pos_y_set_ = false;
background_y_origin_set_ = false;
}
void ClearAttachment() { attachment_set_ = false; }
void ClearClip() { clip_set_ = false; }
void ClearOrigin() { origin_set_ = false; }
void ClearRepeatX() { repeat_x_set_ = false; }
void ClearRepeatY() { repeat_y_set_ = false; }
void ClearComposite() { composite_set_ = false; }
void ClearBlendMode() { blend_mode_set_ = false; }
void ClearSize() {
size_type_ = static_cast<unsigned>(EFillSizeType::kSizeNone);
}
void ClearMaskSourceType() { mask_source_type_set_ = false; }
FillLayer& operator=(const FillLayer&);
FillLayer(const FillLayer&);
bool operator==(const FillLayer&) const;
bool operator!=(const FillLayer& o) const { return !(*this == o); }
bool VisuallyEqual(const FillLayer&) const;
bool ContainsImage(StyleImage*) const;
bool ImagesAreLoaded() const;
bool HasImage() const {
if (image_)
return true;
return next_ ? next_->HasImage() : false;
}
bool HasFixedImage() const {
if (image_ &&
static_cast<EFillAttachment>(attachment_) == EFillAttachment::kFixed)
return true;
return next_ ? next_->HasFixedImage() : false;
}
bool ImageOccludesNextLayers(const Document&, const ComputedStyle&) const;
bool HasRepeatXY() const;
bool ClipOccludesNextLayers() const;
EFillLayerType GetType() const { return static_cast<EFillLayerType>(type_); }
void FillUnsetProperties();
void CullEmptyLayers();
static bool ImagesIdentical(const FillLayer*, const FillLayer*);
EFillBox ThisOrNextLayersClipMax() const {
ComputeCachedPropertiesIfNeeded();
return static_cast<EFillBox>(this_or_next_layers_clip_max_);
}
bool ThisOrNextLayersUseContentBox() const {
ComputeCachedPropertiesIfNeeded();
return this_or_next_layers_use_content_box_;
}
bool ThisOrNextLayersHaveLocalAttachment() const {
ComputeCachedPropertiesIfNeeded();
return this_or_next_layers_have_local_attachment_;
}
void ComputeCachedPropertiesIfNeeded() const;
static EFillAttachment InitialFillAttachment(EFillLayerType) {
return EFillAttachment::kScroll;
}
static EFillBox InitialFillClip(EFillLayerType) { return EFillBox::kBorder; }
static EFillBox InitialFillOrigin(EFillLayerType type) {
return type == EFillLayerType::kBackground ? EFillBox::kPadding
: EFillBox::kBorder;
}
static EFillRepeat InitialFillRepeatX(EFillLayerType) {
return EFillRepeat::kRepeatFill;
}
static EFillRepeat InitialFillRepeatY(EFillLayerType) {
return EFillRepeat::kRepeatFill;
}
static CompositeOperator InitialFillComposite(EFillLayerType) {
return kCompositeSourceOver;
}
static WebBlendMode InitialFillBlendMode(EFillLayerType) {
return WebBlendMode::kNormal;
}
static EFillSizeType InitialFillSizeType(EFillLayerType) {
return EFillSizeType::kSizeLength;
}
static LengthSize InitialFillSizeLength(EFillLayerType) {
return LengthSize();
}
static FillSize InitialFillSize(EFillLayerType type) {
return FillSize(InitialFillSizeType(type), InitialFillSizeLength(type));
}
static Length InitialFillPositionX(EFillLayerType) {
return Length(0.0, kPercent);
}
static Length InitialFillPositionY(EFillLayerType) {
return Length(0.0, kPercent);
}
static StyleImage* InitialFillImage(EFillLayerType) { return nullptr; }
static EMaskSourceType InitialFillMaskSourceType(EFillLayerType) {
return EMaskSourceType::kAlpha;
}
private:
friend class ComputedStyle;
FillLayer() = default;
bool ImageIsOpaque(const Document&, const ComputedStyle&) const;
bool ImageTilesLayer() const;
bool LayerPropertiesEqual(const FillLayer&) const;
FillLayer* next_;
Persistent<StyleImage> image_;
Length position_x_;
Length position_y_;
LengthSize size_length_;
unsigned attachment_ : 2; // EFillAttachment
unsigned clip_ : 2; // EFillBox
unsigned origin_ : 2; // EFillBox
unsigned repeat_x_ : 3; // EFillRepeat
unsigned repeat_y_ : 3; // EFillRepeat
unsigned composite_ : 4; // CompositeOperator
unsigned size_type_ : 2; // EFillSizeType
unsigned blend_mode_ : 5; // WebBlendMode
unsigned mask_source_type_ : 1; // EMaskSourceType
unsigned background_x_origin_ : 2; // BackgroundEdgeOrigin
unsigned background_y_origin_ : 2; // BackgroundEdgeOrigin
unsigned image_set_ : 1;
unsigned attachment_set_ : 1;
unsigned clip_set_ : 1;
unsigned origin_set_ : 1;
unsigned repeat_x_set_ : 1;
unsigned repeat_y_set_ : 1;
unsigned pos_x_set_ : 1;
unsigned pos_y_set_ : 1;
unsigned background_x_origin_set_ : 1;
unsigned background_y_origin_set_ : 1;
unsigned composite_set_ : 1;
unsigned blend_mode_set_ : 1;
unsigned mask_source_type_set_ : 1;
unsigned type_ : 1; // EFillLayerType
// EFillBox, maximum m_clip value from this to bottom layer
mutable unsigned this_or_next_layers_clip_max_ : 2;
// True if any of this or subsequent layers has content-box clip or origin.
mutable unsigned this_or_next_layers_use_content_box_ : 1;
// True if any of this or subsequent layers has local attachment.
mutable unsigned this_or_next_layers_have_local_attachment_ : 1;
// Set once any of the above is accessed. The layers will be frozen
// thereafter.
mutable unsigned cached_properties_computed_ : 1;
};
} // namespace blink
#endif // FillLayer_h