/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* 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/. */
gfxContext::~gfxContext() { while (!mSavedStates.IsEmpty()) {
Restore();
} for (unsignedint c = 0; c < mAzureState.pushedClips.Length(); c++) {
mDT->PopClip();
}
}
void gfxContext::Restore() { #ifdef DEBUG // gfxContext::Restore is used to restore AzureState. We need to restore it // only if it was altered. The following APIs do change the content of // AzureState, a user should save the state before using them and restore it // after finishing painting: // 1. APIs to setup how to paint, such as SetColor()/SetAntialiasMode(). All // gfxContext SetXXXX public functions belong to this category, except // gfxContext::SetPath & gfxContext::SetMatrix. // 2. Clip functions, such as Clip() or PopClip(). You may call PopClip() // directly instead of using gfxContext::Save if the clip region is the // only thing that you altered in the target context. // 3. Function of setup transform matrix, such as Multiply() and // SetMatrix(). Using gfxContextMatrixAutoSaveRestore is more recommended // if transform data is the only thing that you are going to alter. // // You will hit the assertion message below if there is no above functions // been used between a pair of gfxContext::Save and gfxContext::Restore. // Considerate to remove that pair of Save/Restore if hitting that assertion. // // In the other hand, the following APIs do not alter the content of the // current AzureState, therefore, there is no need to save & restore // AzureState: // 1. constant member functions of gfxContext. // 2. Paint calls, such as Line()/Rectangle()/Fill(). Those APIs change the // content of drawing buffer, which is not part of AzureState. // 3. Path building APIs, such as SetPath()/MoveTo()/LineTo()/NewPath(). // Surprisingly, path information is not stored in AzureState either. // Save current AzureState before using these type of APIs does nothing but // make performance worse.
NS_ASSERTION(
mAzureState.mContentChanged || mAzureState.pushedClips.Length() > 0, "The context of the current AzureState is not altered after " "Save() been called. you may consider to remove this pair of " "gfxContext::Save/Restore."); #endif
for (unsignedint c = 0; c < mAzureState.pushedClips.Length(); c++) {
mDT->PopClip();
}
if (mPathIsRect) {
MOZ_ASSERT(!mTransformChanged);
if (op == CompositionOp::OP_SOURCE) { // Emulate cairo operator source which is bound by mask!
mDT->ClearRect(mRect);
mDT->FillRect(mRect, aPattern, DrawOptions(1.0f));
} else {
mDT->FillRect(mRect, aPattern, DrawOptions(1.0f, op, mAzureState.aaMode));
}
} else {
EnsurePath();
mDT->Fill(mPath, aPattern, DrawOptions(1.0f, op, mAzureState.aaMode));
}
}
// XXX snapToPixels is only valid when snapping for filled // rectangles and for even-width stroked rectangles. // For odd-width stroked rectangles, we need to offset x/y by // 0.5... void gfxContext::Rectangle(const gfxRect& rect, bool snapToPixels) {
Rect rec = ToRect(rect);
if (snapToPixels) {
gfxRect newRect(rect); if (UserToDevicePixelSnapped(newRect, SnapOption::IgnoreScale)) {
gfxMatrix mat = CurrentMatrixDouble(); if (mat.Invert()) { // We need the user space rect.
rec = ToRect(mat.TransformBounds(newRect));
} else {
rec = Rect();
}
}
}
void gfxContext::SnappedClip(const gfxRect& rect) {
Rect rec = ToRect(rect);
gfxRect newRect(rect); if (UserToDevicePixelSnapped(newRect, SnapOption::IgnoreScale)) {
gfxMatrix mat = CurrentMatrixDouble(); if (mat.Invert()) { // We need the user space rect.
rec = ToRect(mat.TransformBounds(newRect));
} else {
rec = Rect();
}
}
// Check that the rectangle is axis-aligned. For an axis-aligned rectangle, // two opposite corners define the entire rectangle. So check if // the axis-aligned rectangle with opposite corners p1 and p3 // define an axis-aligned rectangle whose other corners are p2 and p4. // We actually only need to check one of p2 and p4, since an affine // transform maps parallelograms to parallelograms. if (!(p2 == gfxPoint(p1.x, p3.y) || p2 == gfxPoint(p3.x, p1.y))) { returnfalse;
}
if (aOptions.contains(SnapOption::PrioritizeSize)) { // Snap the dimensions of the rect, to minimize distortion; only after that // will we snap its position. In particular, this guarantees that a square // remains square after snapping, which may not be the case if each edge is // independently snapped to device pixels.
// Use the same rounding approach as gfx::BasePoint::Round.
rect.SizeTo(std::floor(rect.width + 0.5), std::floor(rect.height + 0.5));
// Find the top-left corner based on the original center and the snapped // size, then snap this new corner to the grid.
gfxPoint center = (p1 + p3) / 2;
gfxPoint topLeft = center - gfxPoint(rect.width / 2.0, rect.height / 2.0);
topLeft.Round();
rect.MoveTo(topLeft);
} else {
p1.Round();
p3.Round();
rect.MoveTo(gfxPoint(std::min(p1.x, p3.x), std::min(p1.y, p3.y)));
rect.SizeTo(gfxSize(std::max(p1.x, p3.x) - rect.X(),
std::max(p1.y, p3.y) - rect.Y()));
}
if (!mPathBuilder) {
mPathBuilder = mDT->CreatePathBuilder(FillRule::FILL_WINDING);
if (mPathIsRect) {
mPathBuilder->MoveTo(mRect.TopLeft());
mPathBuilder->LineTo(mRect.TopRight());
mPathBuilder->LineTo(mRect.BottomRight());
mPathBuilder->LineTo(mRect.BottomLeft());
mPathBuilder->Close();
}
}
if (mTransformChanged) { // This could be an else if since this should never happen when // mPathBuilder is nullptr and mPath is nullptr. But this way we can // assert if all the state is as expected.
MOZ_ASSERT(oldPath);
MOZ_ASSERT(!mPathIsRect);
/* SVG font code can change the transform after having set the pattern on the * context. When the pattern is set it is in user space, if the transform is * changed after doing so the pattern needs to be converted back into userspace. * We just store the old pattern transform here so that we only do the work * needed here if the pattern is actually used. * We need to avoid doing this when this ChangeTransform comes from a restore, * since the current pattern and the current transform are both part of the * state we know the new mAzureState's values are valid. But if we assume * a change they might become invalid since patternTransformChanged is part of * the state and might be false for the restored AzureState.
*/ void gfxContext::ChangeTransform(const Matrix& aNewMatrix, bool aUpdatePatternTransform) { if (aUpdatePatternTransform && (mAzureState.pattern) &&
!mAzureState.patternTransformChanged) {
mAzureState.patternTransform = GetDTTransform();
mAzureState.patternTransformChanged = true;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.