blob: c39dec334412dd95060a5a16f42ff9482be3bd4e [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-2017 Apple Inc. All rights reserved.
*
* 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.
*
*/
#pragma once
#include "LengthBox.h"
#include "StyleImage.h"
#include <wtf/DataRef.h>
#include <wtf/Vector.h>
namespace WebCore {
class LayoutSize;
class LayoutRect;
class RenderStyle;
enum class NinePieceImageRule : uint8_t {
Stretch,
Round,
Space,
Repeat,
};
// Used for array indexing, so not an enum class.
enum ImagePiece {
MinPiece = 0,
TopLeftPiece = MinPiece,
LeftPiece,
BottomLeftPiece,
TopRightPiece,
RightPiece,
BottomRightPiece,
TopPiece,
BottomPiece,
MiddlePiece,
MaxPiece
};
inline ImagePiece& operator++(ImagePiece& piece)
{
piece = static_cast<ImagePiece>(static_cast<int>(piece) + 1);
return piece;
}
inline bool isCornerPiece(ImagePiece piece)
{
return piece == TopLeftPiece || piece == TopRightPiece || piece == BottomLeftPiece || piece == BottomRightPiece;
}
inline bool isMiddlePiece(ImagePiece piece)
{
return piece == MiddlePiece;
}
inline bool isHorizontalPiece(ImagePiece piece)
{
return piece == TopPiece || piece == BottomPiece || piece == MiddlePiece;
}
inline bool isVerticalPiece(ImagePiece piece)
{
return piece == LeftPiece || piece == RightPiece || piece == MiddlePiece;
}
inline std::optional<BoxSide> imagePieceHorizontalSide(ImagePiece piece)
{
if (piece == TopLeftPiece || piece == TopPiece || piece == TopRightPiece)
return BoxSide::Top;
if (piece == BottomLeftPiece || piece == BottomPiece || piece == BottomRightPiece)
return BoxSide::Bottom;
return std::nullopt;
}
inline std::optional<BoxSide> imagePieceVerticalSide(ImagePiece piece)
{
if (piece == TopLeftPiece || piece == LeftPiece || piece == BottomLeftPiece)
return BoxSide::Left;
if (piece == TopRightPiece || piece == RightPiece || piece == BottomRightPiece)
return BoxSide::Right;
return std::nullopt;
}
class NinePieceImage {
public:
enum class Type {
Normal,
Mask
};
NinePieceImage(Type = Type::Normal);
NinePieceImage(RefPtr<StyleImage>&&, LengthBox imageSlices, bool fill, LengthBox borderSlices, LengthBox outset, NinePieceImageRule horizontalRule, NinePieceImageRule verticalRule);
bool operator==(const NinePieceImage& other) const { return m_data == other.m_data; }
bool operator!=(const NinePieceImage& other) const { return m_data != other.m_data; }
bool hasImage() const { return m_data->image; }
StyleImage* image() const { return m_data->image.get(); }
void setImage(RefPtr<StyleImage>&& image) { m_data.access().image = WTFMove(image); }
const LengthBox& imageSlices() const { return m_data->imageSlices; }
void setImageSlices(LengthBox slices) { m_data.access().imageSlices = WTFMove(slices); }
bool fill() const { return m_data->fill; }
void setFill(bool fill) { m_data.access().fill = fill; }
const LengthBox& borderSlices() const { return m_data->borderSlices; }
void setBorderSlices(LengthBox slices) { m_data.access().borderSlices = WTFMove(slices); }
const LengthBox& outset() const { return m_data->outset; }
void setOutset(LengthBox outset) { m_data.access().outset = WTFMove(outset); }
NinePieceImageRule horizontalRule() const { return m_data->horizontalRule; }
void setHorizontalRule(NinePieceImageRule rule) { m_data.access().horizontalRule = rule; }
NinePieceImageRule verticalRule() const { return m_data->verticalRule; }
void setVerticalRule(NinePieceImageRule rule) { m_data.access().verticalRule = rule; }
void copyImageSlicesFrom(const NinePieceImage& other)
{
m_data.access().imageSlices = other.m_data->imageSlices;
m_data.access().fill = other.m_data->fill;
}
void copyBorderSlicesFrom(const NinePieceImage& other)
{
m_data.access().borderSlices = other.m_data->borderSlices;
}
void copyOutsetFrom(const NinePieceImage& other)
{
m_data.access().outset = other.m_data->outset;
}
void copyRepeatFrom(const NinePieceImage& other)
{
m_data.access().horizontalRule = other.m_data->horizontalRule;
m_data.access().verticalRule = other.m_data->verticalRule;
}
static LayoutUnit computeOutset(const Length& outset, LayoutUnit borderWidth)
{
if (outset.isRelative())
return LayoutUnit(outset.value() * borderWidth);
return LayoutUnit(outset.value());
}
static LayoutUnit computeSlice(Length, LayoutUnit width, LayoutUnit slice, LayoutUnit extent);
static LayoutBoxExtent computeSlices(const LayoutSize&, const LengthBox& lengths, int scaleFactor);
static LayoutBoxExtent computeSlices(const LayoutSize&, const LengthBox& lengths, const FloatBoxExtent& widths, const LayoutBoxExtent& slices);
static bool isEmptyPieceRect(ImagePiece, const LayoutBoxExtent& slices);
static bool isEmptyPieceRect(ImagePiece, const Vector<FloatRect>& destinationRects, const Vector<FloatRect>& sourceRects);
static Vector<FloatRect> computeNineRects(const FloatRect& outer, const LayoutBoxExtent& slices, float deviceScaleFactor);
static void scaleSlicesIfNeeded(const LayoutSize&, LayoutBoxExtent& slices, float deviceScaleFactor);
static FloatSize computeSideTileScale(ImagePiece, const Vector<FloatRect>& destinationRects, const Vector<FloatRect>& sourceRects);
static FloatSize computeMiddleTileScale(const Vector<FloatSize>& scales, const Vector<FloatRect>& destinationRects, const Vector<FloatRect>& sourceRects, NinePieceImageRule hRule, NinePieceImageRule vRule);
static Vector<FloatSize> computeTileScales(const Vector<FloatRect>& destinationRects, const Vector<FloatRect>& sourceRects, NinePieceImageRule hRule, NinePieceImageRule vRule);
void paint(GraphicsContext&, RenderElement*, const RenderStyle&, const LayoutRect& destination, const LayoutSize& source, float deviceScaleFactor, CompositeOperator) const;
private:
struct Data : RefCounted<Data> {
static Ref<Data> create();
static Ref<Data> create(RefPtr<StyleImage>&&, LengthBox imageSlices, bool fill, LengthBox borderSlices, LengthBox outset, NinePieceImageRule horizontalRule, NinePieceImageRule verticalRule);
Ref<Data> copy() const;
bool operator==(const Data&) const;
bool operator!=(const Data& other) const { return !(*this == other); }
bool fill { false };
NinePieceImageRule horizontalRule { NinePieceImageRule::Stretch };
NinePieceImageRule verticalRule { NinePieceImageRule::Stretch };
RefPtr<StyleImage> image;
LengthBox imageSlices { { 100, LengthType::Percent }, { 100, LengthType::Percent }, { 100, LengthType::Percent }, { 100, LengthType::Percent } };
LengthBox borderSlices { { 1, LengthType::Relative }, { 1, LengthType::Relative }, { 1, LengthType::Relative }, { 1, LengthType::Relative } };
LengthBox outset { LengthType::Relative };
private:
Data();
Data(RefPtr<StyleImage>&&, LengthBox imageSlices, bool fill, LengthBox borderSlices, LengthBox outset, NinePieceImageRule horizontalRule, NinePieceImageRule verticalRule);
Data(const Data&);
};
static DataRef<Data>& defaultData();
static DataRef<Data>& defaultMaskData();
DataRef<Data> m_data;
};
WTF::TextStream& operator<<(WTF::TextStream&, const NinePieceImage&);
WTF::TextStream& operator<<(WTF::TextStream&, NinePieceImageRule);
} // namespace WebCore