mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
247 lines
6.5 KiB
C++
247 lines
6.5 KiB
C++
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
* 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/. */
|
|
|
|
#include "gfxTypes.h"
|
|
#include "gfxPattern.h"
|
|
#include "gfxASurface.h"
|
|
#include "gfxPlatform.h"
|
|
#include "gfx2DGlue.h"
|
|
#include "gfxGradientCache.h"
|
|
#include "mozilla/gfx/2D.h"
|
|
|
|
#include "cairo.h"
|
|
|
|
#include <vector>
|
|
|
|
using namespace mozilla::gfx;
|
|
|
|
gfxPattern::gfxPattern(const gfxRGBA& aColor)
|
|
: mExtend(EXTEND_NONE)
|
|
{
|
|
mGfxPattern =
|
|
new (mColorPattern.addr()) ColorPattern(Color(aColor.r, aColor.g, aColor.b, aColor.a));
|
|
}
|
|
|
|
// linear
|
|
gfxPattern::gfxPattern(gfxFloat x0, gfxFloat y0, gfxFloat x1, gfxFloat y1)
|
|
: mExtend(EXTEND_NONE)
|
|
{
|
|
mGfxPattern =
|
|
new (mLinearGradientPattern.addr()) LinearGradientPattern(Point(x0, y0),
|
|
Point(x1, y1),
|
|
nullptr);
|
|
}
|
|
|
|
// radial
|
|
gfxPattern::gfxPattern(gfxFloat cx0, gfxFloat cy0, gfxFloat radius0,
|
|
gfxFloat cx1, gfxFloat cy1, gfxFloat radius1)
|
|
: mExtend(EXTEND_NONE)
|
|
{
|
|
mGfxPattern =
|
|
new (mRadialGradientPattern.addr()) RadialGradientPattern(Point(cx0, cy0),
|
|
Point(cx1, cy1),
|
|
radius0, radius1,
|
|
nullptr);
|
|
}
|
|
|
|
// Azure
|
|
gfxPattern::gfxPattern(SourceSurface *aSurface, const Matrix &aPatternToUserSpace)
|
|
: mPatternToUserSpace(aPatternToUserSpace)
|
|
, mExtend(EXTEND_NONE)
|
|
{
|
|
mGfxPattern = new (mSurfacePattern.addr())
|
|
SurfacePattern(aSurface, ToExtendMode(mExtend), Matrix(), // matrix is overridden in GetPattern()
|
|
mozilla::gfx::Filter::GOOD);
|
|
}
|
|
|
|
gfxPattern::~gfxPattern()
|
|
{
|
|
if (mGfxPattern) {
|
|
mGfxPattern->~Pattern();
|
|
}
|
|
}
|
|
|
|
void
|
|
gfxPattern::AddColorStop(gfxFloat offset, const gfxRGBA& c)
|
|
{
|
|
if (mGfxPattern->GetType() != PatternType::LINEAR_GRADIENT &&
|
|
mGfxPattern->GetType() != PatternType::RADIAL_GRADIENT) {
|
|
return;
|
|
}
|
|
|
|
mStops = nullptr;
|
|
gfxRGBA color = c;
|
|
if (gfxPlatform::GetCMSMode() == eCMSMode_All) {
|
|
qcms_transform *transform = gfxPlatform::GetCMSRGBTransform();
|
|
if (transform) {
|
|
gfxPlatform::TransformPixel(color, color, transform);
|
|
}
|
|
}
|
|
|
|
GradientStop stop;
|
|
stop.offset = offset;
|
|
stop.color = ToColor(color);
|
|
mStopsList.AppendElement(stop);
|
|
}
|
|
|
|
void
|
|
gfxPattern::SetColorStops(GradientStops* aStops)
|
|
{
|
|
mStops = aStops;
|
|
}
|
|
|
|
void
|
|
gfxPattern::CacheColorStops(DrawTarget *aDT)
|
|
{
|
|
mStops = gfxGradientCache::GetOrCreateGradientStops(aDT, mStopsList,
|
|
ToExtendMode(mExtend));
|
|
}
|
|
|
|
void
|
|
gfxPattern::SetMatrix(const gfxMatrix& aPatternToUserSpace)
|
|
{
|
|
mPatternToUserSpace = ToMatrix(aPatternToUserSpace);
|
|
// Cairo-pattern matrices specify the conversion from DrawTarget to pattern
|
|
// space. Azure pattern matrices specify the conversion from pattern to
|
|
// DrawTarget space.
|
|
mPatternToUserSpace.Invert();
|
|
}
|
|
|
|
gfxMatrix
|
|
gfxPattern::GetMatrix() const
|
|
{
|
|
// invert at the higher precision of gfxMatrix
|
|
// cause we need to convert at some point anyways
|
|
gfxMatrix mat = ThebesMatrix(mPatternToUserSpace);
|
|
mat.Invert();
|
|
return mat;
|
|
}
|
|
|
|
gfxMatrix
|
|
gfxPattern::GetInverseMatrix() const
|
|
{
|
|
return ThebesMatrix(mPatternToUserSpace);
|
|
}
|
|
|
|
Pattern*
|
|
gfxPattern::GetPattern(DrawTarget *aTarget,
|
|
Matrix *aOriginalUserToDevice)
|
|
{
|
|
Matrix patternToUser = mPatternToUserSpace;
|
|
|
|
if (aOriginalUserToDevice &&
|
|
*aOriginalUserToDevice != aTarget->GetTransform()) {
|
|
// mPatternToUserSpace maps from pattern space to the original user space,
|
|
// but aTarget now has a transform to a different user space. In order for
|
|
// the Pattern* that we return to be usable in aTarget's new user space we
|
|
// need the Pattern's mMatrix to be the transform from pattern space to
|
|
// aTarget's -new- user space. That transform is equivalent to the
|
|
// transform from pattern space to original user space (patternToUser),
|
|
// multiplied by the transform from original user space to device space,
|
|
// multiplied by the transform from device space to current user space.
|
|
|
|
Matrix deviceToCurrentUser = aTarget->GetTransform();
|
|
deviceToCurrentUser.Invert();
|
|
|
|
patternToUser = patternToUser * *aOriginalUserToDevice * deviceToCurrentUser;
|
|
}
|
|
patternToUser.NudgeToIntegers();
|
|
|
|
if (!mStops &&
|
|
!mStopsList.IsEmpty()) {
|
|
mStops = aTarget->CreateGradientStops(mStopsList.Elements(),
|
|
mStopsList.Length(),
|
|
ToExtendMode(mExtend));
|
|
}
|
|
|
|
switch (mGfxPattern->GetType()) {
|
|
case PatternType::SURFACE:
|
|
mSurfacePattern.addr()->mMatrix = patternToUser;
|
|
mSurfacePattern.addr()->mExtendMode = ToExtendMode(mExtend);
|
|
break;
|
|
case PatternType::LINEAR_GRADIENT:
|
|
mLinearGradientPattern.addr()->mMatrix = patternToUser;
|
|
mLinearGradientPattern.addr()->mStops = mStops;
|
|
break;
|
|
case PatternType::RADIAL_GRADIENT:
|
|
mRadialGradientPattern.addr()->mMatrix = patternToUser;
|
|
mRadialGradientPattern.addr()->mStops = mStops;
|
|
break;
|
|
default:
|
|
/* Reassure the compiler we are handling all the enum values. */
|
|
break;
|
|
}
|
|
|
|
return mGfxPattern;
|
|
}
|
|
|
|
void
|
|
gfxPattern::SetExtend(GraphicsExtend extend)
|
|
{
|
|
mExtend = extend;
|
|
mStops = nullptr;
|
|
}
|
|
|
|
bool
|
|
gfxPattern::IsOpaque()
|
|
{
|
|
if (mGfxPattern->GetType() != PatternType::SURFACE) {
|
|
return false;
|
|
}
|
|
|
|
if (mSurfacePattern.addr()->mSurface->GetFormat() == SurfaceFormat::B8G8R8X8) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
gfxPattern::GraphicsExtend
|
|
gfxPattern::Extend() const
|
|
{
|
|
return mExtend;
|
|
}
|
|
|
|
void
|
|
gfxPattern::SetFilter(GraphicsFilter filter)
|
|
{
|
|
if (mGfxPattern->GetType() != PatternType::SURFACE) {
|
|
return;
|
|
}
|
|
|
|
mSurfacePattern.addr()->mFilter = ToFilter(filter);
|
|
}
|
|
|
|
GraphicsFilter
|
|
gfxPattern::Filter() const
|
|
{
|
|
if (mGfxPattern->GetType() != PatternType::SURFACE) {
|
|
return GraphicsFilter::FILTER_GOOD;
|
|
}
|
|
return ThebesFilter(mSurfacePattern.addr()->mFilter);
|
|
}
|
|
|
|
bool
|
|
gfxPattern::GetSolidColor(gfxRGBA& aColor)
|
|
{
|
|
if (mGfxPattern->GetType() == PatternType::COLOR) {
|
|
aColor = ThebesColor(mColorPattern.addr()->mColor);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
gfxPattern::GraphicsPatternType
|
|
gfxPattern::GetType() const
|
|
{
|
|
return ThebesPatternType(mGfxPattern->GetType());
|
|
}
|
|
|
|
int
|
|
gfxPattern::CairoStatus()
|
|
{
|
|
return CAIRO_STATUS_SUCCESS;
|
|
}
|