bug 446660: tracking bug for build and release of Firefox 3.1a1 - version bumps for nightly builds (3.1a1 -> 3.1a2pre) r=ted

This commit is contained in:
Ben Hearsum 2008-07-23 09:13:22 -04:00
Родитель d0c2632dcd 316a23c38b
Коммит 1a37b01f3c
182 изменённых файлов: 17510 добавлений и 4270 удалений

Просмотреть файл

@ -191,8 +191,7 @@ NS_IMETHODIMP nsAccessNode::Init()
// so that nsDocAccessible::RefreshNodes() can find the anonymous subtree to release when
// the root node goes away
nsCOMPtr<nsIContent> content = do_QueryInterface(mDOMNode);
if (content && (content->IsNativeAnonymous() ||
content->GetBindingParent())) {
if (content && content->IsInAnonymousSubtree()) {
// Specific examples of where this is used: <input type="file"> and <xul:findbar>
nsCOMPtr<nsIAccessible> parentAccessible;
docAccessible->GetAccessibleInParentChain(mDOMNode, PR_TRUE, getter_AddRefs(parentAccessible));

Просмотреть файл

@ -792,11 +792,9 @@ nsAccUtils::FindNeighbourPointingToNode(nsIContent *aForNode,
nsIAtom *aTagName,
PRUint32 aAncestorLevelsToSearch)
{
nsCOMPtr<nsIContent> binding;
nsAutoString controlID;
if (!nsAccUtils::GetID(aForNode, controlID)) {
binding = aForNode->GetBindingParent();
if (binding == aForNode)
if (aForNode->IsInAnonymousSubtree())
return nsnull;
aForNode->GetAttr(kNameSpaceID_None, nsAccessibilityAtoms::anonid, controlID);
@ -805,6 +803,7 @@ nsAccUtils::FindNeighbourPointingToNode(nsIContent *aForNode,
}
// Look for label in subtrees of nearby ancestors
nsCOMPtr<nsIContent> binding(aForNode->GetBindingParent());
PRUint32 count = 0;
nsIContent *labelContent = nsnull;
nsIContent *prevSearched = nsnull;

Просмотреть файл

@ -1760,9 +1760,8 @@ void nsDocAccessible::RefreshNodes(nsIDOMNode *aStartNode)
getter_AddRefs(childAccessNode));
childAccessNode->GetDOMNode(getter_AddRefs(possibleAnonNode));
nsCOMPtr<nsIContent> iterContent = do_QueryInterface(possibleAnonNode);
if (iterContent && (iterContent->IsNativeAnonymous() ||
iterContent->GetBindingParent())) {
// GetBindingParent() check is a perf win -- make sure we don't
if (iterContent && iterContent->IsInAnonymousSubtree()) {
// IsInAnonymousSubtree() check is a perf win -- make sure we don't
// shut down the same subtree twice since we'll reach non-anon content via
// DOM traversal later in this method
RefreshNodes(possibleAnonNode);

Просмотреть файл

@ -640,7 +640,9 @@ nsresult nsHyperTextAccessible::DOMPointToHypertextOffset(nsIDOMNode* aNode, PRI
if (findContent->IsNodeOfType(nsINode::eHTML) &&
findContent->NodeInfo()->Equals(nsAccessibilityAtoms::br)) {
nsIContent *parent = findContent->GetParent();
if (parent && parent->IsNativeAnonymous() && parent->GetChildCount() == 1) {
if (parent &&
parent->IsRootOfNativeAnonymousSubtree() &&
parent->GetChildCount() == 1) {
// This <br> is the only node in a text control, therefore it is the hacky
// "bogus node" used when there is no text in a control
*aHyperTextOffset = 0;

Просмотреть файл

@ -1,7 +1,7 @@
WIN32_MODULE_COMPANYNAME=Mozilla Corporation
WIN32_MODULE_COPYRIGHT=©Firefox and Mozilla Developers, according to the MPL 1.1/GPL 2.0/LGPL 2.1 licenses, as applicable.
WIN32_MODULE_PRODUCTVERSION=3,1,0,0
WIN32_MODULE_PRODUCTVERSION_STRING=3.1a1
WIN32_MODULE_PRODUCTVERSION_STRING=3.1a2pre
WIN32_MODULE_TRADEMARKS=Firefox is a Trademark of The Mozilla Foundation.
WIN32_MODULE_DESCRIPTION=Firefox
WIN32_MODULE_PRODUCTNAME=Firefox

Просмотреть файл

@ -1 +1 @@
3.1a1
3.1a2pre

Просмотреть файл

@ -10,4 +10,4 @@
# hardcoded milestones in the tree from these two files.
#--------------------------------------------------------
1.9.1a1
1.9.1a2pre

Просмотреть файл

@ -196,6 +196,7 @@ FixMath.h
float.h
Folders.h
fontconfig/fontconfig.h
fontconfig/fcfreetype.h
Font.h
Fonts.h
fp.h

Просмотреть файл

@ -146,7 +146,7 @@ public:
* @see nsIAnonymousContentCreator
* @return whether this content is anonymous
*/
PRBool IsNativeAnonymous() const
PRBool IsRootOfNativeAnonymousSubtree() const
{
return HasFlag(NODE_IS_ANONYMOUS);
}
@ -177,7 +177,7 @@ public:
}
nsIContent* content = GetBindingParent();
while (content) {
if (content->IsNativeAnonymous()) {
if (content->IsRootOfNativeAnonymousSubtree()) {
NS_ERROR("Element not marked to be in native anonymous subtree!");
break;
}
@ -189,6 +189,31 @@ public:
#endif
}
/**
* Returns true if and only if this node has a parent, but is not in
* its parent's child list.
*/
PRBool IsRootOfAnonymousSubtree() const
{
NS_ASSERTION(!IsRootOfNativeAnonymousSubtree() ||
(GetParent() && GetBindingParent() == GetParent()),
"root of native anonymous subtree must have parent equal "
"to binding parent");
nsIContent *bindingParent = GetBindingParent();
return bindingParent && bindingParent == GetParent();
}
/**
* Returns true if and only if there is NOT a path through child lists
* from the top of this node's parent chain back to this node.
*/
PRBool IsInAnonymousSubtree() const
{
NS_ASSERTION(!IsInNativeAnonymousSubtree() || GetBindingParent(),
"must have binding parent when in native anonymous subtree");
return GetBindingParent() != nsnull;
}
/**
* Get the namespace that this element's tag is defined in
* @return the namespace
@ -563,9 +588,12 @@ public:
}
/**
* Gets content node with the binding responsible for our construction (and
* existence). Used by anonymous content (XBL-generated). null for all
* explicit content.
* Gets content node with the binding (or native code, possibly on the
* frame) responsible for our construction (and existence). Used by
* anonymous content (both XBL-generated and native-anonymous).
*
* null for all explicit content (i.e., content reachable from the top
* of its GetParent() chain via child lists).
*
* @return the binding parent
*/

Просмотреть файл

@ -1890,7 +1890,7 @@ nsContentUtils::GenerateStateKey(nsIContent* aContent,
NS_ENSURE_TRUE(aContent, NS_ERROR_FAILURE);
// Don't capture state for anonymous content
if (aContent->IsNativeAnonymous() || aContent->GetBindingParent()) {
if (aContent->IsInAnonymousSubtree()) {
return NS_OK;
}

Просмотреть файл

@ -2145,8 +2145,8 @@ nsDocument::ElementFromPoint(PRInt32 aX, PRInt32 aY, nsIDOMElement** aReturn)
// replace it with the first non-anonymous parent node of type element.
while (ptContent &&
!ptContent->IsNodeOfType(nsINode::eELEMENT) ||
ptContent->GetBindingParent() ||
ptContent->IsNativeAnonymous()) {
ptContent->IsInAnonymousSubtree()) {
// XXXldb: Faster to jump to GetBindingParent if non-null?
ptContent = ptContent->GetParent();
}

Просмотреть файл

@ -592,8 +592,11 @@ nsGenericDOMDataNode::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
(!aBindingParent && aParent &&
aParent->GetBindingParent() == GetBindingParent()),
"Already have a binding parent. Unbind first!");
NS_PRECONDITION(aBindingParent != this || IsNativeAnonymous(),
"Only native anonymous content should have itself as its "
NS_PRECONDITION(aBindingParent != this,
"Content must not be its own binding parent");
NS_PRECONDITION(!IsRootOfNativeAnonymousSubtree() ||
aBindingParent == aParent,
"Native anonymous content must have its parent as its "
"own binding parent");
if (!aBindingParent && aParent) {
@ -605,13 +608,14 @@ nsGenericDOMDataNode::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
nsDataSlots *slots = GetDataSlots();
NS_ENSURE_TRUE(slots, NS_ERROR_OUT_OF_MEMORY);
NS_ASSERTION(IsNativeAnonymous() || !HasFlag(NODE_IS_IN_ANONYMOUS_SUBTREE) ||
NS_ASSERTION(IsRootOfNativeAnonymousSubtree() ||
!HasFlag(NODE_IS_IN_ANONYMOUS_SUBTREE) ||
aBindingParent->IsInNativeAnonymousSubtree(),
"Trying to re-bind content from native anonymous subtree to"
"non-native anonymous parent!");
slots->mBindingParent = aBindingParent; // Weak, so no addref happens.
if (IsNativeAnonymous() ||
aBindingParent->IsInNativeAnonymousSubtree()) {
if (IsRootOfNativeAnonymousSubtree() ||
aParent->IsInNativeAnonymousSubtree()) {
SetFlags(NODE_IS_IN_ANONYMOUS_SUBTREE);
}
}

Просмотреть файл

@ -435,18 +435,15 @@ nsIContent*
nsIContent::FindFirstNonNativeAnonymous() const
{
// This handles also nested native anonymous content.
nsIContent* content = GetBindingParent();
nsIContent* possibleResult =
!IsNativeAnonymous() ? const_cast<nsIContent*>(this) : nsnull;
while (content) {
if (content->IsNativeAnonymous()) {
content = possibleResult = content->GetParent();
} else {
content = content->GetBindingParent();
for (const nsIContent *content = this; content;
content = content->GetBindingParent()) {
if (!content->IsInNativeAnonymousSubtree()) {
// Oops, this function signature allows casting const to
// non-const. (Then again, so does GetChildAt(0)->GetParent().)
return const_cast<nsIContent*>(content);
}
}
return possibleResult;
return nsnull;
}
//----------------------------------------------------------------------
@ -2091,11 +2088,11 @@ nsGenericElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
NS_PRECONDITION(!aParent || !aDocument ||
!aParent->HasFlag(NODE_FORCE_XBL_BINDINGS),
"Parent in document but flagged as forcing XBL");
NS_PRECONDITION(aBindingParent != this || IsNativeAnonymous(),
"Only native anonymous content should have itself as its "
"own binding parent");
NS_PRECONDITION(!IsNativeAnonymous() || aBindingParent == this,
"Native anonymous content must have itself as its "
NS_PRECONDITION(aBindingParent != this,
"Content must not be its own binding parent");
NS_PRECONDITION(!IsRootOfNativeAnonymousSubtree() ||
aBindingParent == aParent,
"Native anonymous content must have its parent as its "
"own binding parent");
if (!aBindingParent && aParent) {
@ -2121,13 +2118,13 @@ nsGenericElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
slots->mBindingParent = aBindingParent; // Weak, so no addref happens.
}
}
NS_ASSERTION(!aBindingParent || IsNativeAnonymous() ||
NS_ASSERTION(!aBindingParent || IsRootOfNativeAnonymousSubtree() ||
!HasFlag(NODE_IS_IN_ANONYMOUS_SUBTREE) ||
aBindingParent->IsInNativeAnonymousSubtree(),
"Trying to re-bind content from native anonymous subtree to"
"non-native anonymous parent!");
if (IsNativeAnonymous() ||
aBindingParent && aBindingParent->IsInNativeAnonymousSubtree()) {
if (IsRootOfNativeAnonymousSubtree() ||
aParent && aParent->IsInNativeAnonymousSubtree()) {
SetFlags(NODE_IS_IN_ANONYMOUS_SUBTREE);
}
@ -2302,7 +2299,7 @@ FindNativeAnonymousSubtreeOwner(nsIContent* aContent)
if (aContent->IsInNativeAnonymousSubtree()) {
PRBool isNativeAnon = PR_FALSE;
while (aContent && !isNativeAnon) {
isNativeAnon = aContent->IsNativeAnonymous();
isNativeAnon = aContent->IsRootOfNativeAnonymousSubtree();
aContent = aContent->GetParent();
}
}
@ -2318,7 +2315,7 @@ nsGenericElement::doPreHandleEvent(nsIContent* aContent,
// Don't propagate mouseover and mouseout events when mouse is moving
// inside native anonymous content.
PRBool isAnonForEvents = aContent->IsNativeAnonymous();
PRBool isAnonForEvents = aContent->IsRootOfNativeAnonymousSubtree();
if ((aVisitor.mEvent->message == NS_MOUSE_ENTER_SYNTH ||
aVisitor.mEvent->message == NS_MOUSE_EXIT_SYNTH) &&
// This is an optimization - try to stop event propagation when

Просмотреть файл

@ -259,7 +259,7 @@
check( "Inside Element", root, true, false );
cacheCheck( "Element", root );
check( "Outside Element", root2, passed === 0 ? "autofail" : false, false );
runTest( ecss, "Syntax Error: Element", root, false );
runTest( ecss, "SyntaxError: Element", root, false );
jqTests("Element", root3, "querySelectorAll");
var root4 = root2.cloneNode(true);
@ -267,7 +267,7 @@
runTest( css, "Disconnected Element", root4, true );
check( "Disconnected Element", root4, true, true );
cacheCheck( "Disconnected Element", root4 );
runTest( ecss, "Syntax Error: Disconnected Element", root4, false );
runTest( ecss, "SyntaxError: Disconnected Element", root4, false );
jqTests("Disconnected Element", root3.cloneNode(true), "querySelectorAll");
var fragment = document.createDocumentFragment();
@ -276,7 +276,7 @@
interfaceCheck(fragment, "Fragment");
runTest( css, "Fragment", fragment, true );
check( "Fragment", fragment, true, true );
runTest( ecss, "Syntax Error: Fragment", fragment, false );
runTest( ecss, "SyntaxError: Fragment", fragment, false );
cacheCheck( "Fragment", fragment );
root.parentNode.removeChild( root );
@ -284,7 +284,7 @@
interfaceCheck(document, "Document");
runTest( css, "Document", document, true );
check( "Document", document, true, false );
runTest( ecss, "Syntax Error: Document", document, false );
runTest( ecss, "SyntaxError: Document", document, false );
jqTests("Document", document, "querySelectorAll");
cacheCheck( "Document", document );

Просмотреть файл

@ -134,10 +134,8 @@ nsDOMEvent::nsDOMEvent(nsPresContext* aPresContext, nsEvent* aEvent)
mExplicitOriginalTarget = GetTargetFromFrame();
mTmpRealOriginalTarget = mExplicitOriginalTarget;
nsCOMPtr<nsIContent> content = do_QueryInterface(mExplicitOriginalTarget);
if (content) {
if (content->IsNativeAnonymous() || content->GetBindingParent()) {
mExplicitOriginalTarget = nsnull;
}
if (content && content->IsInAnonymousSubtree()) {
mExplicitOriginalTarget = nsnull;
}
}
}

Просмотреть файл

@ -241,6 +241,17 @@ nsSVGFE::ComputeNeededSourceBBoxes(const nsIntRect& aTargetBBox,
}
}
nsIntRect
nsSVGFE::ComputeChangeBBox(const nsTArray<nsIntRect>& aSourceChangeBoxes,
const nsSVGFilterInstance& aInstance)
{
nsIntRect r;
for (PRUint32 i = 0; i < aSourceChangeBoxes.Length(); ++i) {
r.UnionRect(r, aSourceChangeBoxes[i]);
}
return r;
}
void
nsSVGFE::GetSourceImageNames(nsTArray<nsSVGString*>* aSources)
{
@ -319,6 +330,8 @@ public:
const nsSVGFilterInstance& aInstance);
virtual void ComputeNeededSourceBBoxes(const nsIntRect& aTargetBBox,
nsTArray<nsIntRect>& aSourceBBoxes, const nsSVGFilterInstance& aInstance);
virtual nsIntRect ComputeChangeBBox(const nsTArray<nsIntRect>& aSourceChangeBoxes,
const nsSVGFilterInstance& aInstance);
// Gaussian
NS_DECL_NSIDOMSVGFEGAUSSIANBLURELEMENT
@ -344,7 +357,7 @@ protected:
private:
nsresult GetDXY(PRUint32 *aDX, PRUint32 *aDY, const nsSVGFilterInstance& aInstance);
void InflateRectForBlur(nsIntRect* aRect, const nsSVGFilterInstance& aInstance);
nsIntRect InflateRectForBlur(const nsIntRect& aRect, const nsSVGFilterInstance& aInstance);
void GaussianBlur(const Image *aSource, const Image *aTarget,
const nsIntRect& aDataRect,
@ -695,33 +708,38 @@ nsSVGFEGaussianBlurElement::GetSourceImageNames(nsTArray<nsSVGString*>* aSources
aSources->AppendElement(&mStringAttributes[IN1]);
}
void
nsSVGFEGaussianBlurElement::InflateRectForBlur(nsIntRect* aRect,
nsIntRect
nsSVGFEGaussianBlurElement::InflateRectForBlur(const nsIntRect& aRect,
const nsSVGFilterInstance& aInstance)
{
PRUint32 dX, dY;
nsresult rv = GetDXY(&dX, &dY, aInstance);
nsIntRect result = aRect;
if (NS_SUCCEEDED(rv)) {
InflateRectForBlurDXY(aRect, dX, dY);
InflateRectForBlurDXY(&result, dX, dY);
}
return result;
}
nsIntRect
nsSVGFEGaussianBlurElement::ComputeTargetBBox(const nsTArray<nsIntRect>& aSourceBBoxes,
const nsSVGFilterInstance& aInstance)
{
nsIntRect r = aSourceBBoxes[0];
InflateRectForBlur(&r, aInstance);
return r;
return InflateRectForBlur(aSourceBBoxes[0], aInstance);
}
void
nsSVGFEGaussianBlurElement::ComputeNeededSourceBBoxes(const nsIntRect& aTargetBBox,
nsTArray<nsIntRect>& aSourceBBoxes, const nsSVGFilterInstance& aInstance)
{
nsIntRect r = aTargetBBox;
InflateRectForBlur(&r, aInstance);
aSourceBBoxes[0] = r;
aSourceBBoxes[0] = InflateRectForBlur(aTargetBBox, aInstance);
}
nsIntRect
nsSVGFEGaussianBlurElement::ComputeChangeBBox(const nsTArray<nsIntRect>& aSourceChangeBoxes,
const nsSVGFilterInstance& aInstance)
{
return InflateRectForBlur(aSourceChangeBoxes[0], aInstance);
}
//----------------------------------------------------------------------
@ -2389,6 +2407,8 @@ public:
const nsSVGFilterInstance& aInstance);
virtual void ComputeNeededSourceBBoxes(const nsIntRect& aTargetBBox,
nsTArray<nsIntRect>& aSourceBBoxes, const nsSVGFilterInstance& aInstance);
virtual nsIntRect ComputeChangeBBox(const nsTArray<nsIntRect>& aSourceChangeBoxes,
const nsSVGFilterInstance& aInstance);
// Offset
NS_DECL_NSIDOMSVGFEOFFSETELEMENT
@ -2526,6 +2546,13 @@ nsSVGFEOffsetElement::ComputeTargetBBox(const nsTArray<nsIntRect>& aSourceBBoxes
return aSourceBBoxes[0] + GetOffset(aInstance);
}
nsIntRect
nsSVGFEOffsetElement::ComputeChangeBBox(const nsTArray<nsIntRect>& aSourceChangeBoxes,
const nsSVGFilterInstance& aInstance)
{
return aSourceChangeBoxes[0] + GetOffset(aInstance);
}
void
nsSVGFEOffsetElement::ComputeNeededSourceBBoxes(const nsIntRect& aTargetBBox,
nsTArray<nsIntRect>& aSourceBBoxes, const nsSVGFilterInstance& aInstance)
@ -2722,6 +2749,8 @@ public:
const nsSVGFilterInstance& aInstance);
virtual void ComputeNeededSourceBBoxes(const nsIntRect& aTargetBBox,
nsTArray<nsIntRect>& aSourceBBoxes, const nsSVGFilterInstance& aInstance);
virtual nsIntRect ComputeChangeBBox(const nsTArray<nsIntRect>& aSourceChangeBoxes,
const nsSVGFilterInstance& aInstance);
// Tile
NS_DECL_NSIDOMSVGFETILEELEMENT
@ -2800,6 +2829,13 @@ nsSVGFETileElement::ComputeNeededSourceBBoxes(const nsIntRect& aTargetBBox,
// Just assume we need the entire source bounding box, so do nothing.
}
nsIntRect
nsSVGFETileElement::ComputeChangeBBox(const nsTArray<nsIntRect>& aSourceChangeBoxes,
const nsSVGFilterInstance& aInstance)
{
return GetMaxRect();
}
static PRInt32 WrapInterval(PRInt32 aVal, PRInt32 aMax)
{
aVal = aVal % aMax;
@ -3413,6 +3449,8 @@ public:
const nsSVGFilterInstance& aInstance);
virtual void ComputeNeededSourceBBoxes(const nsIntRect& aTargetBBox,
nsTArray<nsIntRect>& aSourceBBoxes, const nsSVGFilterInstance& aInstance);
virtual nsIntRect ComputeChangeBBox(const nsTArray<nsIntRect>& aSourceChangeBoxes,
const nsSVGFilterInstance& aInstance);
// Morphology
NS_DECL_NSIDOMSVGFEMORPHOLOGYELEMENT
@ -3426,7 +3464,7 @@ public:
protected:
void GetRXY(PRInt32 *aRX, PRInt32 *aRY, const nsSVGFilterInstance& aInstance);
void InflateRect(nsIntRect* aRect, const nsSVGFilterInstance& aInstance);
nsIntRect InflateRect(const nsIntRect& aRect, const nsSVGFilterInstance& aInstance);
virtual NumberAttributesInfo GetNumberInfo();
virtual EnumAttributesInfo GetEnumInfo();
@ -3538,31 +3576,36 @@ nsSVGFEMorphologyElement::GetSourceImageNames(nsTArray<nsSVGString*>* aSources)
aSources->AppendElement(&mStringAttributes[IN1]);
}
void
nsSVGFEMorphologyElement::InflateRect(nsIntRect* aRect,
nsIntRect
nsSVGFEMorphologyElement::InflateRect(const nsIntRect& aRect,
const nsSVGFilterInstance& aInstance)
{
PRInt32 rx, ry;
GetRXY(&rx, &ry, aInstance);
aRect->Inflate(PR_MAX(0, rx), PR_MAX(0, ry));
nsIntRect result = aRect;
result.Inflate(PR_MAX(0, rx), PR_MAX(0, ry));
return result;
}
nsIntRect
nsSVGFEMorphologyElement::ComputeTargetBBox(const nsTArray<nsIntRect>& aSourceBBoxes,
const nsSVGFilterInstance& aInstance)
{
nsIntRect r = aSourceBBoxes[0];
InflateRect(&r, aInstance);
return r;
return InflateRect(aSourceBBoxes[0], aInstance);
}
void
nsSVGFEMorphologyElement::ComputeNeededSourceBBoxes(const nsIntRect& aTargetBBox,
nsTArray<nsIntRect>& aSourceBBoxes, const nsSVGFilterInstance& aInstance)
{
nsIntRect r = aTargetBBox;
InflateRect(&r, aInstance);
aSourceBBoxes[0] = r;
aSourceBBoxes[0] = InflateRect(aTargetBBox, aInstance);
}
nsIntRect
nsSVGFEMorphologyElement::ComputeChangeBBox(const nsTArray<nsIntRect>& aSourceChangeBoxes,
const nsSVGFilterInstance& aInstance)
{
return InflateRect(aSourceChangeBoxes[0], aInstance);
}
#define MORPHOLOGY_EPSILON 0.0001
@ -3728,6 +3771,8 @@ public:
const nsSVGFilterInstance& aInstance);
virtual void ComputeNeededSourceBBoxes(const nsIntRect& aTargetBBox,
nsTArray<nsIntRect>& aSourceBBoxes, const nsSVGFilterInstance& aInstance);
virtual nsIntRect ComputeChangeBBox(const nsTArray<nsIntRect>& aSourceChangeBoxes,
const nsSVGFilterInstance& aInstance);
// Color Matrix
NS_DECL_NSIDOMSVGFECONVOLVEMATRIXELEMENT
@ -3959,6 +4004,15 @@ nsSVGFEConvolveMatrixElement::ComputeNeededSourceBBoxes(const nsIntRect& aTarget
// source's output bounding box.
}
nsIntRect
nsSVGFEConvolveMatrixElement::ComputeChangeBBox(const nsTArray<nsIntRect>& aSourceChangeBoxes,
const nsSVGFilterInstance& aInstance)
{
// XXX Precise results are possible but we're going to skip that work
// for now.
return GetMaxRect();
}
static PRInt32 BoundInterval(PRInt32 aVal, PRInt32 aMax)
{
aVal = PR_MAX(aVal, 0);
@ -4492,8 +4546,12 @@ public:
const nsIntRect& aDataRect);
virtual nsSVGString* GetResultImageName() { return &mStringAttributes[RESULT]; }
virtual void GetSourceImageNames(nsTArray<nsSVGString*>* aSources);
// XXX shouldn't we have ComputeTargetBBox here, since the output can
// extend beyond the bounds of the inputs thanks to the convolution kernel?
virtual void ComputeNeededSourceBBoxes(const nsIntRect& aTargetBBox,
nsTArray<nsIntRect>& aSourceBBoxes, const nsSVGFilterInstance& aInstance);
virtual nsIntRect ComputeChangeBBox(const nsTArray<nsIntRect>& aSourceChangeBoxes,
const nsSVGFilterInstance& aInstance);
NS_FORWARD_NSIDOMSVGELEMENT(nsSVGFELightingElementBase::)
NS_FORWARD_NSIDOMNODE(nsSVGFELightingElementBase::)
@ -4541,7 +4599,7 @@ nsSVGElement::StringInfo nsSVGFELightingElement::sStringInfo[2] =
NS_IMPL_ADDREF_INHERITED(nsSVGFELightingElement,nsSVGFELightingElementBase)
NS_IMPL_RELEASE_INHERITED(nsSVGFELightingElement,nsSVGFELightingElementBase)
NS_INTERFACE_MAP_BEGIN(nsSVGFELightingElement)
NS_INTERFACE_MAP_BEGIN(nsSVGFELightingElement)
NS_INTERFACE_MAP_END_INHERITING(nsSVGFELightingElementBase)
//----------------------------------------------------------------------
@ -4573,6 +4631,14 @@ nsSVGFELightingElement::ComputeNeededSourceBBoxes(const nsIntRect& aTargetBBox,
// but just leave it and assume we use the entire source bounding box.
}
nsIntRect
nsSVGFELightingElement::ComputeChangeBBox(const nsTArray<nsIntRect>& aSourceChangeBoxes,
const nsSVGFilterInstance& aInstance)
{
// XXX be conservative for now
return GetMaxRect();
}
#define DOT(a,b) (a[0] * b[0] + a[1] * b[1] + a[2] * b[2])
#define NORMALIZE(vec) \
PR_BEGIN_MACRO \
@ -5444,6 +5510,8 @@ public:
const nsSVGFilterInstance& aInstance);
virtual void ComputeNeededSourceBBoxes(const nsIntRect& aTargetBBox,
nsTArray<nsIntRect>& aSourceBBoxes, const nsSVGFilterInstance& aInstance);
virtual nsIntRect ComputeChangeBBox(const nsTArray<nsIntRect>& aSourceChangeBoxes,
const nsSVGFilterInstance& aInstance);
// DisplacementMap
NS_DECL_NSIDOMSVGFEDISPLACEMENTMAPELEMENT
@ -5665,6 +5733,15 @@ nsSVGFEDisplacementMapElement::ComputeNeededSourceBBoxes(const nsIntRect& aTarge
// If we change this, we need to change coordinate assumptions above
}
nsIntRect
nsSVGFEDisplacementMapElement::ComputeChangeBBox(const nsTArray<nsIntRect>& aSourceChangeBoxes,
const nsSVGFilterInstance& aInstance)
{
// XXX we could do something clever here involving analysis of 'scale'
// to figure out the maximum displacement
return GetMaxRect();
}
//----------------------------------------------------------------------
// nsSVGElement methods

Просмотреть файл

@ -140,15 +140,15 @@ public:
// Return a list of all image names used as sources. Default is to
// return no sources.
virtual void GetSourceImageNames(nsTArray<nsSVGString*>* aSources);
// Compute the bounding-box of the filter output. The default is just the
// union of the source bounding-boxes. The caller is
// Compute the bounding box of the filter output. The default is just the
// union of the source bounding boxes. The caller is
// responsible for clipping this to the filter primitive subregion, so
// if the filter fills its filter primitive subregion, it can just
// return GetMaxRect() here.
// The source bounding-boxes are ordered corresponding to GetSourceImageNames.
// The source bounding boxes are ordered corresponding to GetSourceImageNames.
virtual nsIntRect ComputeTargetBBox(const nsTArray<nsIntRect>& aSourceBBoxes,
const nsSVGFilterInstance& aInstance);
// Given a bounding-box for what we need to compute in the target,
// Given a bounding box for what we need to compute in the target,
// compute which regions of the inputs are needed. On input
// aSourceBBoxes contains the bounding box of what's rendered by
// each source; this function should change those boxes to indicate
@ -157,7 +157,14 @@ public:
// target bbox.
virtual void ComputeNeededSourceBBoxes(const nsIntRect& aTargetBBox,
nsTArray<nsIntRect>& aSourceBBoxes, const nsSVGFilterInstance& aInstance);
// Given the bounding boxes for the pixels that have changed in the inputs,
// compute the bounding box of the changes in this primitive's output.
// The result will be clipped by the caller to the result of ComputeTargetBBox
// since there's no way anything outside that can change.
// The default implementation returns the union of the source change boxes.
virtual nsIntRect ComputeChangeBBox(const nsTArray<nsIntRect>& aSourceChangeBoxes,
const nsSVGFilterInstance& aInstance);
// Perform the actual filter operation.
// We guarantee that every mImage from aSources and aTarget has the
// same width, height, stride and device offset.

Просмотреть файл

@ -1263,15 +1263,11 @@ nsBindingManager::WalkRules(nsStyleSet* aStyleSet,
}
}
nsIContent* parent = content->GetBindingParent();
if (parent == content) {
NS_ASSERTION(content->IsNativeAnonymous(), "Unexpected binding parent");
break; // The anonymous content case is often deliberately hacked to
// return itself to cut off style inheritance here. Do that.
if (content->IsRootOfNativeAnonymousSubtree()) {
break; // Deliberately cut off style inheritance here.
}
content = parent;
content = content->GetBindingParent();
} while (content);
// If "content" is non-null that means we cut off inheritance at some point

Просмотреть файл

@ -110,11 +110,10 @@ IsAncestorBinding(nsIDocument* aDocument,
NS_ASSERTION(aChild, "expected a child content");
PRUint32 bindingRecursion = 0;
nsIContent* bindingParent = aChild->GetBindingParent();
nsBindingManager* bindingManager = aDocument->BindingManager();
for (nsIContent* prev = aChild;
bindingParent && prev != bindingParent;
prev = bindingParent, bindingParent = bindingParent->GetBindingParent()) {
for (nsIContent *bindingParent = aChild->GetBindingParent();
bindingParent;
bindingParent = bindingParent->GetBindingParent()) {
nsXBLBinding* binding = bindingManager->GetBinding(bindingParent);
if (!binding) {
continue;

Просмотреть файл

@ -1086,6 +1086,7 @@ nsXULElement::UnregisterAccessKey(const nsAString& aOldValue)
if (mNodeInfo->Equals(nsGkAtoms::label)) {
// For anonymous labels the unregistering must
// occur on the binding parent control.
// XXXldb: And what if the binding parent is null?
content = GetBindingParent();
}

Просмотреть файл

@ -440,7 +440,7 @@ nsEditor::GetDesiredSpellCheckState()
return PR_FALSE;
}
if (content->IsNativeAnonymous()) {
if (content->IsRootOfNativeAnonymousSubtree()) {
content = content->GetParent();
}
@ -5241,7 +5241,7 @@ nsEditor::GetPIDOMEventTarget()
nsCOMPtr<nsIContent> content = do_QueryInterface(rootElement);
if (content && content->IsNativeAnonymous())
if (content && content->IsRootOfNativeAnonymousSubtree())
{
mEventTarget = do_QueryInterface(content->GetParent());
piTarget = mEventTarget;

Просмотреть файл

@ -188,7 +188,7 @@ nsHTMLEditor::CreateAnonymousElement(const nsAString & aTag, nsIDOMNode * aPare
// establish parenthood of the element
newContent->SetNativeAnonymous();
res = newContent->BindToTree(doc, parentContent, newContent, PR_TRUE);
res = newContent->BindToTree(doc, parentContent, parentContent, PR_TRUE);
if (NS_FAILED(res)) {
newContent->UnbindFromTree();
return res;

Просмотреть файл

@ -5928,7 +5928,7 @@ nsHTMLEditor::IsAnonymousElement(nsIDOMElement * aElement, PRBool * aReturn)
{
NS_ENSURE_TRUE(aElement, NS_ERROR_NULL_POINTER);
nsCOMPtr<nsIContent> content = do_QueryInterface(aElement);
*aReturn = content->IsNativeAnonymous();
*aReturn = content->IsRootOfNativeAnonymousSubtree();
return NS_OK;
}

Просмотреть файл

@ -366,7 +366,7 @@ nsFindContentIterator::SetupInnerIterator(nsIContent* aContent)
if (!aContent) {
return;
}
NS_ASSERTION(!aContent->IsNativeAnonymous(), "invalid call");
NS_ASSERTION(!aContent->IsRootOfNativeAnonymousSubtree(), "invalid call");
nsIDocument* doc = aContent->GetDocument();
nsIPresShell* shell = doc ? doc->GetPrimaryShell() : nsnull;

Просмотреть файл

@ -411,21 +411,6 @@ FocusElementButNotDocument(nsIDocument* aDocument, nsIContent* aContent)
esm->SetFocusedContent(nsnull);
}
static PRBool
IsInNativeAnonymousSubtree(nsIContent* aContent)
{
while (aContent) {
nsIContent* bindingParent = aContent->GetBindingParent();
if (bindingParent == aContent) {
return PR_TRUE;
}
aContent = bindingParent;
}
return PR_FALSE;
}
void nsWebBrowserFind::SetSelectionAndScroll(nsIDOMWindow* aWindow,
nsIDOMRange* aRange)
{
@ -451,7 +436,7 @@ void nsWebBrowserFind::SetSelectionAndScroll(nsIDOMWindow* aWindow,
// <textarea> or text <input>, we need to get the outer frame
nsITextControlFrame *tcFrame = nsnull;
for ( ; content; content = content->GetParent()) {
if (!IsInNativeAnonymousSubtree(content)) {
if (!content->IsInNativeAnonymousSubtree()) {
nsIFrame* f = presShell->GetPrimaryFrameFor(content);
if (!f)
return;

Просмотреть файл

@ -7,9 +7,8 @@ http://www.cairographics.org/.
VERSIONS:
cairo (1.6.4 - 1.6.4)
pixman (0.10.x - pixman-0.10.0-8-g0b207ae)
glitz 0.5.2 (cvs - 2006-01-10)
cairo (1.6.4-350-g1a9809b)
pixman (pixman-0.11.8-7-gdb3fb5e)
***** NOTE FOR VISUAL C++ 6.0 *****
@ -19,21 +18,6 @@ VC6 is not supported. Please upgrade to VC8.
Some specific things:
cairo git commit ea6dbfd36f2182fda16cb82bca92007e0f7b8d77 -
[cairo-meta-surface] Save and restore the original clip.
cairo git commit d96fdd58abf8d6c8692dbb08ec54cdd80accba79 -
win32: Fix broken printing of type1 fonts
cairo git commit 547e2f552cff264b943803d3a1ff03d05bde35c0
Fix win32-printing show_glyphs analysis for Type 1 fonts
cairo git commit 158d24412bba99a4f57907d7fd22a86aae6e87af
Make win32-printing surface work with bitmap fonts
cairo git commit d35d6eec24c1b7ab0a49149a51bf65ea8e223203
Fix win32 bitmap font metrics when device scale != 1
max-font-size.patch: Clamp freetype font size to 1000 to avoid overflow issues
win32-logical-font-scale.patch: set CAIRO_WIN32_LOGICAL_FONT_SCALE to 1
@ -42,10 +26,6 @@ nonfatal-assertions.patch: Make assertions non-fatal
buggy-repeat.patch: Unconditionally turn on buggy-repeat handling to bandaid bug 413583.
clip-clone.patch: _cairo_clip_init_deep_copy should pass 0,0 as the
source coordinates to clone from since it wants an exact copy of the
source's clipping surface
==== pixman patches ====
endian.patch: include cairo-platform.h for endian macros

Просмотреть файл

@ -118,6 +118,7 @@ CSRCS = \
cairo-surface-fallback.c \
cairo-traps.c \
cairo-unicode.c \
cairo-user-font.c \
cairo-wideint.c \
$(NULL)
@ -128,6 +129,7 @@ EXPORTS = cairo.h cairo-features.h cairo-platform.h cairo-deprecated.h cairo-ren
PSPDF_BASE_CSRCS = \
cairo-base85-stream.c \
cairo-type1-fallback.c \
cairo-type3-glyph-surface.c \
cairo-truetype-subset.c \
cairo-cff-subset.c \
$(NULL)

Просмотреть файл

@ -42,6 +42,14 @@ _cairo_analysis_surface_create (cairo_surface_t *target,
int width,
int height);
cairo_private void
_cairo_analysis_surface_set_ctm (cairo_surface_t *surface,
cairo_matrix_t *ctm);
cairo_private void
_cairo_analysis_surface_get_ctm (cairo_surface_t *surface,
cairo_matrix_t *ctm);
cairo_private cairo_region_t *
_cairo_analysis_surface_get_supported (cairo_surface_t *surface);
@ -58,4 +66,8 @@ cairo_private void
_cairo_analysis_surface_get_bounding_box (cairo_surface_t *surface,
cairo_box_t *bbox);
cairo_private cairo_surface_t *
_cairo_null_surface_create (cairo_content_t content);
#endif /* CAIRO_ANALYSIS_SURFACE_H */

Просмотреть файл

@ -84,7 +84,7 @@ _cairo_analysis_surface_analyze_meta_surface_pattern (cairo_analysis_surface_t *
old_height = surface->height;
old_clip = surface->current_clip;
status = _cairo_surface_get_extents (surface_pattern->surface, &meta_extents);
if (status)
if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
surface->width = meta_extents.width;
@ -140,22 +140,13 @@ _cairo_analysis_surface_add_operation (cairo_analysis_surface_t *surface,
}
}
_cairo_box_from_rectangle (&bbox, rect);
if (surface->has_ctm) {
double x1, y1, x2, y2;
x1 = rect->x;
y1 = rect->y;
x2 = rect->x + rect->width;
y2 = rect->y + rect->height;
_cairo_matrix_transform_bounding_box (&surface->ctm,
&x1, &y1, &x2, &y2,
NULL);
rect->x = floor (x1);
rect->y = floor (y1);
_cairo_matrix_transform_bounding_box_fixed (&surface->ctm, &bbox, NULL);
x2 = ceil (x2) - rect->x;
y2 = ceil (y2) - rect->y;
if (x2 <= 0 || y2 <= 0) {
if (bbox.p1.x == bbox.p2.x || bbox.p1.y == bbox.p2.y) {
/* Even though the operation is not visible we must be
* careful to not allow unsupported operations to be
* replayed to the backend during
@ -171,15 +162,9 @@ _cairo_analysis_surface_add_operation (cairo_analysis_surface_t *surface,
}
}
rect->width = x2;
rect->height = y2;
_cairo_box_round_to_rectangle (&bbox, rect);
}
bbox.p1.x = _cairo_fixed_from_int (rect->x);
bbox.p1.y = _cairo_fixed_from_int (rect->y);
bbox.p2.x = _cairo_fixed_from_int (rect->x + rect->width);
bbox.p2.y = _cairo_fixed_from_int (rect->y + rect->height);
if (surface->first_op) {
surface->first_op = FALSE;
surface->page_bbox = bbox;
@ -253,6 +238,8 @@ _cairo_analysis_surface_finish (void *abstract_surface)
_cairo_region_fini (&surface->supported_region);
_cairo_region_fini (&surface->fallback_region);
cairo_surface_destroy (surface->target);
return CAIRO_STATUS_SUCCESS;
}
@ -319,7 +306,7 @@ _cairo_analysis_surface_paint (void *abstract_surface,
source);
status = _cairo_surface_get_extents (&surface->base, &extents);
if (status)
if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
if (_cairo_operator_bounded_by_source (op)) {
@ -377,7 +364,7 @@ _cairo_analysis_surface_mask (void *abstract_surface,
}
status = _cairo_surface_get_extents (&surface->base, &extents);
if (status)
if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
if (_cairo_operator_bounded_by_source (op)) {
@ -432,7 +419,7 @@ _cairo_analysis_surface_stroke (void *abstract_surface,
source);
status = _cairo_surface_get_extents (&surface->base, &extents);
if (status)
if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
if (_cairo_operator_bounded_by_source (op)) {
@ -511,7 +498,7 @@ _cairo_analysis_surface_fill (void *abstract_surface,
source);
status = _cairo_surface_get_extents (&surface->base, &extents);
if (status)
if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
if (_cairo_operator_bounded_by_source (op)) {
@ -569,26 +556,120 @@ _cairo_analysis_surface_show_glyphs (void *abstract_surface,
cairo_pattern_t *source,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font)
cairo_scaled_font_t *scaled_font,
int *remaining_glyphs)
{
cairo_analysis_surface_t *surface = abstract_surface;
cairo_status_t status, backend_status;
cairo_rectangle_int_t extents, glyph_extents;
if (!surface->target->backend->show_glyphs)
backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
else
/* Adapted from _cairo_surface_show_glyphs */
if (surface->target->backend->show_glyphs)
backend_status = (*surface->target->backend->show_glyphs) (surface->target, op,
source,
glyphs, num_glyphs,
scaled_font);
source,
glyphs, num_glyphs,
scaled_font,
remaining_glyphs);
else if (surface->target->backend->show_text_glyphs)
backend_status = surface->target->backend->show_text_glyphs (surface->target, op,
source,
NULL, 0,
glyphs, num_glyphs,
NULL, 0,
FALSE,
scaled_font);
else
backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN)
backend_status = _cairo_analysis_surface_analyze_meta_surface_pattern (surface,
source);
status = _cairo_surface_get_extents (&surface->base, &extents);
if (status)
if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
if (_cairo_operator_bounded_by_source (op)) {
cairo_rectangle_int_t source_extents;
status = _cairo_pattern_get_extents (source, &source_extents);
if (status)
return status;
_cairo_rectangle_intersect (&extents, &source_extents);
}
_cairo_rectangle_intersect (&extents, &surface->current_clip);
if (_cairo_operator_bounded_by_mask (op)) {
status = _cairo_scaled_font_glyph_device_extents (scaled_font,
glyphs,
num_glyphs,
&glyph_extents);
if (status)
return status;
_cairo_rectangle_intersect (&extents, &glyph_extents);
}
status = _cairo_analysis_surface_add_operation (surface, &extents, backend_status);
return status;
}
static cairo_bool_t
_cairo_analysis_surface_has_show_text_glyphs (void *abstract_surface)
{
cairo_analysis_surface_t *surface = abstract_surface;
return _cairo_surface_has_show_text_glyphs (surface->target);
}
static cairo_int_status_t
_cairo_analysis_surface_show_text_glyphs (void *abstract_surface,
cairo_operator_t op,
cairo_pattern_t *source,
const char *utf8,
int utf8_len,
cairo_glyph_t *glyphs,
int num_glyphs,
const cairo_text_cluster_t *clusters,
int num_clusters,
cairo_bool_t backward,
cairo_scaled_font_t *scaled_font)
{
cairo_analysis_surface_t *surface = abstract_surface;
cairo_status_t status, backend_status;
cairo_rectangle_int_t extents, glyph_extents;
/* Adapted from _cairo_surface_show_glyphs */
backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
if (surface->target->backend->show_text_glyphs)
backend_status = surface->target->backend->show_text_glyphs (surface->target, op,
source,
utf8, utf8_len,
glyphs, num_glyphs,
clusters, num_clusters,
backward,
scaled_font);
if (backend_status == CAIRO_INT_STATUS_UNSUPPORTED && surface->target->backend->show_glyphs) {
int remaining_glyphs = num_glyphs;
backend_status = surface->target->backend->show_glyphs (surface->target, op,
source,
glyphs, num_glyphs,
scaled_font,
&remaining_glyphs);
glyphs += num_glyphs - remaining_glyphs;
num_glyphs = remaining_glyphs;
if (remaining_glyphs == 0)
backend_status = CAIRO_STATUS_SUCCESS;
}
if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN)
backend_status = _cairo_analysis_surface_analyze_meta_surface_pattern (surface,
source);
status = _cairo_surface_get_extents (&surface->base, &extents);
if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
if (_cairo_operator_bounded_by_source (op)) {
@ -650,6 +731,9 @@ static const cairo_surface_backend_t cairo_analysis_surface_backend = {
NULL, /* is_similar */
NULL, /* reset */
NULL, /* fill_stroke */
NULL, /* create_solid_pattern_surface */
_cairo_analysis_surface_has_show_text_glyphs,
_cairo_analysis_surface_show_text_glyphs
};
cairo_surface_t *
@ -673,21 +757,54 @@ _cairo_analysis_surface_create (cairo_surface_t *target,
cairo_matrix_init_identity (&surface->ctm);
surface->has_ctm = FALSE;
surface->target = target;
surface->target = cairo_surface_reference (target);
surface->first_op = TRUE;
surface->has_supported = FALSE;
surface->has_unsupported = FALSE;
surface->page_bbox.p1.x = 0;
surface->page_bbox.p1.y = 0;
surface->page_bbox.p2.x = 0;
surface->page_bbox.p2.y = 0;
_cairo_region_init (&surface->supported_region);
_cairo_region_init (&surface->fallback_region);
surface->current_clip.x = 0;
surface->current_clip.y = 0;
surface->current_clip.width = width;
surface->current_clip.height = height;
if (width == -1 && height == -1) {
surface->current_clip.x = CAIRO_RECT_INT_MIN;
surface->current_clip.y = CAIRO_RECT_INT_MIN;
surface->current_clip.width = CAIRO_RECT_INT_MAX - CAIRO_RECT_INT_MIN;
surface->current_clip.height = CAIRO_RECT_INT_MAX - CAIRO_RECT_INT_MIN;
} else {
surface->current_clip.x = 0;
surface->current_clip.y = 0;
surface->current_clip.width = width;
surface->current_clip.height = height;
}
return &surface->base;
}
cairo_private void
_cairo_analysis_surface_set_ctm (cairo_surface_t *abstract_surface,
cairo_matrix_t *ctm)
{
cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface;
surface->ctm = *ctm;
surface->has_ctm = !_cairo_matrix_is_identity (&surface->ctm);
}
cairo_private void
_cairo_analysis_surface_get_ctm (cairo_surface_t *abstract_surface,
cairo_matrix_t *ctm)
{
cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface;
*ctm = surface->ctm;
}
cairo_region_t *
_cairo_analysis_surface_get_supported (cairo_surface_t *abstract_surface)
{
@ -728,3 +845,108 @@ _cairo_analysis_surface_get_bounding_box (cairo_surface_t *abstract_surface,
*bbox = surface->page_bbox;
}
/* null surface type: a surface that does nothing (has no side effects, yay!) */
static cairo_int_status_t
_return_success (void)
{
return CAIRO_STATUS_SUCCESS;
}
/* These typedefs are just to silence the compiler... */
typedef cairo_int_status_t
(*_set_clip_region_func) (void *surface,
cairo_region_t *region);
typedef cairo_int_status_t
(*_paint_func) (void *surface,
cairo_operator_t op,
cairo_pattern_t *source);
typedef cairo_int_status_t
(*_mask_func) (void *surface,
cairo_operator_t op,
cairo_pattern_t *source,
cairo_pattern_t *mask);
typedef cairo_int_status_t
(*_stroke_func) (void *surface,
cairo_operator_t op,
cairo_pattern_t *source,
cairo_path_fixed_t *path,
cairo_stroke_style_t *style,
cairo_matrix_t *ctm,
cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias);
typedef cairo_int_status_t
(*_fill_func) (void *surface,
cairo_operator_t op,
cairo_pattern_t *source,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias);
typedef cairo_int_status_t
(*_show_glyphs_func) (void *surface,
cairo_operator_t op,
cairo_pattern_t *source,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
int *remaining_glyphs);
static const cairo_surface_backend_t cairo_null_surface_backend = {
CAIRO_INTERNAL_SURFACE_TYPE_NULL,
NULL, /* create_similar */
NULL, /* finish */
NULL, /* acquire_source_image */
NULL, /* release_source_image */
NULL, /* acquire_dest_image */
NULL, /* release_dest_image */
NULL, /* clone_similar */
NULL, /* composite */
NULL, /* fill_rectangles */
NULL, /* composite_trapezoids */
NULL, /* copy_page */
NULL, /* show_page */
(_set_clip_region_func) _return_success, /* set_clip_region */
NULL, /* intersect_clip_path */
NULL, /* get_extents */
NULL, /* old_show_glyphs */
NULL, /* get_font_options */
NULL, /* flush */
NULL, /* mark_dirty_rectangle */
NULL, /* scaled_font_fini */
NULL, /* scaled_glyph_fini */
(_paint_func) _return_success, /* paint */
(_mask_func) _return_success, /* mask */
(_stroke_func) _return_success, /* stroke */
(_fill_func) _return_success, /* fill */
(_show_glyphs_func) _return_success, /* show_glyphs */
NULL, /* snapshot */
NULL, /* is_similar */
NULL, /* reset */
NULL, /* fill_stroke */
NULL, /* create_solid_pattern_surface */
NULL, /* has_show_text_glyphs */
NULL /* show_text_glyphs */
};
cairo_surface_t *
_cairo_null_surface_create (cairo_content_t content)
{
cairo_surface_t *surface;
surface = malloc (sizeof (cairo_surface_t));
if (surface == NULL) {
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
}
_cairo_surface_init (surface, &cairo_null_surface_backend, content);
return surface;
}

Просмотреть файл

@ -181,13 +181,15 @@ _cairo_arc_in_direction (cairo_t *cr,
double angle_max,
cairo_direction_t dir)
{
if (cairo_status (cr))
return;
while (angle_max - angle_min > 4 * M_PI)
angle_max -= 2 * M_PI;
/* Recurse if drawing arc larger than pi */
if (angle_max - angle_min > M_PI) {
double angle_mid = angle_min + (angle_max - angle_min) / 2.0;
/* XXX: Something tells me this block could be condensed. */
if (dir == CAIRO_DIRECTION_FORWARD) {
_cairo_arc_in_direction (cr, xc, yc, radius,
angle_min, angle_mid,
@ -205,7 +207,7 @@ _cairo_arc_in_direction (cairo_t *cr,
angle_min, angle_mid,
dir);
}
} else {
} else if (angle_max != angle_min) {
cairo_matrix_t ctm;
int i, segments;
double angle, angle_step;

Просмотреть файл

@ -236,7 +236,7 @@ _cairo_array_copy_element (cairo_array_t *array, int index, void *dst)
* _cairo_array_index (array, _cairo_array_num_elements (array) - 1);
*
* Return value: %CAIRO_STATUS_SUCCESS if successful or
* CAIRO_STATUS_NO_MEMORY if insufficient memory is available for the
* %CAIRO_STATUS_NO_MEMORY if insufficient memory is available for the
* operation.
**/
cairo_status_t
@ -256,7 +256,7 @@ _cairo_array_append (cairo_array_t *array,
* @elements into the array.
*
* Return value: %CAIRO_STATUS_SUCCESS if successful or
* CAIRO_STATUS_NO_MEMORY if insufficient memory is available for the
* %CAIRO_STATUS_NO_MEMORY if insufficient memory is available for the
* operation.
**/
cairo_status_t
@ -287,7 +287,7 @@ _cairo_array_append_multiple (cairo_array_t *array,
* for in the return value of _cairo_array_num_elements().
*
* Return value: %CAIRO_STATUS_SUCCESS if successful or
* CAIRO_STATUS_NO_MEMORY if insufficient memory is available for the
* %CAIRO_STATUS_NO_MEMORY if insufficient memory is available for the
* operation.
**/
cairo_status_t

Просмотреть файл

@ -1,4 +1,5 @@
/* cairo_output_stream.c: Output stream abstraction
/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc
*

Просмотреть файл

@ -508,7 +508,7 @@ det64_128 (cairo_int64_t a,
* result is provided as a coordinate pair of 128-bit integers.
*
* Returns %CAIRO_BO_STATUS_INTERSECTION if there is an intersection or
* CAIRO_BO_STATUS_PARALLEL if the two lines are exactly parallel.
* %CAIRO_BO_STATUS_PARALLEL if the two lines are exactly parallel.
*/
static cairo_bo_status_t
intersect_lines (cairo_bo_edge_t *a,
@ -1214,7 +1214,7 @@ _active_edges_to_traps (cairo_bo_edge_t *head,
int in_out = 0;
cairo_bo_edge_t *edge;
for (edge = head; edge && edge->next; edge = edge->next) {
for (edge = head; edge; edge = edge->next) {
if (fill_rule == CAIRO_FILL_RULE_WINDING) {
if (edge->reversed)
in_out++;
@ -1415,9 +1415,9 @@ update_minmax(cairo_fixed_t *inout_min,
}
cairo_status_t
_cairo_bentley_ottmann_tessellate_polygon (cairo_traps_t *traps,
cairo_polygon_t *polygon,
cairo_fill_rule_t fill_rule)
_cairo_bentley_ottmann_tessellate_polygon (cairo_traps_t *traps,
const cairo_polygon_t *polygon,
cairo_fill_rule_t fill_rule)
{
int intersections;
cairo_status_t status;

Просмотреть файл

@ -36,7 +36,7 @@
#ifndef CAIRO_BEOS_H
#define CAIRO_BEOS_H
#include <cairo.h>
#include "cairo.h"
#if CAIRO_HAS_BEOS_SURFACE

Просмотреть файл

@ -296,7 +296,7 @@ _cairo_cache_shrink_to_accommodate (cairo_cache_t *cache,
* entry_destroy() callback will be called on it).
*
* Return value: %CAIRO_STATUS_SUCCESS if successful or
* CAIRO_STATUS_NO_MEMORY if insufficient memory is available.
* %CAIRO_STATUS_NO_MEMORY if insufficient memory is available.
**/
cairo_status_t
_cairo_cache_insert (cairo_cache_t *cache,

Просмотреть файл

@ -274,13 +274,13 @@ _cairo_clip_combine_to_surface (cairo_clip_t *clip,
int dst_y,
const cairo_rectangle_int_t *extents)
{
cairo_pattern_union_t pattern;
cairo_surface_pattern_t pattern;
cairo_status_t status;
if (clip->all_clipped)
return CAIRO_STATUS_SUCCESS;
_cairo_pattern_init_for_surface (&pattern.surface, clip->surface);
_cairo_pattern_init_for_surface (&pattern, clip->surface);
status = _cairo_surface_composite (op,
&pattern.base,
@ -485,8 +485,7 @@ _cairo_clip_intersect_mask (cairo_clip_t *clip,
CAIRO_CONTENT_ALPHA,
surface_rect.width,
surface_rect.height,
CAIRO_COLOR_TRANSPARENT,
&pattern.base);
CAIRO_COLOR_TRANSPARENT);
if (surface->status) {
_cairo_pattern_fini (&pattern.base);
return surface->status;
@ -630,7 +629,7 @@ _cairo_clip_translate (cairo_clip_t *clip,
_cairo_fixed_to_double (ty));
while (clip_path) {
_cairo_path_fixed_device_transform (&clip_path->path, &matrix);
_cairo_path_fixed_transform (&clip_path->path, &matrix);
clip_path = clip_path->prev;
}
}
@ -678,7 +677,8 @@ _cairo_clip_init_deep_copy (cairo_clip_t *clip,
if (other->surface) {
status = _cairo_surface_clone_similar (target, other->surface,
0, 0,
0,
0,
other->surface_rect.width,
other->surface_rect.height,
&clip->surface);

Просмотреть файл

@ -111,7 +111,7 @@ CAIRO_BEGIN_DECLS
#define __attribute__(x)
#endif
#if defined(__WIN32__) || defined(_MSC_VER)
#if (defined(__WIN32__) && !defined(__WINE__)) || defined(_MSC_VER)
#define snprintf _snprintf
#endif

Просмотреть файл

@ -61,15 +61,15 @@ cairo_debug_reset_static_data (void)
{
CAIRO_MUTEX_INITIALIZE ();
_cairo_font_reset_static_data ();
_cairo_font_face_reset_static_data ();
#if CAIRO_HAS_FT_FONT
_cairo_ft_font_reset_static_data ();
#endif
_cairo_pattern_reset_static_data ();
_cairo_scaled_font_reset_static_data ();
_cairo_pattern_reset_static_data ();
CAIRO_MUTEX_FINALIZE ();
}

Просмотреть файл

@ -1,4 +1,5 @@
/* cairo_deflate_stream.c: Output stream abstraction
/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2006 Adrian Johnson
*

Просмотреть файл

@ -52,8 +52,6 @@
#define CAIRO_FONT_TYPE_ATSUI CAIRO_FONT_TYPE_QUARTZ
#ifndef _CAIROINT_H_
/* Obsolete functions. These definitions exist to coerce the compiler
* into providing a little bit of guidance with its error
* messages. The idea is to help users port their old code without
@ -137,6 +135,4 @@
#define cairo_get_status_string cairo_get_status_string_DEPRECATED_BY_cairo_status_AND_cairo_status_to_string
#define cairo_status_string cairo_status_string_DEPRECATED_BY_cairo_status_AND_cairo_status_to_string
#endif
#endif /* CAIRO_DEPRECATED_H */

Просмотреть файл

@ -1606,7 +1606,8 @@ _cairo_directfb_surface_show_glyphs (void *abstract_dst,
cairo_pattern_t *pattern,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font)
cairo_scaled_font_t *scaled_font,
int *remaining_glyphs)
{
cairo_directfb_surface_t *dst = abstract_dst;
cairo_directfb_font_cache_t *cache;

Просмотреть файл

@ -47,7 +47,7 @@
#ifndef CAIRO_DIRECTFB_H
#define CAIRO_DIRECTFB_H
#include <cairo.h>
#include "cairo.h"
#ifdef CAIRO_HAS_DIRECTFB_SURFACE

Просмотреть файл

@ -226,6 +226,17 @@ _cairo_fixed_mul (cairo_fixed_t a, cairo_fixed_t b)
return _cairo_int64_to_int32(_cairo_int64_rsl (temp, CAIRO_FIXED_FRAC_BITS));
}
/* computes a * b / c */
static inline cairo_fixed_t
_cairo_fixed_mul_div (cairo_fixed_t a, cairo_fixed_t b, cairo_fixed_t c)
{
cairo_int64_t ab = _cairo_int32x32_64_mul (a, b);
cairo_int64_t c64 = _cairo_int32_to_int64 (c);
cairo_int64_t quo = _cairo_int64_divrem (ab, c64).quo;
return _cairo_int64_to_int32(quo);
}
#else
# error Please define multiplication and other operands for your fixed-point type size
#endif

Просмотреть файл

@ -63,6 +63,8 @@ _cairo_font_face_set_error (cairo_font_face_t *font_face,
if (status == CAIRO_STATUS_SUCCESS)
return status;
/* Don't overwrite an existing error. This preserves the first
* error, which is the most significant. */
_cairo_status_set_error (&font_face->status, status);
return _cairo_error (status);
@ -132,7 +134,8 @@ cairo_font_face_destroy (cairo_font_face_t *font_face)
if (! _cairo_reference_count_dec_and_test (&font_face->ref_count))
return;
font_face->backend->destroy (font_face);
if (font_face->backend->destroy)
font_face->backend->destroy (font_face);
/* We allow resurrection to deal with some memory management for the
* FreeType backend where cairo_ft_font_face_t and cairo_ft_unscaled_font_t
@ -534,7 +537,7 @@ _cairo_unscaled_font_destroy (cairo_unscaled_font_t *unscaled_font)
}
void
_cairo_font_reset_static_data (void)
_cairo_font_face_reset_static_data (void)
{
_cairo_scaled_font_map_destroy ();

Просмотреть файл

@ -95,7 +95,6 @@ cairo_font_options_create (void)
return options;
}
slim_hidden_def (cairo_font_options_create);
/**
* cairo_font_options_copy:
@ -144,7 +143,6 @@ cairo_font_options_destroy (cairo_font_options_t *options)
free (options);
}
slim_hidden_def (cairo_font_options_destroy);
/**
* cairo_font_options_status:

Просмотреть файл

@ -1,3 +1,4 @@
/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2000 Keith Packard
@ -91,7 +92,7 @@ typedef struct _cairo_ft_font_face cairo_ft_font_face_t;
struct _cairo_ft_unscaled_font {
cairo_unscaled_font_t base;
cairo_bool_t from_face; /* from cairo_ft_font_face_create_for_ft_face()? */
cairo_bool_t from_face; /* was the FT_Face provided by user? */
FT_Face face; /* provided or cached face */
/* only set if from_face is false */
@ -282,17 +283,22 @@ _cairo_ft_unscaled_font_map_unlock (void)
static void
_cairo_ft_unscaled_font_init_key (cairo_ft_unscaled_font_t *key,
cairo_bool_t from_face,
char *filename,
int id)
int id,
FT_Face face)
{
unsigned long hash;
key->from_face = from_face;
key->filename = filename;
key->id = id;
key->face = face;
/* 1607 is just an arbitrary prime. */
hash = _cairo_hash_string (filename);
/* the constants are just arbitrary primes */
hash += ((unsigned long) id) * 1607;
hash += ((unsigned long) face) * 2137;
key->base.hash_entry.hash = hash;
}
@ -320,6 +326,7 @@ _cairo_ft_unscaled_font_init_key (cairo_ft_unscaled_font_t *key,
**/
static cairo_status_t
_cairo_ft_unscaled_font_init (cairo_ft_unscaled_font_t *unscaled,
cairo_bool_t from_face,
const char *filename,
int id,
FT_Face face)
@ -327,11 +334,9 @@ _cairo_ft_unscaled_font_init (cairo_ft_unscaled_font_t *unscaled,
_cairo_unscaled_font_init (&unscaled->base,
&cairo_ft_unscaled_font_backend);
if (face) {
if (from_face) {
unscaled->from_face = TRUE;
unscaled->face = face;
unscaled->filename = NULL;
unscaled->id = 0;
_cairo_ft_unscaled_font_init_key (unscaled, TRUE, NULL, 0, face);
} else {
char *filename_copy;
@ -341,8 +346,7 @@ _cairo_ft_unscaled_font_init (cairo_ft_unscaled_font_t *unscaled,
filename_copy = strdup (filename);
if (filename_copy == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
_cairo_ft_unscaled_font_init_key (unscaled, filename_copy, id);
_cairo_ft_unscaled_font_init_key (unscaled, FALSE, filename_copy, id, NULL);
}
unscaled->have_scale = FALSE;
@ -354,12 +358,6 @@ _cairo_ft_unscaled_font_init (cairo_ft_unscaled_font_t *unscaled,
return CAIRO_STATUS_SUCCESS;
}
cairo_bool_t
_cairo_unscaled_font_is_ft (cairo_unscaled_font_t *unscaled_font)
{
return unscaled_font->backend == &cairo_ft_unscaled_font_backend;
}
/**
* _cairo_ft_unscaled_font_fini:
*
@ -391,35 +389,41 @@ _cairo_ft_unscaled_font_keys_equal (const void *key_a,
const cairo_ft_unscaled_font_t *unscaled_a = key_a;
const cairo_ft_unscaled_font_t *unscaled_b = key_b;
return (strcmp (unscaled_a->filename, unscaled_b->filename) == 0 &&
unscaled_a->id == unscaled_b->id);
if (unscaled_a->id == unscaled_b->id &&
unscaled_a->from_face == unscaled_b->from_face)
{
if (unscaled_a->from_face)
return unscaled_a->face == unscaled_b->face;
if (unscaled_a->filename == NULL && unscaled_b->filename == NULL)
return TRUE;
else if (unscaled_a->filename == NULL || unscaled_b->filename == NULL)
return FALSE;
else
return (strcmp (unscaled_a->filename, unscaled_b->filename) == 0);
}
return FALSE;
}
/* Finds or creates a #cairo_ft_unscaled_font_t for the filename/id from
* pattern. Returns a new reference to the unscaled font.
*/
static cairo_ft_unscaled_font_t *
_cairo_ft_unscaled_font_create_for_pattern (FcPattern *pattern)
_cairo_ft_unscaled_font_create_internal (cairo_bool_t from_face,
char *filename,
int id,
FT_Face font_face)
{
cairo_ft_unscaled_font_t key, *unscaled;
cairo_ft_unscaled_font_map_t *font_map;
cairo_status_t status;
FcChar8 *fc_filename;
char *filename;
int id;
if (FcPatternGetString (pattern, FC_FILE, 0, &fc_filename) != FcResultMatch)
goto UNWIND;
filename = (char *) fc_filename;
if (FcPatternGetInteger (pattern, FC_INDEX, 0, &id) != FcResultMatch)
goto UNWIND;
font_map = _cairo_ft_unscaled_font_map_lock ();
if (font_map == NULL)
goto UNWIND;
_cairo_ft_unscaled_font_init_key (&key, filename, id);
_cairo_ft_unscaled_font_init_key (&key, from_face, filename, id, font_face);
/* Return existing unscaled font if it exists in the hash table. */
if (_cairo_hash_table_lookup (font_map->hash_table, &key.base.hash_entry,
@ -437,7 +441,7 @@ _cairo_ft_unscaled_font_create_for_pattern (FcPattern *pattern)
goto UNWIND_FONT_MAP_LOCK;
}
status = _cairo_ft_unscaled_font_init (unscaled, filename, id, NULL);
status = _cairo_ft_unscaled_font_init (unscaled, from_face, filename, id, font_face);
if (status)
goto UNWIND_UNSCALED_MALLOC;
@ -460,57 +464,66 @@ UNWIND:
return NULL;
}
static cairo_ft_unscaled_font_t *
_cairo_ft_unscaled_font_create_for_pattern (FcPattern *pattern)
{
FT_Face font_face = NULL;
char *filename = NULL;
int id = 0;
if (FcPatternGetFTFace (pattern, FC_FT_FACE, 0, &font_face) != FcResultMatch) {
FcChar8 *fc_filename = NULL;
if (FcPatternGetString (pattern, FC_FILE, 0, &fc_filename) != FcResultMatch)
goto UNWIND;
filename = (char *) fc_filename;
if (FcPatternGetInteger (pattern, FC_INDEX, 0, &id) != FcResultMatch)
goto UNWIND;
}
return _cairo_ft_unscaled_font_create_internal (font_face != NULL, filename, id, font_face);
UNWIND:
return NULL;
}
static cairo_ft_unscaled_font_t *
_cairo_ft_unscaled_font_create_from_face (FT_Face face)
{
cairo_status_t status;
cairo_ft_unscaled_font_t *unscaled;
unscaled = malloc (sizeof (cairo_ft_unscaled_font_t));
if (unscaled == NULL) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return NULL;
}
status = _cairo_ft_unscaled_font_init (unscaled, NULL, 0, face);
if (status) {
free (unscaled);
return NULL;
}
return unscaled;
return _cairo_ft_unscaled_font_create_internal (TRUE, NULL, 0, face);
}
static void
_cairo_ft_unscaled_font_destroy (void *abstract_font)
{
cairo_ft_unscaled_font_t *unscaled = abstract_font;
cairo_ft_unscaled_font_map_t *font_map;
if (unscaled == NULL)
return;
font_map = _cairo_ft_unscaled_font_map_lock ();
/* All created objects must have been mapped in the font map. */
assert (font_map != NULL);
_cairo_hash_table_remove (font_map->hash_table,
&unscaled->base.hash_entry);
if (unscaled->from_face) {
/* See comments in _ft_font_face_destroy about the "zombie" state
* for a _ft_font_face.
*/
if (unscaled->faces && !unscaled->faces->unscaled)
cairo_font_face_destroy (&unscaled->faces->base);
unscaled->face = NULL;
} else {
cairo_ft_unscaled_font_map_t *font_map;
font_map = _cairo_ft_unscaled_font_map_lock ();
/* All created objects must have been mapped in the font map. */
assert (font_map != NULL);
_cairo_hash_table_remove (font_map->hash_table,
&unscaled->base.hash_entry);
_font_map_release_face_lock_held (font_map, unscaled);
_cairo_ft_unscaled_font_map_unlock ();
}
unscaled->face = NULL;
_cairo_ft_unscaled_font_map_unlock ();
_cairo_ft_unscaled_font_fini (unscaled);
}
@ -579,7 +592,7 @@ _cairo_ft_unscaled_font_lock_face (cairo_ft_unscaled_font_t *unscaled)
return face;
}
slim_hidden_def (cairo_ft_scaled_font_lock_face);
/* Unlock unscaled font locked with _cairo_ft_unscaled_font_lock_face
*/
@ -592,7 +605,7 @@ _cairo_ft_unscaled_font_unlock_face (cairo_ft_unscaled_font_t *unscaled)
CAIRO_MUTEX_UNLOCK (unscaled->mutex);
}
slim_hidden_def (cairo_ft_scaled_font_unlock_face);
static cairo_status_t
_compute_transform (cairo_ft_font_transform_t *sf,
@ -611,7 +624,7 @@ _compute_transform (cairo_ft_font_transform_t *sf,
status = _cairo_matrix_compute_scale_factors (scale,
&x_scale, &y_scale,
/* XXX */ 1);
1);
if (status)
return status;
@ -1274,7 +1287,7 @@ typedef struct _cairo_ft_scaled_font {
cairo_ft_options_t ft_options;
} cairo_ft_scaled_font_t;
const cairo_scaled_font_backend_t cairo_ft_scaled_font_backend;
const cairo_scaled_font_backend_t _cairo_ft_scaled_font_backend;
/* The load flags passed to FT_Load_Glyph control aspects like hinting and
* antialiasing. Here we compute them from the fields of a FcPattern.
@ -1519,7 +1532,7 @@ _cairo_ft_scaled_font_create (cairo_ft_unscaled_font_t *unscaled,
status = _cairo_scaled_font_init (&scaled_font->base,
font_face,
font_matrix, ctm, options,
&cairo_ft_scaled_font_backend);
&_cairo_ft_scaled_font_backend);
if (status) {
_cairo_unscaled_font_destroy (&unscaled->base);
free (scaled_font);
@ -1597,7 +1610,7 @@ _cairo_ft_scaled_font_create (cairo_ft_unscaled_font_t *unscaled,
cairo_bool_t
_cairo_scaled_font_is_ft (cairo_scaled_font_t *scaled_font)
{
return scaled_font->backend == &cairo_ft_scaled_font_backend;
return scaled_font->backend == &_cairo_ft_scaled_font_backend;
}
static cairo_status_t
@ -2169,40 +2182,36 @@ _cairo_ft_load_truetype_table (void *abstract_font,
}
static cairo_int_status_t
_cairo_ft_map_glyphs_to_unicode (void *abstract_font,
cairo_scaled_font_subset_t *font_subset)
_cairo_ft_index_to_ucs4(void *abstract_font,
unsigned long index,
uint32_t *ucs4)
{
cairo_ft_scaled_font_t *scaled_font = abstract_font;
cairo_ft_unscaled_font_t *unscaled = scaled_font->unscaled;
FT_Face face;
FT_UInt glyph;
unsigned long charcode;
unsigned int i;
int count;
FT_ULong charcode;
FT_UInt gindex;
face = _cairo_ft_unscaled_font_lock_face (unscaled);
if (!face)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
count = font_subset->num_glyphs;
charcode = FT_Get_First_Char( face, &glyph);
while (glyph != 0 && count > 0)
{
for (i = 0; i < font_subset->num_glyphs; i++) {
if (font_subset->glyphs[i] == glyph) {
font_subset->to_unicode[i] = charcode;
count--;
break;
}
}
charcode = FT_Get_Next_Char (face, charcode, &glyph);
*ucs4 = (uint32_t) -1;
charcode = FT_Get_First_Char(face, &gindex);
while (gindex != 0) {
charcode = FT_Get_Next_Char (face, charcode, &gindex);
if (gindex == index) {
*ucs4 = charcode;
break;
}
}
_cairo_ft_unscaled_font_unlock_face (unscaled);
return CAIRO_STATUS_SUCCESS;
}
const cairo_scaled_font_backend_t cairo_ft_scaled_font_backend = {
const cairo_scaled_font_backend_t _cairo_ft_scaled_font_backend = {
CAIRO_FONT_TYPE_FT,
_cairo_ft_scaled_font_create_toy,
_cairo_ft_scaled_font_fini,
@ -2211,7 +2220,7 @@ const cairo_scaled_font_backend_t cairo_ft_scaled_font_backend = {
_cairo_ft_ucs4_to_index,
NULL, /* show_glyphs */
_cairo_ft_load_truetype_table,
_cairo_ft_map_glyphs_to_unicode,
_cairo_ft_index_to_ucs4
};
/* #cairo_ft_font_face_t */
@ -2292,6 +2301,10 @@ _cairo_ft_font_face_scaled_font_create (void *abstract_face,
* derived from a pattern where the user has called
* cairo_ft_font_options_substitute(), so *just* use those load
* flags and ignore the options.
*
* XXX two points about the above comment:
* 1. I don't see how the comment is relevant here,
* 2. What if the face is coming from FC_FT_FACE of a pattern?
*/
ft_options = font_face->ft_options;
@ -2487,7 +2500,7 @@ cairo_ft_font_options_substitute (const cairo_font_options_t *options,
* cairo_set_font_face() or cairo_scaled_font_create(). The
* #cairo_scaled_font_t returned from cairo_scaled_font_create() is
* also for the FreeType backend and can be used with functions such
* as cairo_ft_font_lock_face().
* as cairo_ft_scaled_font_lock_face().
*
* Font rendering options are represented both here and when you
* call cairo_scaled_font_create(). Font options that have a representation
@ -2495,6 +2508,17 @@ cairo_ft_font_options_substitute (const cairo_font_options_t *options,
* appropriately to reflect the options in a #cairo_font_options_t, call
* cairo_ft_font_options_substitute().
*
* The pattern's FC_FT_FACE element is inspected first and if that is set,
* that will be the FreeType font face associated with the returned cairo
* font face. Otherwise the FC_FILE and FC_INDEX elements of @pattern are
* used to load a font face from file.
*
* If the FC_FT_FACE element of @pattern is set, the user is responsible
* for making sure that the referenced FT_Face remains valid for the life
* time of the returned #cairo_font_face_t. See
* cairo_ft_font_face_create_for_ft_face() for an exmaple of how to couple
* the life time of the FT_Face to that of the cairo font-face.
*
* Return value: a newly created #cairo_font_face_t. Free with
* cairo_font_face_destroy() when you are done using it.
**/
@ -2539,7 +2563,23 @@ cairo_ft_font_face_create_for_pattern (FcPattern *pattern)
* cairo_set_font_face() or cairo_scaled_font_create(). The
* #cairo_scaled_font_t returned from cairo_scaled_font_create() is
* also for the FreeType backend and can be used with functions such
* as cairo_ft_font_lock_face().
* as cairo_ft_scaled_font_lock_face().
*
* As an example, here is how one might correctly couple the lifetime of
* the FreeType face object to the #cairo_font_face_t:
*
* <informalexample><programlisting>
* static const cairo_user_data_key_t key;
*
* font_face = cairo_ft_font_face_create_for_ft_face (ft_face, 0);
* status = cairo_font_face_set_user_data (font_face, &key,
* ft_face, (cairo_destroy_func_t) FT_Done_Face);
* if (status) {
* cairo_font_face_destroy (font_face);
* FT_Done_Face (ft_face);
* return ERROR;
* }
* </programlisting></informalexample>
*
* Return value: a newly created #cairo_font_face_t. Free with
* cairo_font_face_destroy() when you are done using it.
@ -2573,16 +2613,16 @@ cairo_ft_font_face_create_for_ft_face (FT_Face face,
* @scaled_font: A #cairo_scaled_font_t from the FreeType font backend. Such an
* object can be created by calling cairo_scaled_font_create() on a
* FreeType backend font face (see cairo_ft_font_face_create_for_pattern(),
* cairo_ft_font_face_create_for_face()).
* cairo_ft_font_face_create_for_ft_face()).
*
* cairo_ft_font_lock_face() gets the #FT_Face object from a FreeType
* cairo_ft_scaled_font_lock_face() gets the #FT_Face object from a FreeType
* backend font and scales it appropriately for the font. You must
* release the face with cairo_ft_font_unlock_face()
* release the face with cairo_ft_scaled_font_unlock_face()
* when you are done using it. Since the #FT_Face object can be
* shared between multiple #cairo_scaled_font_t objects, you must not
* lock any other font objects until you unlock this one. A count is
* kept of the number of times cairo_ft_font_lock_face() is
* called. cairo_ft_font_unlock_face() must be called the same number
* kept of the number of times cairo_ft_scaled_font_lock_face() is
* called. cairo_ft_scaled_font_unlock_face() must be called the same number
* of times.
*
* You must be careful when using this function in a library or in a
@ -2605,6 +2645,11 @@ cairo_ft_scaled_font_lock_face (cairo_scaled_font_t *abstract_font)
FT_Face face;
cairo_status_t status;
if (! _cairo_scaled_font_is_ft (abstract_font)) {
_cairo_error_throw (CAIRO_STATUS_FONT_TYPE_MISMATCH);
return NULL;
}
if (scaled_font->base.status)
return NULL;
@ -2647,6 +2692,11 @@ cairo_ft_scaled_font_unlock_face (cairo_scaled_font_t *abstract_font)
{
cairo_ft_scaled_font_t *scaled_font = (cairo_ft_scaled_font_t *) abstract_font;
if (! _cairo_scaled_font_is_ft (abstract_font)) {
_cairo_error_throw (CAIRO_STATUS_FONT_TYPE_MISMATCH);
return;
}
if (scaled_font->base.status)
return;

Просмотреть файл

@ -37,8 +37,8 @@
#ifndef CAIRO_FT_PRIVATE_H
#define CAIRO_FT_PRIVATE_H
#include <cairo-ft.h>
#include <cairoint.h>
#include "cairo-ft.h"
#include "cairoint.h"
#if CAIRO_HAS_FT_FONT
@ -46,9 +46,6 @@ CAIRO_BEGIN_DECLS
typedef struct _cairo_ft_unscaled_font cairo_ft_unscaled_font_t;
cairo_private cairo_bool_t
_cairo_unscaled_font_is_ft (cairo_unscaled_font_t *unscaled_font);
cairo_private cairo_bool_t
_cairo_scaled_font_is_ft (cairo_scaled_font_t *scaled_font);
@ -67,9 +64,6 @@ _cairo_ft_unscaled_font_unlock_face (cairo_ft_unscaled_font_t *unscaled);
cairo_private cairo_bool_t
_cairo_ft_scaled_font_is_vertical (cairo_scaled_font_t *scaled_font);
slim_hidden_proto (cairo_ft_scaled_font_lock_face);
slim_hidden_proto (cairo_ft_scaled_font_unlock_face);
CAIRO_END_DECLS
#endif /* CAIRO_HAS_FT_FONT */

Просмотреть файл

@ -37,7 +37,7 @@
#ifndef CAIRO_FT_H
#define CAIRO_FT_H
#include <cairo.h>
#include "cairo.h"
#if CAIRO_HAS_FT_FONT

Просмотреть файл

@ -958,7 +958,7 @@ _cairo_glitz_pattern_acquire_surfaces (cairo_pattern_t *src,
cairo_glitz_surface_attributes_t *mattr)
{
cairo_int_status_t status;
cairo_pattern_union_t tmp;
cairo_solid_pattern_t tmp;
/* If src and mask are both solid, then the mask alpha can be
* combined into src and mask can be ignored. */
@ -977,10 +977,7 @@ _cairo_glitz_pattern_acquire_surfaces (cairo_pattern_t *src,
combined = src_solid->color;
_cairo_color_multiply_alpha (&combined, mask_solid->color.alpha);
_cairo_pattern_init_solid (&tmp.solid, &combined,
CAIRO_COLOR_IS_OPAQUE (&combined) ?
CAIRO_CONTENT_COLOR :
CAIRO_CONTENT_COLOR_ALPHA);
_cairo_pattern_init_solid (&tmp, &combined, CAIRO_CONTENT_COLOR_ALPHA);
mask = NULL;
} else {
@ -1164,8 +1161,7 @@ _cairo_glitz_surface_fill_rectangles (void *abstract_dst,
_cairo_surface_create_similar_solid (&dst->base,
CAIRO_CONTENT_COLOR_ALPHA,
1, 1,
(cairo_color_t *) color,
NULL);
(cairo_color_t *) color);
if (src->base.status)
return src->base.status;

Просмотреть файл

@ -37,7 +37,7 @@
#ifndef CAIRO_GLITZ_H
#define CAIRO_GLITZ_H
#include <cairo.h>
#include "cairo.h"
#if CAIRO_HAS_GLITZ_SURFACE

Просмотреть файл

@ -64,7 +64,8 @@ static void
_cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t *gstate,
const cairo_glyph_t *glyphs,
int num_glyphs,
cairo_glyph_t *transformed_glyphs);
cairo_glyph_t *transformed_glyphs,
int *num_transformed_glyphs);
cairo_status_t
_cairo_gstate_init (cairo_gstate_t *gstate,
@ -203,47 +204,6 @@ _cairo_gstate_fini (cairo_gstate_t *gstate)
gstate->source = NULL;
}
static void
_cairo_gstate_destroy (cairo_gstate_t *gstate)
{
_cairo_gstate_fini (gstate);
free (gstate);
}
/**
* _cairo_gstate_clone:
* @other: a #cairo_gstate_t to be copied, not %NULL.
*
* Create a new #cairo_gstate_t setting all graphics state parameters
* to the same values as contained in @other. gstate->next will be set
* to %NULL and may be used by the caller to chain #cairo_gstate_t
* objects together.
*
* Return value: a new #cairo_gstate_t or %NULL if there is insufficient
* memory.
**/
static cairo_status_t
_cairo_gstate_clone (cairo_gstate_t *other, cairo_gstate_t **out)
{
cairo_status_t status;
cairo_gstate_t *gstate;
assert (other != NULL);
gstate = malloc (sizeof (cairo_gstate_t));
if (gstate == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
status = _cairo_gstate_init_copy (gstate, other);
if (status) {
free (gstate);
return status;
}
*out = gstate;
return CAIRO_STATUS_SUCCESS;
}
/**
* _cairo_gstate_save:
* @gstate: input/output gstate pointer
@ -253,14 +213,25 @@ _cairo_gstate_clone (cairo_gstate_t *other, cairo_gstate_t **out)
* copy into @gstate. _cairo_gstate_restore() reverses this.
**/
cairo_status_t
_cairo_gstate_save (cairo_gstate_t **gstate)
_cairo_gstate_save (cairo_gstate_t **gstate, cairo_gstate_t **freelist)
{
cairo_gstate_t *top = NULL;
cairo_gstate_t *top;
cairo_status_t status;
status = _cairo_gstate_clone (*gstate, &top);
if (status)
top = *freelist;
if (top == NULL) {
top = malloc (sizeof (cairo_gstate_t));
if (top == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} else
*freelist = top->next;
status = _cairo_gstate_init_copy (top, *gstate);
if (status) {
top->next = *freelist;
*freelist = top;
return status;
}
top->next = *gstate;
*gstate = top;
@ -275,7 +246,7 @@ _cairo_gstate_save (cairo_gstate_t **gstate)
* Reverses the effects of one _cairo_gstate_save() call.
**/
cairo_status_t
_cairo_gstate_restore (cairo_gstate_t **gstate)
_cairo_gstate_restore (cairo_gstate_t **gstate, cairo_gstate_t **freelist)
{
cairo_gstate_t *top;
@ -285,7 +256,9 @@ _cairo_gstate_restore (cairo_gstate_t **gstate)
*gstate = top->next;
_cairo_gstate_destroy (top);
_cairo_gstate_fini (top);
top->next = *freelist;
*freelist = top;
return CAIRO_STATUS_SUCCESS;
}
@ -822,8 +795,7 @@ _cairo_gstate_copy_transformed_pattern (cairo_gstate_t *gstate,
if (status)
return status;
_cairo_pattern_transform (pattern, ctm_inverse);
/* apply device_transform first so that it is transformed by ctm_inverse */
if (cairo_pattern_get_type (original) == CAIRO_PATTERN_TYPE_SURFACE) {
surface_pattern = (cairo_surface_pattern_t *) original;
surface = surface_pattern->surface;
@ -831,6 +803,8 @@ _cairo_gstate_copy_transformed_pattern (cairo_gstate_t *gstate,
_cairo_pattern_transform (pattern, &surface->device_transform);
}
_cairo_pattern_transform (pattern, ctm_inverse);
return CAIRO_STATUS_SUCCESS;
}
@ -1174,6 +1148,21 @@ _cairo_gstate_clip (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
gstate->antialias, gstate->target);
}
static cairo_status_t
_cairo_gstate_int_clip_extents (cairo_gstate_t *gstate,
cairo_rectangle_int_t *extents)
{
cairo_status_t status;
status = _cairo_surface_get_extents (gstate->target, extents);
if (status)
return status;
status = _cairo_clip_intersect_to_rectangle (&gstate->clip, extents);
return status;
}
cairo_status_t
_cairo_gstate_clip_extents (cairo_gstate_t *gstate,
double *x1,
@ -1184,11 +1173,7 @@ _cairo_gstate_clip_extents (cairo_gstate_t *gstate,
cairo_rectangle_int_t extents;
cairo_status_t status;
status = _cairo_surface_get_extents (gstate->target, &extents);
if (status)
return status;
status = _cairo_clip_intersect_to_rectangle (&gstate->clip, &extents);
status = _cairo_gstate_int_clip_extents (gstate, &extents);
if (status)
return status;
@ -1513,10 +1498,21 @@ _cairo_gstate_glyph_extents (cairo_gstate_t *gstate,
return cairo_scaled_font_status (gstate->scaled_font);
}
cairo_bool_t
_cairo_gstate_has_show_text_glyphs (cairo_gstate_t *gstate)
{
return _cairo_surface_has_show_text_glyphs (gstate->target);
}
cairo_status_t
_cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
const cairo_glyph_t *glyphs,
int num_glyphs)
_cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate,
const char *utf8,
int utf8_len,
const cairo_glyph_t *glyphs,
int num_glyphs,
const cairo_text_cluster_t *clusters,
int num_clusters,
cairo_bool_t backward)
{
cairo_status_t status;
cairo_pattern_union_t source_pattern;
@ -1543,18 +1539,57 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
}
_cairo_gstate_transform_glyphs_to_backend (gstate, glyphs, num_glyphs,
transformed_glyphs);
transformed_glyphs, &num_glyphs);
if (!num_glyphs)
goto CLEANUP_GLYPHS;
status = _cairo_gstate_copy_transformed_source (gstate, &source_pattern.base);
if (status)
goto CLEANUP_GLYPHS;
status = _cairo_surface_show_glyphs (gstate->target,
gstate->op,
&source_pattern.base,
transformed_glyphs,
num_glyphs,
gstate->scaled_font);
/* For really huge font sizes, we can just do path;fill instead of
* show_glyphs, as show_glyphs would put excess pressure on the cache,
* and moreover, not all components below us correctly handle huge font
* sizes. I wanted to set the limit at 256. But alas, seems like cairo's
* rasterizer is something like ten times slower than freetype's for huge
* sizes. So, no win just yet. For now, do it for insanely-huge sizes,
* just to make sure we don't make anyone unhappy. When we get a really
* fast rasterizer in cairo, we may want to readjust this.
*
* Needless to say, do this only if show_text_glyphs is not available. */
if (_cairo_gstate_has_show_text_glyphs (gstate) ||
_cairo_scaled_font_get_max_scale (gstate->scaled_font) <= 10240) {
status = _cairo_surface_show_text_glyphs (gstate->target,
gstate->op,
&source_pattern.base,
utf8, utf8_len,
transformed_glyphs, num_glyphs,
clusters, num_clusters,
backward,
gstate->scaled_font);
} else {
cairo_path_fixed_t path;
_cairo_path_fixed_init (&path);
CAIRO_MUTEX_LOCK (gstate->scaled_font->mutex);
status = _cairo_scaled_font_glyph_path (gstate->scaled_font,
transformed_glyphs, num_glyphs,
&path);
CAIRO_MUTEX_UNLOCK (gstate->scaled_font->mutex);
if (status == CAIRO_STATUS_SUCCESS)
status = _cairo_surface_fill (gstate->target,
gstate->op,
&source_pattern.base,
&path,
CAIRO_FILL_RULE_WINDING,
gstate->tolerance,
gstate->scaled_font->options.antialias);
_cairo_path_fixed_fini (&path);
}
_cairo_pattern_fini (&source_pattern.base);
@ -1587,7 +1622,7 @@ _cairo_gstate_glyph_path (cairo_gstate_t *gstate,
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
_cairo_gstate_transform_glyphs_to_backend (gstate, glyphs, num_glyphs,
transformed_glyphs);
transformed_glyphs, NULL);
CAIRO_MUTEX_LOCK (gstate->scaled_font->mutex);
status = _cairo_scaled_font_glyph_path (gstate->scaled_font,
@ -1623,39 +1658,99 @@ _cairo_gstate_get_antialias (cairo_gstate_t *gstate)
* @num_glyphs: the number of elements in @glyphs
* @transformed_glyphs: a pre-allocated array of at least @num_glyphs
* #cairo_glyph_t objects
* @num_transformed_glyphs: the number of elements in @transformed_glyphs
* after dropping out of bounds glyphs, or %NULL if glyphs shouldn't be
* dropped
*
* Transform an array of glyphs to backend space by first adding the offset
* of the font matrix, then transforming from user space to backend space.
* The result of the transformation is placed in @transformed_glyphs.
*
* This also uses information from the scaled font and the surface to
* cull/drop glyphs that will not be visible.
**/
static void
_cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t *gstate,
const cairo_glyph_t *glyphs,
int num_glyphs,
cairo_glyph_t *transformed_glyphs)
cairo_glyph_t *transformed_glyphs,
int *num_transformed_glyphs)
{
int i;
int i, j;
cairo_matrix_t *ctm = &gstate->ctm;
cairo_matrix_t *font_matrix = &gstate->font_matrix;
cairo_matrix_t *device_transform = &gstate->target->device_transform;
cairo_bool_t drop = FALSE;
double x1 = 0, x2 = 0, y1 = 0, y2 = 0;
if (num_transformed_glyphs != NULL) {
cairo_rectangle_int_t surface_extents;
double scale = _cairo_scaled_font_get_max_scale (gstate->scaled_font);
drop = TRUE;
if (_cairo_gstate_int_clip_extents (gstate, &surface_extents))
drop = FALSE; /* unbounded surface */
else {
if (surface_extents.width == 0 || surface_extents.height == 0) {
/* No visible area. Don't draw anything */
*num_transformed_glyphs = 0;
return;
}
/* XXX We currently drop any glyphs that has its position outside
* of the surface boundaries by a safety margin depending on the
* font scale. This however can fail in extreme cases where the
* font has really long swashes for example... We can correctly
* handle that by looking the glyph up and using its device bbox
* to device if it's going to be visible, but I'm not inclined to
* do that now.
*/
x1 = surface_extents.x - 2*scale;
y1 = surface_extents.y - 2*scale;
x2 = surface_extents.x + surface_extents.width + scale;
y2 = surface_extents.y + surface_extents.height + scale;
}
if (!drop)
*num_transformed_glyphs = num_glyphs;
} else
num_transformed_glyphs = &j;
#define KEEP_GLYPH(glyph) (x1 <= glyph.x && glyph.x <= x2 && y1 <= glyph.y && glyph.y <= y2)
if (_cairo_matrix_is_identity (ctm) &&
_cairo_matrix_is_identity (device_transform) &&
gstate->font_matrix.x0 == 0 && gstate->font_matrix.y0 == 0)
font_matrix->x0 == 0 && font_matrix->y0 == 0)
{
memcpy (transformed_glyphs, glyphs, num_glyphs * sizeof (cairo_glyph_t));
if (!drop)
memcpy (transformed_glyphs, glyphs, num_glyphs * sizeof (cairo_glyph_t));
else {
for (j = 0, i = 0; i < num_glyphs; i++)
{
transformed_glyphs[j].index = glyphs[i].index;
transformed_glyphs[j].x = glyphs[i].x;
transformed_glyphs[j].y = glyphs[i].y;
if (KEEP_GLYPH (transformed_glyphs[j]))
j++;
}
*num_transformed_glyphs = j;
}
}
else if (_cairo_matrix_is_translation (ctm) &&
_cairo_matrix_is_translation (device_transform))
{
double tx = gstate->font_matrix.x0 + ctm->x0 + device_transform->x0;
double ty = gstate->font_matrix.y0 + ctm->y0 + device_transform->y0;
double tx = font_matrix->x0 + ctm->x0 + device_transform->x0;
double ty = font_matrix->y0 + ctm->y0 + device_transform->y0;
for (i = 0; i < num_glyphs; i++)
for (j = 0, i = 0; i < num_glyphs; i++)
{
transformed_glyphs[i].index = glyphs[i].index;
transformed_glyphs[i].x = glyphs[i].x + tx;
transformed_glyphs[i].y = glyphs[i].y + ty;
transformed_glyphs[j].index = glyphs[i].index;
transformed_glyphs[j].x = glyphs[i].x + tx;
transformed_glyphs[j].y = glyphs[i].y + ty;
if (!drop || KEEP_GLYPH (transformed_glyphs[j]))
j++;
}
*num_transformed_glyphs = j;
}
else
{
@ -1669,12 +1764,15 @@ _cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t *gstate,
cairo_matrix_multiply (&aggregate_transform,
&aggregate_transform, device_transform);
for (i = 0; i < num_glyphs; i++)
for (j = 0, i = 0; i < num_glyphs; i++)
{
transformed_glyphs[i] = glyphs[i];
transformed_glyphs[j] = glyphs[i];
cairo_matrix_transform_point (&aggregate_transform,
&transformed_glyphs[i].x,
&transformed_glyphs[i].y);
&transformed_glyphs[j].x,
&transformed_glyphs[j].y);
if (!drop || KEEP_GLYPH (transformed_glyphs[j]))
j++;
}
*num_transformed_glyphs = j;
}
}

Просмотреть файл

@ -296,7 +296,7 @@ _cairo_hash_table_lookup_internal (cairo_hash_table_t *hash_table,
* size.
*
* Return value: %CAIRO_STATUS_SUCCESS if successful or
* CAIRO_STATUS_NO_MEMORY if out of memory.
* %CAIRO_STATUS_NO_MEMORY if out of memory.
**/
static cairo_status_t
_cairo_hash_table_resize (cairo_hash_table_t *hash_table)
@ -401,7 +401,7 @@ _cairo_hash_table_lookup (cairo_hash_table_t *hash_table,
*
* Return value: a random live entry or %NULL if there are no entries
* that match the given predicate. In particular, if predicate is
* NULL, a %NULL return value indicates that the table is empty.
* %NULL, a %NULL return value indicates that the table is empty.
**/
void *
_cairo_hash_table_random_entry (cairo_hash_table_t *hash_table,
@ -459,7 +459,7 @@ _cairo_hash_table_random_entry (cairo_hash_table_t *hash_table,
* necessary, use _cairo_hash_table_remove first.
*
* Return value: %CAIRO_STATUS_SUCCESS if successful or
* CAIRO_STATUS_NO_MEMORY if insufficient memory is available.
* %CAIRO_STATUS_NO_MEMORY if insufficient memory is available.
**/
cairo_status_t
_cairo_hash_table_insert (cairo_hash_table_t *hash_table,
@ -504,7 +504,7 @@ _cairo_hash_table_insert (cairo_hash_table_t *hash_table,
* _cairo_hash_table_create).
*
* Return value: %CAIRO_STATUS_SUCCESS if successful or
* CAIRO_STATUS_NO_MEMORY if out of memory.
* %CAIRO_STATUS_NO_MEMORY if out of memory.
**/
void
_cairo_hash_table_remove (cairo_hash_table_t *hash_table,

Просмотреть файл

@ -36,22 +36,20 @@
#include "cairoint.h"
typedef struct cairo_hull
{
typedef struct cairo_hull {
cairo_point_t point;
cairo_slope_t slope;
int discard;
int id;
} cairo_hull_t;
static cairo_status_t
_cairo_hull_create (cairo_pen_vertex_t *vertices,
int num_vertices,
cairo_hull_t **out)
static void
_cairo_hull_init (cairo_hull_t *hull,
cairo_pen_vertex_t *vertices,
int num_vertices)
{
int i;
cairo_hull_t *hull;
cairo_point_t *p, *extremum, tmp;
int i;
extremum = &vertices[0].point;
for (i = 1; i < num_vertices; i++) {
@ -64,10 +62,6 @@ _cairo_hull_create (cairo_pen_vertex_t *vertices,
*extremum = vertices[0].point;
vertices[0].point = tmp;
hull = _cairo_malloc_ab (num_vertices, sizeof (cairo_hull_t));
if (hull == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
for (i = 0; i < num_vertices; i++) {
hull[i].point = vertices[i].point;
_cairo_slope_init (&hull[i].slope, &hull[0].point, &hull[i].point);
@ -82,9 +76,6 @@ _cairo_hull_create (cairo_pen_vertex_t *vertices,
if (i != 0 && hull[i].slope.dx == 0 && hull[i].slope.dy == 0)
hull[i].discard = 1;
}
*out = hull;
return CAIRO_STATUS_SUCCESS;
}
static int
@ -196,13 +187,19 @@ _cairo_hull_to_pen (cairo_hull_t *hull, cairo_pen_vertex_t *vertices, int *num_v
cairo_status_t
_cairo_hull_compute (cairo_pen_vertex_t *vertices, int *num_vertices)
{
cairo_status_t status;
cairo_hull_t *hull = NULL;
cairo_hull_t hull_stack[CAIRO_STACK_ARRAY_LENGTH (cairo_hull_t)];
cairo_hull_t *hull;
int num_hull = *num_vertices;
status = _cairo_hull_create (vertices, num_hull, &hull);
if (status)
return status;
if (num_hull > ARRAY_LENGTH (hull_stack)) {
hull = _cairo_malloc_ab (num_hull, sizeof (cairo_hull_t));
if (hull == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} else {
hull = hull_stack;
}
_cairo_hull_init (hull, vertices, num_hull);
qsort (hull + 1, num_hull - 1,
sizeof (cairo_hull_t), _cairo_hull_vertex_compare);
@ -211,7 +208,8 @@ _cairo_hull_compute (cairo_pen_vertex_t *vertices, int *num_vertices)
_cairo_hull_to_pen (hull, vertices, num_vertices);
free (hull);
if (hull != hull_stack)
free (hull);
return CAIRO_STATUS_SUCCESS;
}

Просмотреть файл

@ -124,7 +124,7 @@ _cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image,
if (surface == NULL)
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
_cairo_surface_init (&surface->base, &cairo_image_surface_backend,
_cairo_surface_init (&surface->base, &_cairo_image_surface_backend,
_cairo_content_from_pixman_format (pixman_format));
surface->pixman_image = pixman_image;
@ -392,7 +392,8 @@ _cairo_image_surface_create_with_content (cairo_content_t content,
* stride = cairo_format_stride_for_width (format, width);
* data = malloc (stride * height);
* surface = cairo_image_surface_create_for_data (data, format,
* width, height);
* width, height,
* stride);
* </programlisting></informalexample>
*
* Return value: the appropriate stride to use given the desired
@ -1192,7 +1193,7 @@ _cairo_image_surface_set_clip_region (void *abstract_surface,
{
cairo_image_surface_t *surface = (cairo_image_surface_t *) abstract_surface;
if (! pixman_image_set_clip_region (surface->pixman_image, &region->rgn))
if (! pixman_image_set_clip_region32 (surface->pixman_image, &region->rgn))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
surface->has_clip = region != NULL;
@ -1246,10 +1247,10 @@ _cairo_image_surface_reset (void *abstract_surface)
cairo_bool_t
_cairo_surface_is_image (const cairo_surface_t *surface)
{
return surface->backend == &cairo_image_surface_backend;
return surface->backend == &_cairo_image_surface_backend;
}
const cairo_surface_backend_t cairo_image_surface_backend = {
const cairo_surface_backend_t _cairo_image_surface_backend = {
CAIRO_SURFACE_TYPE_IMAGE,
_cairo_image_surface_create_similar,
_cairo_image_surface_finish,

Просмотреть файл

@ -82,7 +82,7 @@ _lzw_buf_init (lzw_buf_t *buf, int size)
/* Increase the buffer size by doubling.
*
* Returns %CAIRO_STATUS_SUCCESS or CAIRO_STATUS_NO_MEMORY
* Returns %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY
*/
static cairo_status_t
_lzw_buf_grow (lzw_buf_t *buf)

Просмотреть файл

@ -423,6 +423,18 @@ _cairo_matrix_transform_bounding_box (const cairo_matrix_t *matrix,
}
}
cairo_private void
_cairo_matrix_transform_bounding_box_fixed (const cairo_matrix_t *matrix,
cairo_box_t *bbox,
cairo_bool_t *is_tight)
{
double x1, y1, x2, y2;
_cairo_box_to_doubles (bbox, &x1, &y1, &x2, &y2);
_cairo_matrix_transform_bounding_box (matrix, &x1, &y1, &x2, &y2, is_tight);
_cairo_box_from_doubles (bbox, &x1, &y1, &x2, &y2);
}
static void
_cairo_matrix_scalar_multiply (cairo_matrix_t *matrix, double scalar)
{
@ -478,10 +490,10 @@ cairo_matrix_invert (cairo_matrix_t *matrix)
_cairo_matrix_compute_determinant (matrix, &det);
if (det == 0)
if (! ISFINITE (det))
return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
if (! ISFINITE (det))
if (det == 0)
return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
_cairo_matrix_compute_adjoint (matrix);
@ -498,7 +510,7 @@ _cairo_matrix_is_invertible (const cairo_matrix_t *matrix)
_cairo_matrix_compute_determinant (matrix, &det);
return det != 0. && ISFINITE (det);
return ISFINITE (det) && det != 0.;
}
void
@ -713,6 +725,10 @@ _cairo_matrix_is_integer_translation (const cairo_matrix_t *matrix,
(Note that the minor axis length is at the minimum of the above solution,
which is just sqrt ( f - sqrt(g² + h²) ) given the symmetry of (D)).
For another derivation of the same result, using Singular Value Decomposition,
see doc/tutorial/src/singular.c.
*/
/* determine the length of the major axis of a circle of the given radius

Просмотреть файл

@ -46,7 +46,7 @@ typedef enum {
CAIRO_COMMAND_MASK,
CAIRO_COMMAND_STROKE,
CAIRO_COMMAND_FILL,
CAIRO_COMMAND_SHOW_GLYPHS,
CAIRO_COMMAND_SHOW_TEXT_GLYPHS,
/* Other junk. For most of these, we should be able to assert that
* they never get called except as part of fallbacks for the 5
@ -104,14 +104,19 @@ typedef struct _cairo_command_fill {
cairo_antialias_t antialias;
} cairo_command_fill_t;
typedef struct _cairo_command_show_glyphs {
typedef struct _cairo_command_show_text_glyphs {
cairo_command_header_t header;
cairo_operator_t op;
cairo_pattern_union_t source;
char *utf8;
int utf8_len;
cairo_glyph_t *glyphs;
unsigned int num_glyphs;
cairo_text_cluster_t *clusters;
int num_clusters;
cairo_bool_t backward;
cairo_scaled_font_t *scaled_font;
} cairo_command_show_glyphs_t;
} cairo_command_show_text_glyphs_t;
typedef struct _cairo_command_intersect_clip_path {
cairo_command_header_t header;
@ -130,7 +135,7 @@ typedef union _cairo_command {
cairo_command_mask_t mask;
cairo_command_stroke_t stroke;
cairo_command_fill_t fill;
cairo_command_show_glyphs_t show_glyphs;
cairo_command_show_text_glyphs_t show_text_glyphs;
/* The other junk. */
cairo_command_intersect_clip_path_t intersect_clip_path;
@ -159,6 +164,10 @@ _cairo_meta_surface_create (cairo_content_t content,
int width_pixels,
int height_pixels);
cairo_private cairo_int_status_t
_cairo_meta_surface_get_path (cairo_surface_t *surface,
cairo_path_fixed_t *path);
cairo_private cairo_status_t
_cairo_meta_surface_replay (cairo_surface_t *surface,
cairo_surface_t *target);

Просмотреть файл

@ -39,7 +39,7 @@
/* A meta surface is a surface that records all drawing operations at
* the highest level of the surface backend interface, (that is, the
* level of paint, mask, stroke, fill, and show_glyphs). The meta
* level of paint, mask, stroke, fill, and show_text_glyphs). The meta
* surface can then be "replayed" against any target surface with:
*
* _cairo_meta_surface_replay (meta, target);
@ -157,10 +157,12 @@ _cairo_meta_surface_finish (void *abstract_surface)
free (command);
break;
case CAIRO_COMMAND_SHOW_GLYPHS:
_cairo_pattern_fini (&command->show_glyphs.source.base);
free (command->show_glyphs.glyphs);
cairo_scaled_font_destroy (command->show_glyphs.scaled_font);
case CAIRO_COMMAND_SHOW_TEXT_GLYPHS:
_cairo_pattern_fini (&command->show_text_glyphs.source.base);
free (command->show_text_glyphs.utf8);
free (command->show_text_glyphs.glyphs);
free (command->show_text_glyphs.clusters);
cairo_scaled_font_destroy (command->show_text_glyphs.scaled_font);
free (command);
break;
@ -426,23 +428,34 @@ _cairo_meta_surface_fill (void *abstract_surface,
return status;
}
static cairo_bool_t
_cairo_meta_surface_has_show_text_glyphs (void *abstract_surface)
{
return TRUE;
}
static cairo_int_status_t
_cairo_meta_surface_show_glyphs (void *abstract_surface,
cairo_operator_t op,
cairo_pattern_t *source,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font)
_cairo_meta_surface_show_text_glyphs (void *abstract_surface,
cairo_operator_t op,
cairo_pattern_t *source,
const char *utf8,
int utf8_len,
cairo_glyph_t *glyphs,
int num_glyphs,
const cairo_text_cluster_t *clusters,
int num_clusters,
cairo_bool_t backward,
cairo_scaled_font_t *scaled_font)
{
cairo_status_t status;
cairo_meta_surface_t *meta = abstract_surface;
cairo_command_show_glyphs_t *command;
cairo_command_show_text_glyphs_t *command;
command = malloc (sizeof (cairo_command_show_glyphs_t));
command = malloc (sizeof (cairo_command_show_text_glyphs_t));
if (command == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
command->header.type = CAIRO_COMMAND_SHOW_GLYPHS;
command->header.type = CAIRO_COMMAND_SHOW_TEXT_GLYPHS;
command->header.region = CAIRO_META_REGION_ALL;
command->op = op;
@ -450,14 +463,39 @@ _cairo_meta_surface_show_glyphs (void *abstract_surface,
if (status)
goto CLEANUP_COMMAND;
command->glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
if (command->glyphs == NULL) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto CLEANUP_SOURCE;
}
memcpy (command->glyphs, glyphs, sizeof (cairo_glyph_t) * num_glyphs);
command->utf8 = NULL;
command->utf8_len = utf8_len;
command->glyphs = NULL;
command->num_glyphs = num_glyphs;
command->clusters = NULL;
command->num_clusters = num_clusters;
if (utf8_len) {
command->utf8 = malloc (utf8_len);
if (command->utf8 == NULL) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto CLEANUP_ARRAYS;
}
memcpy (command->utf8, utf8, utf8_len);
}
if (num_glyphs) {
command->glyphs = _cairo_malloc_ab (num_glyphs, sizeof (glyphs[0]));
if (command->glyphs == NULL) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto CLEANUP_ARRAYS;
}
memcpy (command->glyphs, glyphs, sizeof (glyphs[0]) * num_glyphs);
}
if (num_clusters) {
command->clusters = _cairo_malloc_ab (num_clusters, sizeof (clusters[0]));
if (command->clusters == NULL) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto CLEANUP_ARRAYS;
}
memcpy (command->clusters, clusters, sizeof (clusters[0]) * num_clusters);
}
command->backward = backward;
command->scaled_font = cairo_scaled_font_reference (scaled_font);
@ -469,8 +507,11 @@ _cairo_meta_surface_show_glyphs (void *abstract_surface,
CLEANUP_SCALED_FONT:
cairo_scaled_font_destroy (command->scaled_font);
CLEANUP_ARRAYS:
free (command->utf8);
free (command->glyphs);
CLEANUP_SOURCE:
free (command->clusters);
_cairo_pattern_fini (&command->source.base);
CLEANUP_COMMAND:
free (command);
@ -485,7 +526,7 @@ _cairo_meta_surface_show_glyphs (void *abstract_surface,
* surface-modifying function on the result of this function.
*
* The caller owns the return value and should call
* cairo_surface_destroy when finished with it. This function will not
* cairo_surface_destroy() when finished with it. This function will not
* return %NULL, but will return a nil surface instead.
*
* Return value: The snapshot surface.
@ -570,6 +611,9 @@ _cairo_meta_surface_get_extents (void *abstract_surface,
{
cairo_meta_surface_t *surface = abstract_surface;
if (surface->width_pixels == -1 && surface->height_pixels == -1)
return CAIRO_INT_STATUS_UNSUPPORTED;
rectangle->x = 0;
rectangle->y = 0;
rectangle->width = surface->width_pixels;
@ -618,15 +662,24 @@ static const cairo_surface_backend_t cairo_meta_surface_backend = {
/* Here are the 5 basic drawing operations, (which are in some
* sense the only things that cairo_meta_surface should need to
* implement). */
* implement). However, we implement the more generic show_text_glyphs
* instead of show_glyphs. One or the other is eough. */
_cairo_meta_surface_paint,
_cairo_meta_surface_mask,
_cairo_meta_surface_stroke,
_cairo_meta_surface_fill,
_cairo_meta_surface_show_glyphs,
NULL,
_cairo_meta_surface_snapshot
_cairo_meta_surface_snapshot,
NULL, /* is_similar */
NULL, /* reset */
NULL, /* fill_stroke */
NULL, /* create_solid_pattern_surface */
_cairo_meta_surface_has_show_text_glyphs,
_cairo_meta_surface_show_text_glyphs
};
static cairo_path_fixed_t *
@ -635,7 +688,7 @@ _cairo_command_get_path (cairo_command_t *command)
switch (command->header.type) {
case CAIRO_COMMAND_PAINT:
case CAIRO_COMMAND_MASK:
case CAIRO_COMMAND_SHOW_GLYPHS:
case CAIRO_COMMAND_SHOW_TEXT_GLYPHS:
return NULL;
case CAIRO_COMMAND_STROKE:
return &command->stroke.path;
@ -649,6 +702,78 @@ _cairo_command_get_path (cairo_command_t *command)
return NULL;
}
cairo_int_status_t
_cairo_meta_surface_get_path (cairo_surface_t *surface,
cairo_path_fixed_t *path)
{
cairo_meta_surface_t *meta;
cairo_command_t *command, **elements;
int i, num_elements;
cairo_int_status_t status;
if (surface->status)
return surface->status;
meta = (cairo_meta_surface_t *) surface;
status = CAIRO_STATUS_SUCCESS;
num_elements = meta->commands.num_elements;
elements = _cairo_array_index (&meta->commands, 0);
for (i = meta->replay_start_idx; i < num_elements; i++) {
command = elements[i];
switch (command->header.type) {
case CAIRO_COMMAND_PAINT:
case CAIRO_COMMAND_MASK:
case CAIRO_COMMAND_INTERSECT_CLIP_PATH:
status = CAIRO_INT_STATUS_UNSUPPORTED;
break;
case CAIRO_COMMAND_STROKE:
{
cairo_traps_t traps;
_cairo_traps_init (&traps);
/* XXX call cairo_stroke_to_path() when that is implemented */
status = _cairo_path_fixed_stroke_to_traps (&command->stroke.path,
&command->stroke.style,
&command->stroke.ctm,
&command->stroke.ctm_inverse,
command->stroke.tolerance,
&traps);
if (status == CAIRO_STATUS_SUCCESS)
status = _cairo_traps_path (&traps, path);
_cairo_traps_fini (&traps);
break;
}
case CAIRO_COMMAND_FILL:
{
status = _cairo_path_fixed_append (path, &command->fill.path, CAIRO_DIRECTION_FORWARD);
break;
}
case CAIRO_COMMAND_SHOW_TEXT_GLYPHS:
{
status = _cairo_scaled_font_glyph_path (command->show_text_glyphs.scaled_font,
command->show_text_glyphs.glyphs,
command->show_text_glyphs.num_glyphs,
path);
break;
}
default:
ASSERT_NOT_REACHED;
}
if (status)
break;
}
return _cairo_surface_set_error (surface, status);
}
static cairo_status_t
_cairo_meta_surface_replay_internal (cairo_surface_t *surface,
cairo_surface_t *target,
@ -699,7 +824,7 @@ _cairo_meta_surface_replay_internal (cairo_surface_t *surface,
status = _cairo_path_fixed_init_copy (&path_copy, dev_path);
if (status)
break;
_cairo_path_fixed_device_transform (&path_copy, device_transform);
_cairo_path_fixed_transform (&path_copy, device_transform);
dev_path = &path_copy;
}
@ -798,13 +923,13 @@ _cairo_meta_surface_replay_internal (cairo_surface_t *surface,
command->fill.antialias);
break;
}
case CAIRO_COMMAND_SHOW_GLYPHS:
case CAIRO_COMMAND_SHOW_TEXT_GLYPHS:
{
cairo_glyph_t *glyphs = command->show_glyphs.glyphs;
cairo_glyph_t *glyphs = command->show_text_glyphs.glyphs;
cairo_glyph_t *dev_glyphs;
int i, num_glyphs = command->show_glyphs.num_glyphs;
int i, num_glyphs = command->show_text_glyphs.num_glyphs;
/* show_glyphs is special because _cairo_surface_show_glyphs is allowed
/* show_text_glyphs is special because _cairo_surface_show_text_glyphs is allowed
* to modify the glyph array that's passed in. We must always
* copy the array before handing it to the backend.
*/
@ -825,11 +950,14 @@ _cairo_meta_surface_replay_internal (cairo_surface_t *surface,
memcpy (dev_glyphs, glyphs, sizeof (cairo_glyph_t) * num_glyphs);
}
status = _cairo_surface_show_glyphs (target,
command->show_glyphs.op,
&command->show_glyphs.source.base,
dev_glyphs, num_glyphs,
command->show_glyphs.scaled_font);
status = _cairo_surface_show_text_glyphs (target,
command->show_text_glyphs.op,
&command->show_text_glyphs.source.base,
command->show_text_glyphs.utf8, command->show_text_glyphs.utf8_len,
dev_glyphs, num_glyphs,
command->show_text_glyphs.clusters, command->show_text_glyphs.num_clusters,
command->show_text_glyphs.backward,
command->show_text_glyphs.scaled_font);
free (dev_glyphs);
break;
@ -887,7 +1015,7 @@ _cairo_meta_surface_replay (cairo_surface_t *surface,
/* Replay meta to surface. When the return status of each operation is
* one of %CAIRO_STATUS_SUCCESS, %CAIRO_INT_STATUS_UNSUPPORTED, or
* CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY the status of each operation
* %CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY the status of each operation
* will be stored in the meta surface. Any other status will abort the
* replay and return the status.
*/

Просмотреть файл

@ -38,6 +38,8 @@
#include "cairoint.h"
COMPILE_TIME_ASSERT (CAIRO_STATUS_LAST_STATUS < CAIRO_INT_STATUS_UNSUPPORTED);
COMPILE_TIME_ASSERT (CAIRO_INT_STATUS_LAST_STATUS <= 127);
/**
* cairo_status_to_string:
@ -101,6 +103,16 @@ cairo_status_to_string (cairo_status_t status)
return "error creating or writing to a temporary file";
case CAIRO_STATUS_INVALID_STRIDE:
return "invalid value for stride";
case CAIRO_STATUS_FONT_TYPE_MISMATCH:
return "the font type is not appropriate for the operation";
case CAIRO_STATUS_USER_FONT_IMMUTABLE:
return "the user-font is immutable";
case CAIRO_STATUS_USER_FONT_ERROR:
return "error occurred in a user-font callback function";
case CAIRO_STATUS_NEGATIVE_COUNT:
return "negative number used where it is not allowed";
case CAIRO_STATUS_INVALID_CLUSTERS:
return "input clusters do not represent the accompanying text and glyph arrays";
}
return "<unknown error status>";

Просмотреть файл

@ -0,0 +1,226 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
* Copyright © 2005,2007 Red Hat, Inc.
* Copyright © 2007 Mathias Hasselmann
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
* Mathias Hasselmann <mathias.hasselmann@gmx.de>
* Behdad Esfahbod <behdad@behdad.org>
*/
#ifndef CAIRO_MUTEX_IMPL_PRIVATE_H
#define CAIRO_MUTEX_IMPL_PRIVATE_H
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include "cairo-features.h"
CAIRO_BEGIN_DECLS
/* A fully qualified no-operation statement */
#define CAIRO_MUTEX_IMPL_NOOP do {/*no-op*/} while (0)
/* And one that evaluates it's argument once */
#define CAIRO_MUTEX_IMPL_NOOP1(expr) do { if (expr) ; } while (0)
/* Cairo mutex implementation:
*
* Any new mutex implementation needs to do the following:
*
* - Condition on the right header or feature. Headers are
* preferred as eg. you still can use win32 mutex implementation
* on a win32 system even if you do not compile the win32
* surface/backend.
*
* - typedef #cairo_mutex_impl_t to the proper mutex type on your target
* system. Note that you may or may not need to use a pointer,
* depending on what kinds of initialization your mutex
* implementation supports. No trailing semicolon needed.
* You should be able to compile the following snippet (don't try
* running it):
*
* <programlisting>
* cairo_mutex_impl_t _cairo_some_mutex;
* </programlisting>
*
* - #define CAIRO_MUTEX_IMPL_LOCK(mutex) and CAIRO_MUTEX_IMPL_UNLOCK(mutex) to
* proper statement to lock/unlock the mutex object passed in.
* You can (and should) assume that the mutex is already
* initialized, and is-not-already-locked/is-locked,
* respectively. Use the "do { ... } while (0)" idiom if necessary.
* No trailing semicolons are needed (in any macro you define here).
* You should be able to compile the following snippet:
*
* <programlisting>
* cairo_mutex_impl_t _cairo_some_mutex;
*
* if (1)
* CAIRO_MUTEX_IMPL_LOCK (_cairo_some_mutex);
* else
* CAIRO_MUTEX_IMPL_UNLOCK (_cairo_some_mutex);
* </programlisting>
*
* - #define %CAIRO_MUTEX_IMPL_NIL_INITIALIZER to something that can
* initialize the #cairo_mutex_impl_t type you defined. Most of the
* time one of 0, %NULL, or {} works. At this point
* you should be able to compile the following snippet:
*
* <programlisting>
* cairo_mutex_impl_t _cairo_some_mutex = CAIRO_MUTEX_IMPL_NIL_INITIALIZER;
*
* if (1)
* CAIRO_MUTEX_IMPL_LOCK (_cairo_some_mutex);
* else
* CAIRO_MUTEX_IMPL_UNLOCK (_cairo_some_mutex);
* </programlisting>
*
* - If the above code is not enough to initialize a mutex on
* your platform, #define CAIRO_MUTEX_IMPL_INIT(mutex) to statement
* to initialize the mutex (allocate resources, etc). Such that
* you should be able to compile AND RUN the following snippet:
*
* <programlisting>
* cairo_mutex_impl_t _cairo_some_mutex = CAIRO_MUTEX_IMPL_NIL_INITIALIZER;
*
* CAIRO_MUTEX_IMPL_INIT (_cairo_some_mutex);
*
* if (1)
* CAIRO_MUTEX_IMPL_LOCK (_cairo_some_mutex);
* else
* CAIRO_MUTEX_IMPL_UNLOCK (_cairo_some_mutex);
* </programlisting>
*
* - If you define CAIRO_MUTEX_IMPL_INIT(mutex), cairo will use it to
* initialize all static mutex'es. If for any reason that should
* not happen (eg. %CAIRO_MUTEX_IMPL_INIT is just a faster way than
* what cairo does using %CAIRO_MUTEX_IMPL_NIL_INITIALIZER), then
* <programlisting>
* #define CAIRO_MUTEX_IMPL_INITIALIZE() CAIRO_MUTEX_IMPL_NOOP
* </programlisting>
*
* - If your system supports freeing a mutex object (deallocating
* resources, etc), then #define CAIRO_MUTEX_IMPL_FINI(mutex) to do
* that.
*
* - If you define CAIRO_MUTEX_IMPL_FINI(mutex), cairo will use it to
* define a finalizer function to finalize all static mutex'es.
* However, it's up to you to call CAIRO_MUTEX_IMPL_FINALIZE() at
* proper places, eg. when the system is unloading the cairo library.
* So, if for any reason finalizing static mutex'es is not needed
* (eg. you never call CAIRO_MUTEX_IMPL_FINALIZE()), then
* <programlisting>
* #define CAIRO_MUTEX_IMPL_FINALIZE() CAIRO_MUTEX_IMPL_NOOP
* </programlisting>
*
* - That is all. If for any reason you think the above API is
* not enough to implement #cairo_mutex_impl_t on your system, please
* stop and write to the cairo mailing list about it. DO NOT
* poke around cairo-mutex-private.h for possible solutions.
*/
#ifndef CAIRO_MUTEX_TYPE_PRIVATE_H
#error "Do not include cairo-mutex-impl-private.h directly. Include cairo-mutex-type-private.h instead."
#endif
#if CAIRO_NO_MUTEX
/* No mutexes */
typedef int cairo_mutex_impl_t;
# define CAIRO_MUTEX_IMPL_INITIALIZE() CAIRO_MUTEX_IMPL_NOOP
# define CAIRO_MUTEX_IMPL_LOCK(mutex) CAIRO_MUTEX_IMPL_NOOP1(mutex)
# define CAIRO_MUTEX_IMPL_UNLOCK(mutex) CAIRO_MUTEX_IMPL_NOOP1(mutex)
# define CAIRO_MUTEX_IMPL_NIL_INITIALIZER 0
#elif HAVE_PTHREAD_H /*******************************************************/
# include <pthread.h>
typedef pthread_mutex_t cairo_mutex_impl_t;
# define CAIRO_MUTEX_IMPL_LOCK(mutex) pthread_mutex_lock (&(mutex))
# define CAIRO_MUTEX_IMPL_UNLOCK(mutex) pthread_mutex_unlock (&(mutex))
# define CAIRO_MUTEX_IMPL_FINI(mutex) pthread_mutex_destroy (&(mutex))
# define CAIRO_MUTEX_IMPL_FINALIZE() CAIRO_MUTEX_IMPL_NOOP
# define CAIRO_MUTEX_IMPL_NIL_INITIALIZER PTHREAD_MUTEX_INITIALIZER
#elif HAVE_WINDOWS_H /*******************************************************/
# include <windows.h>
typedef CRITICAL_SECTION cairo_mutex_impl_t;
# define CAIRO_MUTEX_IMPL_LOCK(mutex) EnterCriticalSection (&(mutex))
# define CAIRO_MUTEX_IMPL_UNLOCK(mutex) LeaveCriticalSection (&(mutex))
# define CAIRO_MUTEX_IMPL_INIT(mutex) InitializeCriticalSection (&(mutex))
# define CAIRO_MUTEX_IMPL_FINI(mutex) DeleteCriticalSection (&(mutex))
# define CAIRO_MUTEX_IMPL_NIL_INITIALIZER { NULL, 0, 0, NULL, NULL, 0 }
#elif defined __OS2__ /******************************************************/
# define INCL_BASE
# define INCL_PM
# include <os2.h>
typedef HMTX cairo_mutex_impl_t;
# define CAIRO_MUTEX_IMPL_LOCK(mutex) DosRequestMutexSem(mutex, SEM_INDEFINITE_WAIT)
# define CAIRO_MUTEX_IMPL_UNLOCK(mutex) DosReleaseMutexSem(mutex)
# define CAIRO_MUTEX_IMPL_INIT(mutex) DosCreateMutexSem (NULL, &(mutex), 0L, FALSE)
# define CAIRO_MUTEX_IMPL_FINI(mutex) DosCloseMutexSem (mutex)
# define CAIRO_MUTEX_IMPL_NIL_INITIALIZER 0
#elif CAIRO_HAS_BEOS_SURFACE /***********************************************/
typedef BLocker* cairo_mutex_impl_t;
# define CAIRO_MUTEX_IMPL_LOCK(mutex) (mutex)->Lock()
# define CAIRO_MUTEX_IMPL_UNLOCK(mutex) (mutex)->Unlock()
# define CAIRO_MUTEX_IMPL_INIT(mutex) (mutex) = new BLocker()
# define CAIRO_MUTEX_IMPL_FINI(mutex) delete (mutex)
# define CAIRO_MUTEX_IMPL_NIL_INITIALIZER NULL
#else /**********************************************************************/
# error "XXX: No mutex implementation found. Cairo will not work with multiple threads. Define CAIRO_NO_MUTEX to 1 to acknowledge and accept this limitation and compile cairo without thread-safety support."
#endif
CAIRO_END_DECLS
#endif

Просмотреть файл

@ -41,136 +41,27 @@
#ifndef CAIRO_MUTEX_PRIVATE_H
#define CAIRO_MUTEX_PRIVATE_H
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <cairo-features.h>
#include "cairo-compiler-private.h"
#include "cairo-mutex-type-private.h"
/* Only the following three are mandatory at this point */
#ifndef CAIRO_MUTEX_LOCK
# error "CAIRO_MUTEX_LOCK not defined. Check cairo-mutex-type-private.h."
#endif
#ifndef CAIRO_MUTEX_UNLOCK
# error "CAIRO_MUTEX_UNLOCK not defined. Check cairo-mutex-type-private.h."
#endif
#ifndef CAIRO_MUTEX_NIL_INITIALIZER
# error "CAIRO_MUTEX_NIL_INITIALIZER not defined. Check cairo-mutex-type-private.h."
#endif
CAIRO_BEGIN_DECLS
#define CAIRO_MUTEX_DECLARE(mutex) extern cairo_mutex_t mutex
#include "cairo-mutex-list-private.h"
#undef CAIRO_MUTEX_DECLARE
/* make sure implementations don't fool us: we decide these ourself */
#undef _CAIRO_MUTEX_USE_STATIC_INITIALIZER
#undef _CAIRO_MUTEX_USE_STATIC_FINALIZER
#ifdef CAIRO_MUTEX_INIT
/* If %CAIRO_MUTEX_INIT is defined, we may need to initialize all
* static mutex'es. */
# ifndef CAIRO_MUTEX_INITIALIZE
# define CAIRO_MUTEX_INITIALIZE() do { \
if (!_cairo_mutex_initialized) \
_cairo_mutex_initialize (); \
} while(0)
cairo_private void _cairo_mutex_initialize (void);
/* and make sure we implement the above */
# define _CAIRO_MUTEX_USE_STATIC_INITIALIZER 1
# endif /* CAIRO_MUTEX_INITIALIZE */
#else /* no CAIRO_MUTEX_INIT */
/* Otherwise we probably don't need to initialize static mutex'es, */
# ifndef CAIRO_MUTEX_INITIALIZE
# define CAIRO_MUTEX_INITIALIZE() CAIRO_MUTEX_NOOP
# endif /* CAIRO_MUTEX_INITIALIZE */
/* and dynamic ones can be initialized using the static initializer. */
# define CAIRO_MUTEX_INIT(mutex) do { \
cairo_mutex_t _tmp_mutex = CAIRO_MUTEX_NIL_INITIALIZER; \
memcpy (&(mutex), &_tmp_mutex, sizeof (_tmp_mutex)); \
} while (0)
#endif /* CAIRO_MUTEX_INIT */
#ifdef CAIRO_MUTEX_FINI
/* If %CAIRO_MUTEX_FINI is defined, we may need to finalize all
* static mutex'es. */
# ifndef CAIRO_MUTEX_FINALIZE
# define CAIRO_MUTEX_FINALIZE() do { \
if (_cairo_mutex_initialized) \
_cairo_mutex_finalize (); \
} while(0)
cairo_private void _cairo_mutex_finalize (void);
/* and make sure we implement the above */
# define _CAIRO_MUTEX_USE_STATIC_FINALIZER 1
# endif /* CAIRO_MUTEX_FINALIZE */
#else /* no CAIRO_MUTEX_FINI */
/* Otherwise we probably don't need to finalize static mutex'es, */
# ifndef CAIRO_MUTEX_FINALIZE
# define CAIRO_MUTEX_FINALIZE() CAIRO_MUTEX_NOOP
# endif /* CAIRO_MUTEX_FINALIZE */
/* neither do the dynamic ones. */
# define CAIRO_MUTEX_FINI(mutex) CAIRO_MUTEX_NOOP1(mutex)
#endif /* CAIRO_MUTEX_FINI */
#ifndef _CAIRO_MUTEX_USE_STATIC_INITIALIZER
#define _CAIRO_MUTEX_USE_STATIC_INITIALIZER 0
#if _CAIRO_MUTEX_IMPL_USE_STATIC_INITIALIZER
cairo_private void _cairo_mutex_initialize (void);
#endif
#ifndef _CAIRO_MUTEX_USE_STATIC_FINALIZER
#define _CAIRO_MUTEX_USE_STATIC_FINALIZER 0
#if _CAIRO_MUTEX_IMPL_USE_STATIC_FINALIZER
cairo_private void _cairo_mutex_finalize (void);
#endif
/* only if using static initializer and/or finalizer define the boolean */
#if _CAIRO_MUTEX_USE_STATIC_INITIALIZER || _CAIRO_MUTEX_USE_STATIC_FINALIZER
#if _CAIRO_MUTEX_IMPL_USE_STATIC_INITIALIZER || _CAIRO_MUTEX_IMPL_USE_STATIC_FINALIZER
cairo_private extern cairo_bool_t _cairo_mutex_initialized;
#endif
/* Finally, extern the static mutexes and undef */
#define CAIRO_MUTEX_DECLARE(mutex) cairo_private extern cairo_mutex_t mutex
#include "cairo-mutex-list-private.h"
#undef CAIRO_MUTEX_DECLARE
CAIRO_END_DECLS
/* Make sure everything we want is defined */
#ifndef CAIRO_MUTEX_INITIALIZE
# error "CAIRO_MUTEX_INITIALIZE not defined"
#endif
#ifndef CAIRO_MUTEX_FINALIZE
# error "CAIRO_MUTEX_FINALIZE not defined"
#endif
#ifndef CAIRO_MUTEX_LOCK
# error "CAIRO_MUTEX_LOCK not defined"
#endif
#ifndef CAIRO_MUTEX_UNLOCK
# error "CAIRO_MUTEX_UNLOCK not defined"
#endif
#ifndef CAIRO_MUTEX_INIT
# error "CAIRO_MUTEX_INIT not defined"
#endif
#ifndef CAIRO_MUTEX_FINI
# error "CAIRO_MUTEX_FINI not defined"
#endif
#ifndef CAIRO_MUTEX_NIL_INITIALIZER
# error "CAIRO_MUTEX_NIL_INITIALIZER not defined"
#endif
#endif

Просмотреть файл

@ -45,166 +45,144 @@
#include "config.h"
#endif
#include <cairo-features.h>
CAIRO_BEGIN_DECLS
/* A fully qualified no-operation statement */
#define CAIRO_MUTEX_NOOP do {/*no-op*/} while (0)
/* And one that evaluates it's argument once */
#define CAIRO_MUTEX_NOOP1(expr) do { if (expr) ; } while (0)
/* Cairo mutex implementation:
*
* Any new mutex implementation needs to do the following:
*
* - Condition on the right header or feature. Headers are
* preferred as eg. you still can use win32 mutex implementation
* on a win32 system even if you do not compile the win32
* surface/backend.
*
* - typedef #cairo_mutex_t to the proper mutex type on your target
* system. Note that you may or may not need to use a pointer,
* depending on what kinds of initialization your mutex
* implementation supports. No trailing semicolon needed.
* You should be able to compile the following snippet (don't try
* running it):
*
* cairo_mutex_t _cairo_some_mutex;
*
* - #define CAIRO_MUTEX_LOCK(mutex) and CAIRO_MUTEX_UNLOCK(mutex) to
* proper statement to lock/unlock the mutex object passed in.
* You can (and should) assume that the mutex is already
* initialized, and is-not-already-locked/is-locked,
* respectively. Use the "do { ... } while (0)" idiom if necessary.
* No trailing semicolons are needed (in any macro you define here).
* You should be able to compile the following snippet:
*
* cairo_mutex_t _cairo_some_mutex;
*
* if (1)
* %CAIRO_MUTEX_LOCK (_cairo_some_mutex);
* else
* %CAIRO_MUTEX_UNLOCK (_cairo_some_mutex);
*
* - #define %CAIRO_MUTEX_NIL_INITIALIZER to something that can
* initialize the #cairo_mutex_t type you defined. Most of the
* time one of 0, %NULL, or {} works. At this point
* you should be able to compile the following snippet:
*
* cairo_mutex_t _cairo_some_mutex = CAIRO_MUTEX_NIL_INITIALIZER;
*
* if (1)
* %CAIRO_MUTEX_LOCK (_cairo_some_mutex);
* else
* %CAIRO_MUTEX_UNLOCK (_cairo_some_mutex);
*
* - If the above code is not enough to initialize a mutex on
* your platform, #define CAIRO_MUTEX_INIT(mutex) to statement
* to initialize the mutex (allocate resources, etc). Such that
* you should be able to compile AND RUN the following snippet:
*
* cairo_mutex_t _cairo_some_mutex = CAIRO_MUTEX_NIL_INITIALIZER;
*
* %CAIRO_MUTEX_INIT (_cairo_some_mutex);
*
* if (1)
* %CAIRO_MUTEX_LOCK (_cairo_some_mutex);
* else
* %CAIRO_MUTEX_UNLOCK (_cairo_some_mutex);
*
* - If you define CAIRO_MUTEX_INIT(mutex), cairo will use it to
* initialize all static mutex'es. If for any reason that should
* not happen (eg. %CAIRO_MUTEX_INIT is just a faster way than
* what cairo does using %CAIRO_MUTEX_NIL_INITIALIZER), then
* #define CAIRO_MUTEX_INITIALIZE() CAIRO_MUTEX_NOOP
*
* - If your system supports freeing a mutex object (deallocating
* resources, etc), then #define CAIRO_MUTEX_FINI(mutex) to do
* that.
*
* - If you define CAIRO_MUTEX_FINI(mutex), cairo will use it to
* define a finalizer function to finalize all static mutex'es.
* However, it's up to you to call CAIRO_MUTEX_FINALIZE() at
* proper places, eg. when the system is unloading the cairo library.
* So, if for any reason finalizing static mutex'es is not needed
* (eg. you never call %CAIRO_MUTEX_FINALIZE), then
* #define CAIRO_MUTEX_FINALIZE() CAIRO_MUTEX_NOOP
*
* - That is all. If for any reason you think the above API is
* not enough to implement #cairo_mutex_t on your system, please
* stop and write to the cairo mailing list about it. DO NOT
* poke around cairo-mutex-private.h for possible solutions.
*/
#if CAIRO_NO_MUTEX
/* No mutexes */
typedef int cairo_mutex_t;
# define CAIRO_MUTEX_INITIALIZE() CAIRO_MUTEX_NOOP
# define CAIRO_MUTEX_LOCK(mutex) CAIRO_MUTEX_NOOP1(mutex)
# define CAIRO_MUTEX_UNLOCK(mutex) CAIRO_MUTEX_NOOP1(mutex)
# define CAIRO_MUTEX_NIL_INITIALIZER 0
#elif HAVE_PTHREAD_H /*******************************************************/
# include <pthread.h>
typedef pthread_mutex_t cairo_mutex_t;
# define CAIRO_MUTEX_LOCK(mutex) pthread_mutex_lock (&(mutex))
# define CAIRO_MUTEX_UNLOCK(mutex) pthread_mutex_unlock (&(mutex))
# define CAIRO_MUTEX_FINI(mutex) pthread_mutex_destroy (&(mutex))
# define CAIRO_MUTEX_FINALIZE() CAIRO_MUTEX_NOOP
# define CAIRO_MUTEX_NIL_INITIALIZER PTHREAD_MUTEX_INITIALIZER
#elif HAVE_WINDOWS_H /*******************************************************/
# include <windows.h>
typedef CRITICAL_SECTION cairo_mutex_t;
# define CAIRO_MUTEX_LOCK(mutex) EnterCriticalSection (&(mutex))
# define CAIRO_MUTEX_UNLOCK(mutex) LeaveCriticalSection (&(mutex))
# define CAIRO_MUTEX_INIT(mutex) InitializeCriticalSection (&(mutex))
# define CAIRO_MUTEX_FINI(mutex) DeleteCriticalSection (&(mutex))
# define CAIRO_MUTEX_NIL_INITIALIZER { NULL, 0, 0, NULL, NULL, 0 }
#elif defined __OS2__ /******************************************************/
# define INCL_BASE
# define INCL_PM
# include <os2.h>
typedef HMTX cairo_mutex_t;
# define CAIRO_MUTEX_LOCK(mutex) DosRequestMutexSem(mutex, SEM_INDEFINITE_WAIT)
# define CAIRO_MUTEX_UNLOCK(mutex) DosReleaseMutexSem(mutex)
# define CAIRO_MUTEX_INIT(mutex) DosCreateMutexSem (NULL, &(mutex), 0L, FALSE)
# define CAIRO_MUTEX_FINI(mutex) DosCloseMutexSem (mutex)
# define CAIRO_MUTEX_NIL_INITIALIZER 0
#elif CAIRO_HAS_BEOS_SURFACE /***********************************************/
typedef BLocker* cairo_mutex_t;
# define CAIRO_MUTEX_LOCK(mutex) (mutex)->Lock()
# define CAIRO_MUTEX_UNLOCK(mutex) (mutex)->Unlock()
# define CAIRO_MUTEX_INIT(mutex) (mutex) = new BLocker()
# define CAIRO_MUTEX_FINI(mutex) delete (mutex)
# define CAIRO_MUTEX_NIL_INITIALIZER NULL
#else /**********************************************************************/
# error "XXX: No mutex implementation found. Cairo will not work with multiple threads. Define CAIRO_NO_MUTEX to 1 to acknowledge and accept this limitation and compile cairo without thread-safety support."
#include "cairo-features.h"
#include "cairo-compiler-private.h"
#include "cairo-mutex-impl-private.h"
/* Only the following three are mandatory at this point */
#ifndef CAIRO_MUTEX_IMPL_LOCK
# error "CAIRO_MUTEX_IMPL_LOCK not defined. Check cairo-mutex-impl-private.h."
#endif
#ifndef CAIRO_MUTEX_IMPL_UNLOCK
# error "CAIRO_MUTEX_IMPL_UNLOCK not defined. Check cairo-mutex-impl-private.h."
#endif
#ifndef CAIRO_MUTEX_IMPL_NIL_INITIALIZER
# error "CAIRO_MUTEX_IMPL_NIL_INITIALIZER not defined. Check cairo-mutex-impl-private.h."
#endif
CAIRO_END_DECLS
/* make sure implementations don't fool us: we decide these ourself */
#undef _CAIRO_MUTEX_IMPL_USE_STATIC_INITIALIZER
#undef _CAIRO_MUTEX_IMPL_USE_STATIC_FINALIZER
#ifdef CAIRO_MUTEX_IMPL_INIT
/* If %CAIRO_MUTEX_IMPL_INIT is defined, we may need to initialize all
* static mutex'es. */
# ifndef CAIRO_MUTEX_IMPL_INITIALIZE
# define CAIRO_MUTEX_IMPL_INITIALIZE() do { \
if (!_cairo_mutex_initialized) \
_cairo_mutex_initialize (); \
} while(0)
/* and make sure we implement the above */
# define _CAIRO_MUTEX_IMPL_USE_STATIC_INITIALIZER 1
# endif /* CAIRO_MUTEX_IMPL_INITIALIZE */
#else /* no CAIRO_MUTEX_IMPL_INIT */
/* Otherwise we probably don't need to initialize static mutex'es, */
# ifndef CAIRO_MUTEX_IMPL_INITIALIZE
# define CAIRO_MUTEX_IMPL_INITIALIZE() CAIRO_MUTEX_IMPL_NOOP
# endif /* CAIRO_MUTEX_IMPL_INITIALIZE */
/* and dynamic ones can be initialized using the static initializer. */
# define CAIRO_MUTEX_IMPL_INIT(mutex) do { \
cairo_mutex_t _tmp_mutex = CAIRO_MUTEX_IMPL_NIL_INITIALIZER; \
memcpy (&(mutex), &_tmp_mutex, sizeof (_tmp_mutex)); \
} while (0)
#endif /* CAIRO_MUTEX_IMPL_INIT */
#ifdef CAIRO_MUTEX_IMPL_FINI
/* If %CAIRO_MUTEX_IMPL_FINI is defined, we may need to finalize all
* static mutex'es. */
# ifndef CAIRO_MUTEX_IMPL_FINALIZE
# define CAIRO_MUTEX_IMPL_FINALIZE() do { \
if (_cairo_mutex_initialized) \
_cairo_mutex_finalize (); \
} while(0)
/* and make sure we implement the above */
# define _CAIRO_MUTEX_IMPL_USE_STATIC_FINALIZER 1
# endif /* CAIRO_MUTEX_IMPL_FINALIZE */
#else /* no CAIRO_MUTEX_IMPL_FINI */
/* Otherwise we probably don't need to finalize static mutex'es, */
# ifndef CAIRO_MUTEX_IMPL_FINALIZE
# define CAIRO_MUTEX_IMPL_FINALIZE() CAIRO_MUTEX_IMPL_NOOP
# endif /* CAIRO_MUTEX_IMPL_FINALIZE */
/* neither do the dynamic ones. */
# define CAIRO_MUTEX_IMPL_FINI(mutex) CAIRO_MUTEX_IMPL_NOOP1(mutex)
#endif /* CAIRO_MUTEX_IMPL_FINI */
#ifndef _CAIRO_MUTEX_IMPL_USE_STATIC_INITIALIZER
#define _CAIRO_MUTEX_IMPL_USE_STATIC_INITIALIZER 0
#endif
#ifndef _CAIRO_MUTEX_IMPL_USE_STATIC_FINALIZER
#define _CAIRO_MUTEX_IMPL_USE_STATIC_FINALIZER 0
#endif
/* Make sure everything we want is defined */
#ifndef CAIRO_MUTEX_IMPL_INITIALIZE
# error "CAIRO_MUTEX_IMPL_INITIALIZE not defined"
#endif
#ifndef CAIRO_MUTEX_IMPL_FINALIZE
# error "CAIRO_MUTEX_IMPL_FINALIZE not defined"
#endif
#ifndef CAIRO_MUTEX_IMPL_LOCK
# error "CAIRO_MUTEX_IMPL_LOCK not defined"
#endif
#ifndef CAIRO_MUTEX_IMPL_UNLOCK
# error "CAIRO_MUTEX_IMPL_UNLOCK not defined"
#endif
#ifndef CAIRO_MUTEX_IMPL_INIT
# error "CAIRO_MUTEX_IMPL_INIT not defined"
#endif
#ifndef CAIRO_MUTEX_IMPL_FINI
# error "CAIRO_MUTEX_IMPL_FINI not defined"
#endif
#ifndef CAIRO_MUTEX_IMPL_NIL_INITIALIZER
# error "CAIRO_MUTEX_IMPL_NIL_INITIALIZER not defined"
#endif
/* Public interface. */
/* By default it simply uses the implementation provided.
* But we can provide for debugging features by overriding them */
#ifndef CAIRO_MUTEX_DEBUG
typedef cairo_mutex_impl_t cairo_mutex_t;
#else
# define cairo_mutex_t cairo_mutex_impl_t
#endif
#define CAIRO_MUTEX_INITIALIZE CAIRO_MUTEX_IMPL_INITIALIZE
#define CAIRO_MUTEX_FINALIZE CAIRO_MUTEX_IMPL_FINALIZE
#define CAIRO_MUTEX_LOCK CAIRO_MUTEX_IMPL_LOCK
#define CAIRO_MUTEX_UNLOCK CAIRO_MUTEX_IMPL_UNLOCK
#define CAIRO_MUTEX_INIT CAIRO_MUTEX_IMPL_INIT
#define CAIRO_MUTEX_FINI CAIRO_MUTEX_IMPL_FINI
#define CAIRO_MUTEX_NIL_INITIALIZER CAIRO_MUTEX_IMPL_NIL_INITIALIZER
/* Debugging support */
#ifdef CAIRO_MUTEX_DEBUG
/* TODO add mutex debugging facilities here (eg deadlock detection) */
#endif /* CAIRO_MUTEX_DEBUG */
#endif

Просмотреть файл

@ -33,25 +33,27 @@
#include "cairoint.h"
#include "cairo-mutex-private.h"
#define CAIRO_MUTEX_DECLARE(mutex) cairo_mutex_t mutex = CAIRO_MUTEX_NIL_INITIALIZER
#include "cairo-mutex-list-private.h"
#undef CAIRO_MUTEX_DECLARE
#if _CAIRO_MUTEX_USE_STATIC_INITIALIZER || _CAIRO_MUTEX_USE_STATIC_FINALIZER
#if _CAIRO_MUTEX_IMPL_USE_STATIC_INITIALIZER || _CAIRO_MUTEX_IMPL_USE_STATIC_FINALIZER
# if _CAIRO_MUTEX_USE_STATIC_INITIALIZER
# define _CAIRO_MUTEX_INITIALIZED_DEFAULT_VALUE FALSE
# if _CAIRO_MUTEX_IMPL_USE_STATIC_INITIALIZER
# define _CAIRO_MUTEX_IMPL_INITIALIZED_DEFAULT_VALUE FALSE
# else
# define _CAIRO_MUTEX_INITIALIZED_DEFAULT_VALUE TRUE
# define _CAIRO_MUTEX_IMPL_INITIALIZED_DEFAULT_VALUE TRUE
# endif
cairo_bool_t _cairo_mutex_initialized = _CAIRO_MUTEX_INITIALIZED_DEFAULT_VALUE;
cairo_bool_t _cairo_mutex_initialized = _CAIRO_MUTEX_IMPL_INITIALIZED_DEFAULT_VALUE;
# undef _CAIRO_MUTEX_INITIALIZED_DEFAULT_VALUE
# undef _CAIRO_MUTEX_IMPL_INITIALIZED_DEFAULT_VALUE
#endif
#if _CAIRO_MUTEX_USE_STATIC_INITIALIZER
#if _CAIRO_MUTEX_IMPL_USE_STATIC_INITIALIZER
void _cairo_mutex_initialize (void)
{
if (_cairo_mutex_initialized)
@ -65,7 +67,7 @@ void _cairo_mutex_initialize (void)
}
#endif
#if _CAIRO_MUTEX_USE_STATIC_FINALIZER
#if _CAIRO_MUTEX_IMPL_USE_STATIC_FINALIZER
void _cairo_mutex_finalize (void)
{
if (!_cairo_mutex_initialized)

Просмотреть файл

@ -49,7 +49,7 @@
# include <os2emx.h>
#endif
#include <cairo-os2.h>
#include "cairo-os2.h"
#include "cairoint.h"
typedef struct _cairo_os2_surface

Просмотреть файл

@ -56,8 +56,8 @@
/*
* Here comes the extra API for the OS/2 platform. Currently it consists
* of two extra functions, the cairo_os2_init () and the
* cairo_os2_fini (). Both of them are called automatically if
* of two extra functions, the cairo_os2_init() and the
* cairo_os2_fini(). Both of them are called automatically if
* Cairo is compiled to be a DLL file, but you have to call them before
* using the Cairo API if you link to Cairo statically!
*
@ -145,8 +145,10 @@ cairo_os2_fini (void)
CAIRO_MUTEX_FINALIZE ();
#if CAIRO_HAS_FT_FONT
# if HAVE_FCFINI
/* Uninitialize FontConfig */
FcFini ();
# endif
#endif
#ifdef __WATCOMC__

Просмотреть файл

@ -38,7 +38,7 @@
#ifndef _CAIRO_OS2_H_
#define _CAIRO_OS2_H_
#include <cairo.h>
#include "cairo.h"
CAIRO_BEGIN_DECLS

Просмотреть файл

@ -157,11 +157,11 @@ _cairo_memory_stream_copy (cairo_output_stream_t *base,
cairo_private int
_cairo_memory_stream_length (cairo_output_stream_t *stream);
/* cairo_base85_stream.c */
/* cairo-base85-stream.c */
cairo_private cairo_output_stream_t *
_cairo_base85_stream_create (cairo_output_stream_t *output);
/* cairo_deflate_stream.c */
/* cairo-deflate-stream.c */
cairo_private cairo_output_stream_t *
_cairo_deflate_stream_create (cairo_output_stream_t *output);

Просмотреть файл

@ -49,7 +49,7 @@
*/
#define SIGNIFICANT_DIGITS_AFTER_DECIMAL 6
/* Numbers printed with %g are assumed to only have CAIRO_FIXED_FRAC_BITS
/* Numbers printed with %g are assumed to only have %CAIRO_FIXED_FRAC_BITS
* bits of precision available after the decimal point.
*
* FIXED_POINT_DECIMAL_DIGITS specifies the minimum number of decimal
@ -58,10 +58,12 @@
*
* The conversion is:
*
* <programlisting>
* FIXED_POINT_DECIMAL_DIGITS = ceil( CAIRO_FIXED_FRAC_BITS * ln(2)/ln(10) )
* </programlisting>
*
* We can replace ceil(x) with (int)(x+1) since x will never be an
* integer for any likely value of CAIRO_FIXED_FRAC_BITS.
* integer for any likely value of %CAIRO_FIXED_FRAC_BITS.
*/
#define FIXED_POINT_DECIMAL_DIGITS ((int)(CAIRO_FIXED_FRAC_BITS*0.301029996 + 1))

Просмотреть файл

@ -67,6 +67,14 @@ struct _cairo_paginated_surface_backend {
cairo_warn cairo_int_status_t
(*set_bounding_box) (void *surface,
cairo_box_t *bbox);
/* Optional. Indicates whether the page requires fallback images.
* Will be called at the end of the ANALYZE phase but before the
* mode is changed to RENDER.
*/
cairo_warn cairo_int_status_t
(*set_fallback_images_required)(void *surface,
cairo_bool_t fallbacks_required);
};
/* A #cairo_paginated_surface_t provides a very convenient wrapper that
@ -80,7 +88,7 @@ struct _cairo_paginated_surface_backend {
* _cairo_paginated_surface_create which takes its own, much simpler,
* #cairo_paginated_surface_backend_t. You are free to return the result
* of _cairo_paginated_surface_create() from your public
* cairo_<foo>_surface_create. The paginated backend will be careful
* cairo_<foo>_surface_create(). The paginated backend will be careful
* to not let the user see that they really got a "wrapped"
* surface. See test-paginated-surface.c for a fairly minimal example
* of a paginated-using surface. That should be a reasonable example
@ -88,29 +96,29 @@ struct _cairo_paginated_surface_backend {
*
* What the paginated surface does is first save all drawing
* operations for a page into a meta-surface. Then when the user calls
* cairo_show_page, the paginated surface performs the following
* cairo_show_page(), the paginated surface performs the following
* sequence of operations (using the backend functions passed to
* cairo_paginated_surface_create):
* cairo_paginated_surface_create()):
*
* 1. Calls start_page (if non %NULL). At this point, it is appropriate
* 1. Calls start_page() (if not %NULL). At this point, it is appropriate
* for the target to emit any page-specific header information into
* its output.
*
* 2. Calls set_paginated_mode with an argument of CAIRO_PAGINATED_MODE_ANALYZE
* 2. Calls set_paginated_mode() with an argument of %CAIRO_PAGINATED_MODE_ANALYZE
*
* 3. Replays the meta-surface to the target surface, (with an
* analysis surface inserted between which watches the return value
* from each operation). This analysis stage is used to decide which
* operations will require fallbacks.
*
* 4. Calls set_bounding_box to provide the target surface with the
* 4. Calls set_bounding_box() to provide the target surface with the
* tight bounding box of the page.
*
* 5. Calls set_paginated_mode with an argument of CAIRO_PAGINATED_MODE_RENDER
* 5. Calls set_paginated_mode() with an argument of %CAIRO_PAGINATED_MODE_RENDER
*
* 6. Replays a subset of the meta-surface operations to the target surface
*
* 7. Calls set_paginated_mode with an argument of CAIRO_PAGINATED_MODE_FALLBACK
* 7. Calls set_paginated_mode() with an argument of %CAIRO_PAGINATED_MODE_FALLBACK
*
* 8. Replays the remaining operations to an image surface, sets an
* appropriate clip on the target, then paints the resulting image

Просмотреть файл

@ -89,7 +89,7 @@ _cairo_paginated_surface_create (cairo_surface_t *target,
* evidence of the paginated wrapper out to the user. */
surface->base.type = cairo_surface_get_type (target);
surface->target = target;
surface->target = cairo_surface_reference (target);
surface->content = content;
surface->width = width;
@ -316,6 +316,15 @@ _paint_page (cairo_paginated_surface_t *surface)
goto FAIL;
}
if (surface->backend->set_fallback_images_required) {
cairo_bool_t has_fallbacks = _cairo_analysis_surface_has_unsupported (analysis);
status = surface->backend->set_fallback_images_required (surface->target,
has_fallbacks);
if (status)
goto FAIL;
}
surface->backend->set_paginated_mode (surface->target, CAIRO_PAGINATED_MODE_RENDER);
/* Finer grained fallbacks are currently only supported for some
@ -595,13 +604,26 @@ _cairo_paginated_surface_fill (void *abstract_surface,
tolerance, antialias);
}
static cairo_bool_t
_cairo_paginated_surface_has_show_text_glyphs (void *abstract_surface)
{
cairo_paginated_surface_t *surface = abstract_surface;
return _cairo_surface_has_show_text_glyphs (surface->target);
}
static cairo_int_status_t
_cairo_paginated_surface_show_glyphs (void *abstract_surface,
cairo_operator_t op,
cairo_pattern_t *source,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font)
_cairo_paginated_surface_show_text_glyphs (void *abstract_surface,
cairo_operator_t op,
cairo_pattern_t *source,
const char *utf8,
int utf8_len,
cairo_glyph_t *glyphs,
int num_glyphs,
const cairo_text_cluster_t *clusters,
int num_clusters,
cairo_bool_t backward,
cairo_scaled_font_t *scaled_font)
{
cairo_paginated_surface_t *surface = abstract_surface;
cairo_int_status_t status;
@ -613,8 +635,8 @@ _cairo_paginated_surface_show_glyphs (void *abstract_surface,
surface->page_is_blank = FALSE;
/* Since this is a "wrapping" surface, we're calling back into
* _cairo_surface_show_glyphs from within a call to the same.
* Since _cairo_surface_show_glyphs acquires a mutex, we release
* _cairo_surface_show_text_glyphs from within a call to the same.
* Since _cairo_surface_show_text_glyphs acquires a mutex, we release
* and re-acquire the mutex around this nested call.
*
* Yes, this is ugly, but we consider it pragmatic as compared to
@ -623,9 +645,12 @@ _cairo_paginated_surface_show_glyphs (void *abstract_surface,
* lead to bugs).
*/
CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
status = _cairo_surface_show_glyphs (surface->meta, op, source,
glyphs, num_glyphs,
scaled_font);
status = _cairo_surface_show_text_glyphs (surface->meta, op, source,
utf8, utf8_len,
glyphs, num_glyphs,
clusters, num_clusters,
backward,
scaled_font);
CAIRO_MUTEX_LOCK (scaled_font->mutex);
return status;
@ -666,6 +691,12 @@ static const cairo_surface_backend_t cairo_paginated_surface_backend = {
_cairo_paginated_surface_mask,
_cairo_paginated_surface_stroke,
_cairo_paginated_surface_fill,
_cairo_paginated_surface_show_glyphs,
_cairo_paginated_surface_snapshot
NULL, /* show_glyphs */
_cairo_paginated_surface_snapshot,
NULL, /* is_similar */
NULL, /* reset */
NULL, /* fill_stroke */
NULL, /* create_solid_pattern_surface */
_cairo_paginated_surface_has_show_text_glyphs,
_cairo_paginated_surface_show_text_glyphs
};

Просмотреть файл

@ -476,7 +476,7 @@ static int const num_args[] =
};
cairo_status_t
_cairo_path_fixed_interpret (cairo_path_fixed_t *path,
_cairo_path_fixed_interpret (const cairo_path_fixed_t *path,
cairo_direction_t dir,
cairo_path_fixed_move_to_func_t *move_to,
cairo_path_fixed_line_to_func_t *line_to,
@ -485,7 +485,7 @@ _cairo_path_fixed_interpret (cairo_path_fixed_t *path,
void *closure)
{
cairo_status_t status;
cairo_path_buf_t *buf;
const cairo_path_buf_t *buf;
cairo_path_op_t op;
cairo_bool_t forward = (dir == CAIRO_DIRECTION_FORWARD);
int step = forward ? 1 : -1;
@ -541,6 +541,52 @@ _cairo_path_fixed_interpret (cairo_path_fixed_t *path,
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_append_move_to (void *closure,
cairo_point_t *point)
{
cairo_path_fixed_t *path = (cairo_path_fixed_t *) closure;
return _cairo_path_fixed_move_to (path, point->x, point->y);
}
static cairo_status_t
_append_line_to (void *closure,
cairo_point_t *point)
{
cairo_path_fixed_t *path = (cairo_path_fixed_t *) closure;
return _cairo_path_fixed_line_to (path, point->x, point->y);
}
static cairo_status_t
_append_curve_to (void *closure,
cairo_point_t *p0,
cairo_point_t *p1,
cairo_point_t *p2)
{
cairo_path_fixed_t *path = (cairo_path_fixed_t *) closure;
return _cairo_path_fixed_curve_to (path, p0->x, p0->y, p1->x, p1->y, p2->x, p2->y);
}
static cairo_status_t
_append_close_path (void *closure)
{
cairo_path_fixed_t *path = (cairo_path_fixed_t *) closure;
return _cairo_path_fixed_close_path (path);
}
cairo_private cairo_status_t
_cairo_path_fixed_append (cairo_path_fixed_t *path,
const cairo_path_fixed_t *other,
cairo_direction_t dir)
{
return _cairo_path_fixed_interpret (other, dir,
_append_move_to,
_append_line_to,
_append_curve_to,
_append_close_path,
path);
}
static void
_cairo_path_fixed_offset_and_scale (cairo_path_fixed_t *path,
cairo_fixed_t offx,
@ -566,29 +612,47 @@ _cairo_path_fixed_offset_and_scale (cairo_path_fixed_t *path,
}
}
/**
* _cairo_path_fixed_device_transform:
* _cairo_path_fixed_transform:
* @path: a #cairo_path_fixed_t to be transformed
* @device_transform: a matrix with only scaling/translation (no rotation or shear)
* @matrix: a #cairo_matrix_t
*
* Transform the fixed-point path according to the scaling and
* translation of the given matrix. This function assert()s that the
* given matrix has no rotation or shear elements, (that is, xy and yx
* are 0.0).
* Transform the fixed-point path according to the given matrix.
* There is a fast path for the case where @matrix has no rotation
* or shear.
**/
void
_cairo_path_fixed_device_transform (cairo_path_fixed_t *path,
cairo_matrix_t *device_transform)
_cairo_path_fixed_transform (cairo_path_fixed_t *path,
cairo_matrix_t *matrix)
{
assert (device_transform->yx == 0.0 && device_transform->xy == 0.0);
/* XXX: Support freeform matrices someday (right now, only translation and scale
* work. */
_cairo_path_fixed_offset_and_scale (path,
_cairo_fixed_from_double (device_transform->x0),
_cairo_fixed_from_double (device_transform->y0),
_cairo_fixed_from_double (device_transform->xx),
_cairo_fixed_from_double (device_transform->yy));
cairo_path_buf_t *buf;
int i;
double dx, dy;
if (matrix->yx == 0.0 && matrix->xy == 0.0) {
/* Fast path for the common case of scale+transform */
_cairo_path_fixed_offset_and_scale (path,
_cairo_fixed_from_double (matrix->x0),
_cairo_fixed_from_double (matrix->y0),
_cairo_fixed_from_double (matrix->xx),
_cairo_fixed_from_double (matrix->yy));
return;
}
buf = &path->buf_head.base;
while (buf) {
for (i = 0; i < buf->num_points; i++) {
dx = _cairo_fixed_to_double (buf->points[i].x);
dy = _cairo_fixed_to_double (buf->points[i].y);
cairo_matrix_transform_point (matrix, &dx, &dy);
buf->points[i].x = _cairo_fixed_from_double (dx);
buf->points[i].y = _cairo_fixed_from_double (dy);
}
buf = buf->next;
}
}
cairo_bool_t
@ -701,7 +765,7 @@ _cpf_close_path (void *closure)
cairo_status_t
_cairo_path_fixed_interpret_flat (cairo_path_fixed_t *path,
_cairo_path_fixed_interpret_flat (const cairo_path_fixed_t *path,
cairo_direction_t dir,
cairo_path_fixed_move_to_func_t *move_to,
cairo_path_fixed_line_to_func_t *line_to,
@ -805,14 +869,16 @@ _cairo_path_fixed_is_box (cairo_path_fixed_t *path,
return FALSE;
}
/**
/*
* Check whether the given path contains a single rectangle
* that is logically equivalent to:
* <informalexample><programlisting>
* cairo_move_to (cr, x, y);
* cairo_rel_line_to (cr, width, 0);
* cairo_rel_line_to (cr, 0, height);
* cairo_rel_line_to (cr, -width, 0);
* cairo_close_path (cr);
* </programlisting></informalexample>
*/
cairo_bool_t
_cairo_path_fixed_is_rectangle (cairo_path_fixed_t *path,

Просмотреть файл

@ -1191,9 +1191,10 @@ typedef struct _cairo_rectilinear_stroker
cairo_point_t current_point;
cairo_point_t first_point;
cairo_bool_t open_sub_path;
cairo_line_t *segments;
int segments_size;
int num_segments;
int segments_size;
cairo_line_t *segments;
cairo_line_t segments_embedded[8]; /* common case is a single rectangle */
} cairo_rectilinear_stroker_t;
static void
@ -1206,15 +1207,16 @@ _cairo_rectilinear_stroker_init (cairo_rectilinear_stroker_t *stroker,
_cairo_fixed_from_double (stroke_style->line_width / 2.0);
stroker->traps = traps;
stroker->open_sub_path = FALSE;
stroker->segments = NULL;
stroker->segments_size = 0;
stroker->segments = stroker->segments_embedded;
stroker->segments_size = ARRAY_LENGTH (stroker->segments_embedded);
stroker->num_segments = 0;
}
static void
_cairo_rectilinear_stroker_fini (cairo_rectilinear_stroker_t *stroker)
{
free (stroker->segments);
if (stroker->segments != stroker->segments_embedded)
free (stroker->segments);
}
static cairo_status_t
@ -1222,18 +1224,24 @@ _cairo_rectilinear_stroker_add_segment (cairo_rectilinear_stroker_t *stroker,
cairo_point_t *p1,
cairo_point_t *p2)
{
int new_size;
cairo_line_t *new_segments;
if (stroker->num_segments == stroker->segments_size) {
new_size = stroker->segments_size * 2;
/* Common case is one rectangle of exactly 4 segments. */
if (new_size == 0)
new_size = 4;
new_segments = _cairo_realloc_ab (stroker->segments,
new_size, sizeof (cairo_line_t));
if (new_segments == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
int new_size = stroker->segments_size * 2;
cairo_line_t *new_segments;
if (stroker->segments == stroker->segments_embedded) {
new_segments = _cairo_malloc_ab (new_size, sizeof (cairo_line_t));
if (new_segments == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
memcpy (new_segments, stroker->segments,
stroker->num_segments * sizeof (cairo_line_t));
} else {
new_segments = _cairo_realloc_ab (stroker->segments,
new_size, sizeof (cairo_line_t));
if (new_segments == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
stroker->segments_size = new_size;
stroker->segments = new_segments;
@ -1390,8 +1398,7 @@ _cairo_rectilinear_stroker_line_to (void *closure,
if (a->x == b->x && a->y == b->y)
return CAIRO_STATUS_SUCCESS;
status = _cairo_rectilinear_stroker_add_segment (stroker,
a, b);
status = _cairo_rectilinear_stroker_add_segment (stroker, a, b);
stroker->current_point = *point;
stroker->open_sub_path = TRUE;

Просмотреть файл

@ -50,7 +50,7 @@ static const cairo_solid_pattern_t _cairo_pattern_nil_null_pointer = {
CAIRO_EXTEND_GRADIENT_DEFAULT }, /* extend */
};
const cairo_solid_pattern_t cairo_pattern_none = {
const cairo_solid_pattern_t _cairo_pattern_none = {
{ CAIRO_PATTERN_TYPE_SOLID, /* type */
CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */
CAIRO_STATUS_SUCCESS, /* status */
@ -63,10 +63,10 @@ const cairo_solid_pattern_t cairo_pattern_none = {
/**
* _cairo_pattern_set_error:
* @pattern: a pattern
* @status: a status value indicating an error, (eg. not
* CAIRO_STATUS_SUCCESS)
* @status: a status value indicating an error
*
* Atomically sets pattern->status to @status and calls _cairo_error;
* Does nothing if status is %CAIRO_STATUS_SUCCESS.
*
* All assignments of an error status to pattern->status should happen
* through _cairo_pattern_set_error(). Note that due to the nature of
@ -81,6 +81,9 @@ static cairo_status_t
_cairo_pattern_set_error (cairo_pattern_t *pattern,
cairo_status_t status)
{
if (status == CAIRO_STATUS_SUCCESS)
return status;
/* Don't overwrite an existing error. This preserves the first
* error, which is the most significant. */
_cairo_status_set_error (&pattern->status, status);
@ -252,6 +255,9 @@ _cairo_pattern_init_solid (cairo_solid_pattern_t *pattern,
const cairo_color_t *color,
cairo_content_t content)
{
if (content == CAIRO_CONTENT_COLOR_ALPHA && CAIRO_COLOR_IS_OPAQUE (color))
content = CAIRO_CONTENT_COLOR;
_cairo_pattern_init (&pattern->base, CAIRO_PATTERN_TYPE_SOLID);
pattern->color = *color;
pattern->content = content;
@ -358,7 +364,8 @@ _cairo_pattern_reset_solid_pattern_cache (void)
CAIRO_MUTEX_LOCK (_cairo_pattern_solid_pattern_cache_lock);
for (i = 0; i < MIN (ARRAY_LENGTH (solid_pattern_cache.patterns), solid_pattern_cache.size); i++) {
free (solid_pattern_cache.patterns[i]);
if (solid_pattern_cache.patterns[i])
free (solid_pattern_cache.patterns[i]);
solid_pattern_cache.patterns[i] = NULL;
}
solid_pattern_cache.size = 0;
@ -376,8 +383,7 @@ _cairo_pattern_create_in_error (cairo_status_t status)
CAIRO_MUTEX_INITIALIZE ();
pattern = _cairo_pattern_create_solid (_cairo_stock_color (CAIRO_STOCK_BLACK),
CAIRO_CONTENT_COLOR);
pattern = _cairo_pattern_create_solid (CAIRO_COLOR_BLACK, CAIRO_CONTENT_COLOR);
if (pattern->status == CAIRO_STATUS_SUCCESS)
status = _cairo_pattern_set_error (pattern, status);
@ -1364,6 +1370,7 @@ _cairo_pattern_acquire_surface_for_gradient (cairo_gradient_pattern_t *pattern,
#define MAX_SURFACE_CACHE_SIZE 16
static struct {
struct _cairo_pattern_solid_surface_cache{
cairo_content_t content;
cairo_color_t color;
cairo_surface_t *surface;
} cache[MAX_SURFACE_CACHE_SIZE];
@ -1376,10 +1383,10 @@ _cairo_pattern_solid_surface_matches (
const cairo_solid_pattern_t *pattern,
cairo_surface_t *dst)
{
if (CAIRO_REFERENCE_COUNT_GET_VALUE (&cache->surface->ref_count) != 1)
if (cache->content != pattern->content)
return FALSE;
if (! _cairo_color_equal (&cache->color, &pattern->color))
if (CAIRO_REFERENCE_COUNT_GET_VALUE (&cache->surface->ref_count) != 1)
return FALSE;
if (! _cairo_surface_is_similar (cache->surface, dst, pattern->content))
@ -1388,6 +1395,18 @@ _cairo_pattern_solid_surface_matches (
return TRUE;
}
static cairo_bool_t
_cairo_pattern_solid_surface_matches_color (
const struct _cairo_pattern_solid_surface_cache *cache,
const cairo_solid_pattern_t *pattern,
cairo_surface_t *dst)
{
if (! _cairo_color_equal (&cache->color, &pattern->color))
return FALSE;
return _cairo_pattern_solid_surface_matches (cache, pattern, dst);
}
static cairo_int_status_t
_cairo_pattern_acquire_surface_for_solid (cairo_solid_pattern_t *pattern,
cairo_surface_t *dst,
@ -1400,61 +1419,89 @@ _cairo_pattern_acquire_surface_for_solid (cairo_solid_pattern_t *pattern,
{
static int i;
cairo_surface_t *surface;
cairo_surface_t *surface, *to_destroy = NULL;
cairo_status_t status;
CAIRO_MUTEX_LOCK (_cairo_pattern_solid_surface_cache_lock);
/* Check cache first */
if (i < solid_surface_cache.size &&
_cairo_pattern_solid_surface_matches (&solid_surface_cache.cache[i],
pattern,
dst))
_cairo_pattern_solid_surface_matches_color (&solid_surface_cache.cache[i],
pattern,
dst))
{
if (! _cairo_surface_reset (solid_surface_cache.cache[i].surface))
goto DONE;
status = _cairo_surface_reset (solid_surface_cache.cache[i].surface);
if (status)
goto UNLOCK;
goto DONE;
}
for (i = 0 ; i < solid_surface_cache.size; i++) {
if (_cairo_pattern_solid_surface_matches (&solid_surface_cache.cache[i],
pattern,
dst))
if (_cairo_pattern_solid_surface_matches_color (&solid_surface_cache.cache[i],
pattern,
dst))
{
if (! _cairo_surface_reset (solid_surface_cache.cache[i].surface))
goto DONE;
status = _cairo_surface_reset (solid_surface_cache.cache[i].surface);
if (status)
goto UNLOCK;
goto DONE;
}
}
/* Not cached, need to create new */
surface = _cairo_surface_create_similar_solid (dst,
pattern->content,
1, 1,
&pattern->color,
&pattern->base);
if (surface->status) {
status = surface->status;
goto UNLOCK;
}
if (! _cairo_surface_is_similar (surface, dst, pattern->content)) {
/* in the rare event of a substitute surface being returned (e.g.
* malloc failure) don't cache the fallback surface */
*out = surface;
goto NOCACHE;
}
/* Cache new */
if (solid_surface_cache.size < MAX_SURFACE_CACHE_SIZE) {
solid_surface_cache.size++;
} else {
/* Choose a surface to repaint/evict */
surface = NULL;
if (solid_surface_cache.size == MAX_SURFACE_CACHE_SIZE) {
i = rand () % MAX_SURFACE_CACHE_SIZE;
surface = solid_surface_cache.cache[i].surface;
/* Evict old */
cairo_surface_destroy (solid_surface_cache.cache[i].surface);
if (_cairo_pattern_solid_surface_matches (&solid_surface_cache.cache[i],
pattern,
dst))
{
/* Reuse the surface instead of evicting */
status = _cairo_surface_reset (surface);
if (status)
goto EVICT;
status = _cairo_surface_repaint_solid_pattern_surface (dst, surface, pattern);
if (status)
goto EVICT;
cairo_surface_reference (surface);
}
else
{
EVICT:
surface = NULL;
}
}
solid_surface_cache.cache[i].color = pattern->color;
if (surface == NULL) {
/* Not cached, need to create new */
surface = _cairo_surface_create_solid_pattern_surface (dst, pattern);
if (surface->status) {
status = surface->status;
goto UNLOCK;
}
if (! _cairo_surface_is_similar (surface, dst, pattern->content)) {
/* in the rare event of a substitute surface being returned (e.g.
* malloc failure) don't cache the fallback surface */
*out = surface;
goto NOCACHE;
}
}
if (i == solid_surface_cache.size)
solid_surface_cache.size++;
to_destroy = solid_surface_cache.cache[i].surface;
solid_surface_cache.cache[i].surface = surface;
solid_surface_cache.cache[i].color = pattern->color;
solid_surface_cache.cache[i].content = pattern->content;
DONE:
*out = cairo_surface_reference (solid_surface_cache.cache[i].surface);
@ -1471,19 +1518,32 @@ NOCACHE:
UNLOCK:
CAIRO_MUTEX_UNLOCK (_cairo_pattern_solid_surface_cache_lock);
if (to_destroy)
cairo_surface_destroy (to_destroy);
return status;
}
static void
_cairo_pattern_reset_solid_surface_cache (void)
{
int i;
CAIRO_MUTEX_LOCK (_cairo_pattern_solid_surface_cache_lock);
for (i = 0; i < solid_surface_cache.size; i++)
cairo_surface_destroy (solid_surface_cache.cache[i].surface);
solid_surface_cache.size = 0;
/* remove surfaces starting from the end so that solid_surface_cache.cache
* is always in a consistent state when we release the mutex. */
while (solid_surface_cache.size) {
cairo_surface_t *surface;
solid_surface_cache.size--;
surface = solid_surface_cache.cache[solid_surface_cache.size].surface;
solid_surface_cache.cache[solid_surface_cache.size].surface = NULL;
/* release the lock to avoid the possibility of a recursive
* deadlock when the scaled font destroy closure gets called */
CAIRO_MUTEX_UNLOCK (_cairo_pattern_solid_surface_cache_lock);
cairo_surface_destroy (surface);
CAIRO_MUTEX_LOCK (_cairo_pattern_solid_surface_cache_lock);
}
CAIRO_MUTEX_UNLOCK (_cairo_pattern_solid_surface_cache_lock);
}
@ -1793,18 +1853,11 @@ _cairo_pattern_acquire_surface (cairo_pattern_t *pattern,
src->stops->color.blue,
src->stops->color.alpha);
_cairo_pattern_init_solid (&solid, &color,
CAIRO_COLOR_IS_OPAQUE (&color) ?
CAIRO_CONTENT_COLOR :
CAIRO_CONTENT_COLOR_ALPHA);
_cairo_pattern_init_solid (&solid, &color, CAIRO_CONTENT_COLOR_ALPHA);
}
else
{
const cairo_color_t *color;
color = _cairo_stock_color (CAIRO_STOCK_TRANSPARENT);
_cairo_pattern_init_solid (&solid, color,
CAIRO_CONTENT_ALPHA);
_cairo_pattern_init_solid (&solid, CAIRO_COLOR_TRANSPARENT, CAIRO_CONTENT_ALPHA);
}
status = _cairo_pattern_acquire_surface_for_solid (&solid, dst,
@ -1907,10 +1960,7 @@ _cairo_pattern_acquire_surfaces (cairo_pattern_t *src,
combined = src_solid->color;
_cairo_color_multiply_alpha (&combined, mask_solid->color.alpha);
_cairo_pattern_init_solid (&src_tmp.solid, &combined,
CAIRO_COLOR_IS_OPAQUE (&combined) ?
CAIRO_CONTENT_COLOR :
CAIRO_CONTENT_COLOR_ALPHA);
_cairo_pattern_init_solid (&src_tmp.solid, &combined, CAIRO_CONTENT_COLOR_ALPHA);
mask = NULL;
}
@ -2028,15 +2078,10 @@ _cairo_pattern_get_extents (cairo_pattern_t *pattern,
* horizontal/vertical linear gradients).
*/
/* XXX: because extents are represented as x, y, w, h we can't
* actually have a rectangle that covers our entire valid
* coordinate space, since we'd need width/height to be 2*INT_MAX.
*/
extents->x = 0;
extents->y = 0;
extents->width = CAIRO_RECT_INT_MAX;
extents->height = CAIRO_RECT_INT_MAX;
extents->x = CAIRO_RECT_INT_MIN;
extents->y = CAIRO_RECT_INT_MIN;
extents->width = CAIRO_RECT_INT_MIN + CAIRO_RECT_INT_MAX;
extents->height = CAIRO_RECT_INT_MIN + CAIRO_RECT_INT_MAX;
return CAIRO_STATUS_SUCCESS;
}

Просмотреть файл

@ -45,16 +45,51 @@
#include "cairo-compiler-private.h"
#include "cairo-types-private.h"
/* The glyph buffer size is based on the expected maximum glyphs in a
* line so that an entire line can be emitted in as one string. If the
* glyphs in a line exceeds this size the only downside is the slight
* overhead of emitting two strings.
*/
#define PDF_GLYPH_BUFFER_SIZE 200
typedef cairo_status_t (*cairo_pdf_operators_use_font_subset_t) (unsigned int font_id,
unsigned int subset_id,
void *closure);
typedef struct _cairo_pdf_glyph {
unsigned int glyph_index;
double x_position;
double x_advance;
} cairo_pdf_glyph_t;
typedef struct _cairo_pdf_operators {
cairo_output_stream_t *stream;
cairo_matrix_t cairo_to_pdf;
cairo_scaled_font_subsets_t *font_subsets;
cairo_pdf_operators_use_font_subset_t use_font_subset;
void *use_font_subset_closure;
cairo_bool_t in_text_object; /* inside BT/ET pair */
/* PDF text state */
cairo_bool_t is_new_text_object; /* text object started but matrix and font not yet selected */
unsigned int font_id;
unsigned int subset_id;
cairo_matrix_t text_matrix; /* PDF text matrix (Tlm in the PDF reference) */
cairo_matrix_t cairo_to_pdftext; /* translate cairo coords to PDF text space */
cairo_matrix_t font_matrix_inverse;
double cur_x; /* Current position in PDF text space (Tm in the PDF reference) */
double cur_y;
int hex_width;
int num_glyphs;
cairo_pdf_glyph_t glyphs[PDF_GLYPH_BUFFER_SIZE];
/* PDF line style */
cairo_bool_t has_line_style;
double line_width;
cairo_line_cap_t line_cap;
cairo_line_join_t line_join;
double miter_limit;
cairo_bool_t has_dashes;
} cairo_pdf_operators_t;
cairo_private void
@ -63,7 +98,7 @@ _cairo_pdf_operators_init (cairo_pdf_operators_t *pdf_operators,
cairo_matrix_t *cairo_to_pdf,
cairo_scaled_font_subsets_t *font_subsets);
cairo_private void
cairo_private cairo_status_t
_cairo_pdf_operators_fini (cairo_pdf_operators_t *pdf_operators);
cairo_private void
@ -80,11 +115,22 @@ cairo_private void
_cairo_pdf_operators_set_cairo_to_pdf_matrix (cairo_pdf_operators_t *pdf_operators,
cairo_matrix_t *cairo_to_pdf);
cairo_private cairo_status_t
_cairo_pdf_operators_flush (cairo_pdf_operators_t *pdf_operators);
cairo_private void
_cairo_pdf_operators_reset (cairo_pdf_operators_t *pdf_operators);
cairo_private cairo_int_status_t
_cairo_pdf_operators_clip (cairo_pdf_operators_t *pdf_operators,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule);
cairo_private cairo_int_status_t
_cairo_pdf_operators_emit_stroke_style (cairo_pdf_operators_t *pdf_operators,
cairo_stroke_style_t *style,
double scale);
cairo_private cairo_int_status_t
_cairo_pdf_operators_stroke (cairo_pdf_operators_t *pdf_operators,
cairo_path_fixed_t *path,
@ -106,9 +152,15 @@ _cairo_pdf_operators_fill_stroke (cairo_pdf_operators_t *pdf_operators,
cairo_matrix_t *ctm_inverse);
cairo_private cairo_int_status_t
_cairo_pdf_operators_show_glyphs (cairo_pdf_operators_t *pdf_operators,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font);
_cairo_pdf_operators_show_text_glyphs (cairo_pdf_operators_t *pdf_operators,
const char *utf8,
int utf8_len,
cairo_glyph_t *glyphs,
int num_glyphs,
const cairo_text_cluster_t *clusters,
int num_clusters,
cairo_bool_t backward,
cairo_scaled_font_t *scaled_font);
#endif /* CAIRO_PDF_OPERATORS_H */

Просмотреть файл

@ -47,6 +47,10 @@
#include <ctype.h>
static cairo_status_t
_cairo_pdf_operators_end_text (cairo_pdf_operators_t *pdf_operators);
void
_cairo_pdf_operators_init (cairo_pdf_operators_t *pdf_operators,
cairo_output_stream_t *stream,
@ -58,11 +62,15 @@ _cairo_pdf_operators_init (cairo_pdf_operators_t *pdf_operators,
pdf_operators->font_subsets = font_subsets;
pdf_operators->use_font_subset = NULL;
pdf_operators->use_font_subset_closure = NULL;
pdf_operators->in_text_object = FALSE;
pdf_operators->num_glyphs = 0;
pdf_operators->has_line_style = FALSE;
}
void
cairo_status_t
_cairo_pdf_operators_fini (cairo_pdf_operators_t *pdf_operators)
{
return _cairo_pdf_operators_flush (pdf_operators);
}
void
@ -74,11 +82,16 @@ _cairo_pdf_operators_set_font_subsets_callback (cairo_pdf_operators_t *pdf
pdf_operators->use_font_subset_closure = closure;
}
/* Change the output stream to a different stream.
* _cairo_pdf_operators_flush() should always be called before calling
* this function.
*/
void
_cairo_pdf_operators_set_stream (cairo_pdf_operators_t *pdf_operators,
cairo_output_stream_t *stream)
{
pdf_operators->stream = stream;
pdf_operators->has_line_style = FALSE;
}
void
@ -86,6 +99,45 @@ _cairo_pdf_operators_set_cairo_to_pdf_matrix (cairo_pdf_operators_t *pdf_operato
cairo_matrix_t *cairo_to_pdf)
{
pdf_operators->cairo_to_pdf = *cairo_to_pdf;
pdf_operators->has_line_style = FALSE;
}
/* Finish writing out any pending commands to the stream. This
* function must be called by the surface before emitting anything
* into the PDF stream.
*
* pdf_operators may leave the emitted PDF for some operations
* unfinished in case subsequent operations can be merged. This
* function will finish off any incomplete operation so the stream
* will be in a state where the surface may emit it's own PDF
* operations (eg changing patterns).
*
*/
cairo_status_t
_cairo_pdf_operators_flush (cairo_pdf_operators_t *pdf_operators)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
if (pdf_operators->in_text_object)
status = _cairo_pdf_operators_end_text (pdf_operators);
return status;
}
/* Reset the known graphics state of the PDF consumer. ie no
* assumptions will be made about the state. The next time a
* particular graphics state is required (eg line width) the state
* operator is always emitted and then remembered for subsequent
* operatations.
*
* This should be called when starting a new stream or after emitting
* the 'Q' operator (where pdf-operators functions were called inside
* the q/Q pair).
*/
void
_cairo_pdf_operators_reset (cairo_pdf_operators_t *pdf_operators)
{
pdf_operators->has_line_style = FALSE;
}
/* A word wrap stream can be used as a filter to do word wrapping on
@ -478,7 +530,7 @@ _cairo_pdf_line_join (cairo_line_join_t join)
}
}
static cairo_int_status_t
cairo_int_status_t
_cairo_pdf_operators_emit_stroke_style (cairo_pdf_operators_t *pdf_operators,
cairo_stroke_style_t *style,
double scale)
@ -486,6 +538,7 @@ _cairo_pdf_operators_emit_stroke_style (cairo_pdf_operators_t *pdf_operators,
double *dash = style->dash;
int num_dashes = style->num_dashes;
double dash_offset = style->dash_offset;
double line_width = style->line_width * scale;
/* PostScript has "special needs" when it comes to zero-length
* dash segments with butt caps. It apparently (at least
@ -550,17 +603,26 @@ _cairo_pdf_operators_emit_stroke_style (cairo_pdf_operators_t *pdf_operators,
}
}
_cairo_output_stream_printf (pdf_operators->stream,
"%f w\n",
style->line_width * scale);
if (!pdf_operators->has_line_style || pdf_operators->line_width != line_width) {
_cairo_output_stream_printf (pdf_operators->stream,
"%f w\n",
line_width);
pdf_operators->line_width = line_width;
}
_cairo_output_stream_printf (pdf_operators->stream,
"%d J\n",
_cairo_pdf_line_cap (style->line_cap));
if (!pdf_operators->has_line_style || pdf_operators->line_cap != style->line_cap) {
_cairo_output_stream_printf (pdf_operators->stream,
"%d J\n",
_cairo_pdf_line_cap (style->line_cap));
pdf_operators->line_cap = style->line_cap;
}
_cairo_output_stream_printf (pdf_operators->stream,
"%d j\n",
_cairo_pdf_line_join (style->line_join));
if (!pdf_operators->has_line_style || pdf_operators->line_join != style->line_join) {
_cairo_output_stream_printf (pdf_operators->stream,
"%d j\n",
_cairo_pdf_line_join (style->line_join));
pdf_operators->line_join = style->line_join;
}
if (num_dashes) {
int d;
@ -570,15 +632,21 @@ _cairo_pdf_operators_emit_stroke_style (cairo_pdf_operators_t *pdf_operators,
_cairo_output_stream_printf (pdf_operators->stream, " %f", dash[d] * scale);
_cairo_output_stream_printf (pdf_operators->stream, "] %f d\n",
dash_offset * scale);
} else {
pdf_operators->has_dashes = TRUE;
} else if (!pdf_operators->has_line_style || pdf_operators->has_dashes) {
_cairo_output_stream_printf (pdf_operators->stream, "[] 0.0 d\n");
pdf_operators->has_dashes = FALSE;
}
if (dash != style->dash)
free (dash);
_cairo_output_stream_printf (pdf_operators->stream,
"%f M ",
style->miter_limit < 1.0 ? 1.0 : style->miter_limit);
if (!pdf_operators->has_line_style || pdf_operators->miter_limit != style->miter_limit) {
_cairo_output_stream_printf (pdf_operators->stream,
"%f M ",
style->miter_limit < 1.0 ? 1.0 : style->miter_limit);
pdf_operators->miter_limit = style->miter_limit;
}
pdf_operators->has_line_style = TRUE;
return _cairo_output_stream_get_status (pdf_operators->stream);
}
@ -622,6 +690,9 @@ _cairo_pdf_operators_emit_stroke (cairo_pdf_operators_t *pdf_operators,
cairo_bool_t has_ctm = TRUE;
double scale = 1.0;
if (pdf_operators->in_text_object)
status = _cairo_pdf_operators_end_text (pdf_operators);
/* Optimize away the stroke ctm when it does not affect the
* stroke. There are other ctm cases that could be optimized
* however this is the most common.
@ -717,6 +788,9 @@ _cairo_pdf_operators_fill (cairo_pdf_operators_t *pdf_operators,
const char *pdf_operator;
cairo_status_t status;
if (pdf_operators->in_text_object)
status = _cairo_pdf_operators_end_text (pdf_operators);
status = _cairo_pdf_operators_emit_path (pdf_operators,
path,
&pdf_operators->cairo_to_pdf,
@ -773,205 +847,567 @@ _cairo_pdf_operators_fill_stroke (cairo_pdf_operators_t *pdf_operators,
#define GLYPH_POSITION_TOLERANCE 0.001
cairo_int_status_t
_cairo_pdf_operators_show_glyphs (cairo_pdf_operators_t *pdf_operators,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font)
/* Emit the string of glyphs using the 'Tj' operator. This requires
* that the glyphs are positioned at their natural glyph advances. */
static cairo_status_t
_cairo_pdf_operators_emit_glyph_string (cairo_pdf_operators_t *pdf_operators,
cairo_output_stream_t *stream)
{
unsigned int current_subset_id = (unsigned int)-1;
cairo_scaled_font_subsets_glyph_t subset_glyph;
cairo_bool_t diagonal, in_TJ;
cairo_status_t status, status_ignored;
double Tlm_x = 0, Tlm_y = 0;
double Tm_x = 0, y;
int i, hex_width;
cairo_output_stream_t *word_wrap_stream;
int i;
for (i = 0; i < num_glyphs; i++)
cairo_matrix_transform_point (&pdf_operators->cairo_to_pdf, &glyphs[i].x, &glyphs[i].y);
_cairo_output_stream_printf (stream, "<");
for (i = 0; i < pdf_operators->num_glyphs; i++) {
_cairo_output_stream_printf (stream,
"%0*x",
pdf_operators->hex_width,
pdf_operators->glyphs[i].glyph_index);
pdf_operators->cur_x += pdf_operators->glyphs[i].x_advance;
}
_cairo_output_stream_printf (stream, ">Tj\n");
return _cairo_output_stream_get_status (stream);
}
/* Emit the string of glyphs using the 'TJ' operator.
*
* The TJ operator takes an array of strings of glyphs. Each string of
* glyphs is displayed using the glyph advances of each glyph to
* position the glyphs. A relative adjustment to the glyph advance may
* be specified by including the adjustment between two strings. The
* adjustment is in units of text space * -1000.
*/
static cairo_status_t
_cairo_pdf_operators_emit_glyph_string_with_positioning (
cairo_pdf_operators_t *pdf_operators,
cairo_output_stream_t *stream)
{
int i;
_cairo_output_stream_printf (stream, "[<");
for (i = 0; i < pdf_operators->num_glyphs; i++) {
if (pdf_operators->glyphs[i].x_position != pdf_operators->cur_x)
{
double delta = pdf_operators->glyphs[i].x_position - pdf_operators->cur_x;
int rounded_delta;
delta = -1000.0*delta;
/* As the delta is in 1/1000 of a unit of text space,
* rounding to an integer should still provide sufficient
* precision. We round the delta before adding to Tm_x so
* that we keep track of the accumulated rounding error in
* the PDF interpreter and compensate for it when
* calculating subsequent deltas.
*/
rounded_delta = _cairo_lround (delta);
if (rounded_delta != 0) {
_cairo_output_stream_printf (stream,
">%d<",
rounded_delta);
}
/* Convert the rounded delta back to text
* space before adding to the current text
* position. */
delta = rounded_delta/-1000.0;
pdf_operators->cur_x += delta;
}
_cairo_output_stream_printf (stream,
"%0*x",
pdf_operators->hex_width,
pdf_operators->glyphs[i].glyph_index);
pdf_operators->cur_x += pdf_operators->glyphs[i].x_advance;
}
_cairo_output_stream_printf (stream, ">]TJ\n");
return _cairo_output_stream_get_status (stream);
}
static cairo_status_t
_cairo_pdf_operators_flush_glyphs (cairo_pdf_operators_t *pdf_operators)
{
cairo_output_stream_t *word_wrap_stream;
cairo_status_t status;
int i;
double x;
if (pdf_operators->num_glyphs == 0)
return 0;
word_wrap_stream = _word_wrap_stream_create (pdf_operators->stream, 72);
status = _cairo_output_stream_get_status (word_wrap_stream);
if (status)
return _cairo_output_stream_destroy (word_wrap_stream);
_cairo_output_stream_printf (word_wrap_stream,
"BT\n");
if (scaled_font->scale.xy == 0.0 &&
scaled_font->scale.yx == 0.0)
diagonal = TRUE;
else
diagonal = FALSE;
in_TJ = FALSE;
for (i = 0; i < num_glyphs; i++) {
status = _cairo_scaled_font_subsets_map_glyph (pdf_operators->font_subsets,
scaled_font, glyphs[i].index,
&subset_glyph);
if (status) {
status_ignored = _cairo_output_stream_destroy (word_wrap_stream);
return status;
}
if (subset_glyph.is_composite)
hex_width = 4;
else
hex_width = 2;
if (subset_glyph.is_scaled == FALSE) {
y = 0.0;
cairo_matrix_transform_distance (&scaled_font->scale,
&subset_glyph.x_advance,
&y);
}
if (subset_glyph.subset_id != current_subset_id) {
if (in_TJ) {
_cairo_output_stream_printf (word_wrap_stream, ">] TJ\n");
in_TJ = FALSE;
}
_cairo_output_stream_printf (word_wrap_stream,
"/f-%d-%d 1 Tf\n",
subset_glyph.font_id,
subset_glyph.subset_id);
if (pdf_operators->use_font_subset) {
status = pdf_operators->use_font_subset (subset_glyph.font_id,
subset_glyph.subset_id,
pdf_operators->use_font_subset_closure);
if (status) {
status_ignored = _cairo_output_stream_destroy (word_wrap_stream);
return status;
}
}
}
if (subset_glyph.subset_id != current_subset_id || !diagonal) {
_cairo_output_stream_printf (word_wrap_stream,
"%f %f %f %f %f %f Tm\n",
scaled_font->scale.xx,
-scaled_font->scale.yx,
-scaled_font->scale.xy,
scaled_font->scale.yy,
glyphs[i].x,
glyphs[i].y);
current_subset_id = subset_glyph.subset_id;
Tlm_x = glyphs[i].x;
Tlm_y = glyphs[i].y;
Tm_x = Tlm_x;
}
if (diagonal) {
if (i < num_glyphs - 1 &&
fabs((glyphs[i].y - glyphs[i+1].y)/scaled_font->scale.yy) < GLYPH_POSITION_TOLERANCE &&
fabs((glyphs[i].x - glyphs[i+1].x)/scaled_font->scale.xx) < 10)
{
if (!in_TJ) {
if (i != 0) {
_cairo_output_stream_printf (word_wrap_stream,
"%f %f Td\n",
(glyphs[i].x - Tlm_x)/scaled_font->scale.xx,
(glyphs[i].y - Tlm_y)/scaled_font->scale.yy);
Tlm_x = glyphs[i].x;
Tlm_y = glyphs[i].y;
Tm_x = Tlm_x;
}
_cairo_output_stream_printf (word_wrap_stream,
"[<%0*x",
hex_width,
subset_glyph.subset_glyph_index);
Tm_x += subset_glyph.x_advance;
in_TJ = TRUE;
} else {
if (fabs((glyphs[i].x - Tm_x)/scaled_font->scale.xx) > GLYPH_POSITION_TOLERANCE) {
double delta = glyphs[i].x - Tm_x;
int rounded_delta;
delta = -1000.0*delta/scaled_font->scale.xx;
/* As the delta is in 1/1000 of a unit of text
* space, rounding to an integer should still
* provide sufficient precision. We round the
* delta before adding to Tm_x so that we keep
* track of the accumulated rounding error in
* the PDF interpreter and compensate for it
* when calculating subsequent deltas.
*/
rounded_delta = _cairo_lround (delta);
if (rounded_delta != 0) {
_cairo_output_stream_printf (word_wrap_stream,
"> %d <",
rounded_delta);
}
/* Convert the rounded delta back to cairo
* space before adding to the current text
* position. */
delta = rounded_delta*scaled_font->scale.xx/-1000.0;
Tm_x += delta;
}
_cairo_output_stream_printf (word_wrap_stream,
"%0*x",
hex_width,
subset_glyph.subset_glyph_index);
Tm_x += subset_glyph.x_advance;
}
}
else
{
if (in_TJ) {
if (fabs((glyphs[i].x - Tm_x)/scaled_font->scale.xx) > GLYPH_POSITION_TOLERANCE) {
double delta = glyphs[i].x - Tm_x;
int rounded_delta;
delta = -1000.0*delta/scaled_font->scale.xx;
rounded_delta = _cairo_lround (delta);
if (rounded_delta != 0) {
_cairo_output_stream_printf (word_wrap_stream,
"> %d <",
rounded_delta);
}
delta = rounded_delta*scaled_font->scale.xx/-1000.0;
Tm_x += delta;
}
_cairo_output_stream_printf (word_wrap_stream,
"%0*x>] TJ\n",
hex_width,
subset_glyph.subset_glyph_index);
Tm_x += subset_glyph.x_advance;
in_TJ = FALSE;
} else {
if (i != 0) {
_cairo_output_stream_printf (word_wrap_stream,
"%f %f Td ",
(glyphs[i].x - Tlm_x)/scaled_font->scale.xx,
(glyphs[i].y - Tlm_y)/scaled_font->scale.yy);
Tlm_x = glyphs[i].x;
Tlm_y = glyphs[i].y;
Tm_x = Tlm_x;
}
_cairo_output_stream_printf (word_wrap_stream,
"<%0*x> Tj ",
hex_width,
subset_glyph.subset_glyph_index);
Tm_x += subset_glyph.x_advance;
}
}
} else {
_cairo_output_stream_printf (word_wrap_stream,
"<%0*x> Tj\n",
hex_width,
subset_glyph.subset_glyph_index);
}
/* Check if glyph advance used to position every glyph */
x = pdf_operators->cur_x;
for (i = 0; i < pdf_operators->num_glyphs; i++) {
if (fabs(pdf_operators->glyphs[i].x_position - x) > GLYPH_POSITION_TOLERANCE)
break;
x += pdf_operators->glyphs[i].x_advance;
}
if (i == pdf_operators->num_glyphs) {
status = _cairo_pdf_operators_emit_glyph_string (pdf_operators,
word_wrap_stream);
} else {
status = _cairo_pdf_operators_emit_glyph_string_with_positioning (
pdf_operators, word_wrap_stream);
}
_cairo_output_stream_printf (word_wrap_stream,
"ET\n");
pdf_operators->num_glyphs = 0;
status = _cairo_output_stream_destroy (word_wrap_stream);
if (status)
return status;
return status;
}
static cairo_status_t
_cairo_pdf_operators_add_glyph (cairo_pdf_operators_t *pdf_operators,
cairo_scaled_font_subsets_glyph_t *glyph,
double x_position)
{
double x, y;
x = glyph->x_advance;
y = glyph->y_advance;
if (glyph->is_scaled)
cairo_matrix_transform_distance (&pdf_operators->font_matrix_inverse, &x, &y);
pdf_operators->glyphs[pdf_operators->num_glyphs].x_position = x_position;
pdf_operators->glyphs[pdf_operators->num_glyphs].glyph_index = glyph->subset_glyph_index;
pdf_operators->glyphs[pdf_operators->num_glyphs].x_advance = x;
pdf_operators->num_glyphs++;
if (pdf_operators->num_glyphs == PDF_GLYPH_BUFFER_SIZE)
return _cairo_pdf_operators_flush_glyphs (pdf_operators);
return CAIRO_STATUS_SUCCESS;
}
/* Use 'Tm' operator to set the PDF text matrix. */
static cairo_status_t
_cairo_pdf_operators_set_text_matrix (cairo_pdf_operators_t *pdf_operators,
cairo_matrix_t *matrix)
{
cairo_matrix_t inverse;
cairo_status_t status;
/* We require the matrix to be invertable. */
inverse = *matrix;
status = cairo_matrix_invert (&inverse);
if (status)
return status;
pdf_operators->text_matrix = *matrix;
pdf_operators->cur_x = 0;
pdf_operators->cur_y = 0;
_cairo_output_stream_printf (pdf_operators->stream,
"%f %f %f %f %f %f Tm\n",
pdf_operators->text_matrix.xx,
pdf_operators->text_matrix.yx,
pdf_operators->text_matrix.xy,
pdf_operators->text_matrix.yy,
pdf_operators->text_matrix.x0,
pdf_operators->text_matrix.y0);
pdf_operators->cairo_to_pdftext = *matrix;
status = cairo_matrix_invert (&pdf_operators->cairo_to_pdftext);
assert (status == CAIRO_STATUS_SUCCESS);
cairo_matrix_multiply (&pdf_operators->cairo_to_pdftext,
&pdf_operators->cairo_to_pdf,
&pdf_operators->cairo_to_pdftext);
return _cairo_output_stream_get_status (pdf_operators->stream);
}
#define TEXT_MATRIX_TOLERANCE 1e-6
/* Set the translation components of the PDF text matrix to x, y. The
* 'Td' operator is used to transform the text matrix.
*/
static cairo_status_t
_cairo_pdf_operators_set_text_position (cairo_pdf_operators_t *pdf_operators,
double x,
double y)
{
cairo_matrix_t translate, inverse;
cairo_status_t status;
/* The Td operator transforms the text_matrix with:
*
* text_matrix' = T x text_matrix
*
* where T is a translation matrix with the translation components
* set to the Td operands tx and ty.
*/
inverse = pdf_operators->text_matrix;
status = cairo_matrix_invert (&inverse);
assert (status == CAIRO_STATUS_SUCCESS);
pdf_operators->text_matrix.x0 = x;
pdf_operators->text_matrix.y0 = y;
cairo_matrix_multiply (&translate, &pdf_operators->text_matrix, &inverse);
if (fabs(translate.x0) < TEXT_MATRIX_TOLERANCE)
translate.x0 = 0.0;
if (fabs(translate.y0) < TEXT_MATRIX_TOLERANCE)
translate.y0 = 0.0;
_cairo_output_stream_printf (pdf_operators->stream,
"%f %f Td\n",
translate.x0,
translate.y0);
pdf_operators->cur_x = 0;
pdf_operators->cur_y = 0;
pdf_operators->cairo_to_pdftext = pdf_operators->text_matrix;
status = cairo_matrix_invert (&pdf_operators->cairo_to_pdftext);
assert (status == CAIRO_STATUS_SUCCESS);
cairo_matrix_multiply (&pdf_operators->cairo_to_pdftext,
&pdf_operators->cairo_to_pdf,
&pdf_operators->cairo_to_pdftext);
return _cairo_output_stream_get_status (pdf_operators->stream);
}
/* Select the font using the 'Tf' operator. The font size is set to 1
* as we use the 'Tm' operator to set the font scale.
*/
static cairo_status_t
_cairo_pdf_operators_set_font_subset (cairo_pdf_operators_t *pdf_operators,
cairo_scaled_font_subsets_glyph_t *subset_glyph)
{
cairo_status_t status;
_cairo_output_stream_printf (pdf_operators->stream,
"/f-%d-%d 1 Tf\n",
subset_glyph->font_id,
subset_glyph->subset_id);
if (pdf_operators->use_font_subset) {
status = pdf_operators->use_font_subset (subset_glyph->font_id,
subset_glyph->subset_id,
pdf_operators->use_font_subset_closure);
if (status)
return status;
}
pdf_operators->font_id = subset_glyph->font_id;
pdf_operators->subset_id = subset_glyph->subset_id;
if (subset_glyph->is_composite)
pdf_operators->hex_width = 4;
else
pdf_operators->hex_width = 2;
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_pdf_operators_begin_text (cairo_pdf_operators_t *pdf_operators)
{
_cairo_output_stream_printf (pdf_operators->stream, "BT\n");
pdf_operators->in_text_object = TRUE;
pdf_operators->num_glyphs = 0;
return _cairo_output_stream_get_status (pdf_operators->stream);
}
static cairo_status_t
_cairo_pdf_operators_end_text (cairo_pdf_operators_t *pdf_operators)
{
cairo_status_t status;
status = _cairo_pdf_operators_flush_glyphs (pdf_operators);
if (status)
return status;
_cairo_output_stream_printf (pdf_operators->stream, "ET\n");
pdf_operators->in_text_object = FALSE;
return _cairo_output_stream_get_status (pdf_operators->stream);
}
/* Compare the scale components of two matrices. The translation
* components are ignored. */
static cairo_bool_t
_cairo_matrix_scale_equal (cairo_matrix_t *a, cairo_matrix_t *b)
{
return (a->xx == b->xx &&
a->xy == b->xy &&
a->yx == b->yx &&
a->yy == b->yy);
}
static cairo_status_t
_cairo_pdf_operators_begin_actualtext (cairo_pdf_operators_t *pdf_operators,
const char *utf8,
int utf8_len)
{
uint16_t *utf16;
int utf16_len;
cairo_status_t status;
int i;
_cairo_output_stream_printf (pdf_operators->stream, "/Span << /ActualText <feff");
if (utf8_len) {
status = _cairo_utf8_to_utf16 (utf8, utf8_len, &utf16, &utf16_len);
if (status)
return status;
for (i = 0; i < utf16_len; i++) {
_cairo_output_stream_printf (pdf_operators->stream,
"%04x", (int) (utf16[i]));
}
free (utf16);
}
_cairo_output_stream_printf (pdf_operators->stream, "> >> BDC\n");
return _cairo_output_stream_get_status (pdf_operators->stream);
}
static cairo_status_t
_cairo_pdf_operators_end_actualtext (cairo_pdf_operators_t *pdf_operators)
{
_cairo_output_stream_printf (pdf_operators->stream, "EMC\n");
return _cairo_output_stream_get_status (pdf_operators->stream);
}
static cairo_status_t
_cairo_pdf_operators_emit_glyph (cairo_pdf_operators_t *pdf_operators,
cairo_glyph_t *glyph,
cairo_scaled_font_subsets_glyph_t *subset_glyph)
{
double x, y;
cairo_status_t status;
if (pdf_operators->is_new_text_object ||
pdf_operators->font_id != subset_glyph->font_id ||
pdf_operators->subset_id != subset_glyph->subset_id)
{
status = _cairo_pdf_operators_flush_glyphs (pdf_operators);
if (status)
return status;
status = _cairo_pdf_operators_set_font_subset (pdf_operators, subset_glyph);
if (status)
return status;
pdf_operators->is_new_text_object = FALSE;
}
x = glyph->x;
y = glyph->y;
cairo_matrix_transform_point (&pdf_operators->cairo_to_pdftext, &x, &y);
/* The TJ operator for displaying text strings can only set
* the horizontal position of the glyphs. If the y position
* (in text space) changes, use the Td operator to change the
* current position to the next glyph. We also use the Td
* operator to move the current position if the horizontal
* position changes by more than 10 (in text space
* units). This is becauses the horizontal glyph positioning
* in the TJ operator is intended for kerning and there may be
* PDF consumers that do not handle very large position
* adjustments in TJ.
*/
if (fabs(x - pdf_operators->cur_x) > 10 ||
fabs(y - pdf_operators->cur_y) > GLYPH_POSITION_TOLERANCE)
{
status = _cairo_pdf_operators_flush_glyphs (pdf_operators);
if (status)
return status;
x = glyph->x;
y = glyph->y;
cairo_matrix_transform_point (&pdf_operators->cairo_to_pdf, &x, &y);
status = _cairo_pdf_operators_set_text_position (pdf_operators, x, y);
if (status)
return status;
x = 0.0;
y = 0.0;
}
status = _cairo_pdf_operators_add_glyph (pdf_operators,
subset_glyph,
x);
return status;
}
/* A utf8_len of -1 indicates no unicode text. A utf8_len = 0 is an
* empty string.
*/
static cairo_int_status_t
_cairo_pdf_operators_emit_cluster (cairo_pdf_operators_t *pdf_operators,
const char *utf8,
int utf8_len,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_bool_t backward,
cairo_scaled_font_t *scaled_font)
{
cairo_scaled_font_subsets_glyph_t subset_glyph;
cairo_glyph_t *cur_glyph;
cairo_status_t status;
int i;
/* If the cluster maps 1 glyph to 1 or more unicode characters, we
* first try _map_glyph() with the unicode string to see if it can
* use toUnicode to map our glyph to the unicode. This will fail
* if the glyph is already mapped to a different unicode string.
*
* We also go through this path if no unicode mapping was
* supplied (utf8_len < 0).
*
* Mapping a glyph to a zero length unicode string requires the
* use of ActualText.
*/
if (num_glyphs == 1 && utf8_len != 0) {
status = _cairo_scaled_font_subsets_map_glyph (pdf_operators->font_subsets,
scaled_font,
glyphs->index,
utf8,
utf8_len < 0 ? 0 : utf8_len,
&subset_glyph);
if (status)
return status;
if (subset_glyph.utf8_is_mapped || utf8_len < 0) {
status = _cairo_pdf_operators_emit_glyph (pdf_operators,
glyphs,
&subset_glyph);
return 0;
}
}
/* Fallback to using ActualText to map zero or more glyphs to a
* unicode string. */
_cairo_pdf_operators_flush_glyphs (pdf_operators);
status = _cairo_pdf_operators_begin_actualtext (pdf_operators, utf8, utf8_len);
cur_glyph = glyphs;
for (i = 0; i < num_glyphs; i++) {
status = _cairo_scaled_font_subsets_map_glyph (pdf_operators->font_subsets,
scaled_font,
cur_glyph->index,
NULL, 0,
&subset_glyph);
if (status)
return status;
status = _cairo_pdf_operators_emit_glyph (pdf_operators,
cur_glyph,
&subset_glyph);
if (status)
return status;
if (backward)
cur_glyph--;
else
cur_glyph++;
}
status = _cairo_pdf_operators_flush_glyphs (pdf_operators);
if (status)
return status;
status = _cairo_pdf_operators_end_actualtext (pdf_operators);
return status;
}
cairo_int_status_t
_cairo_pdf_operators_show_text_glyphs (cairo_pdf_operators_t *pdf_operators,
const char *utf8,
int utf8_len,
cairo_glyph_t *glyphs,
int num_glyphs,
const cairo_text_cluster_t *clusters,
int num_clusters,
cairo_bool_t backward,
cairo_scaled_font_t *scaled_font)
{
cairo_status_t status;
int i;
cairo_matrix_t text_matrix, invert_y_axis;
double x, y;
const char *cur_text;
cairo_glyph_t *cur_glyph;
pdf_operators->font_matrix_inverse = scaled_font->font_matrix;
status = cairo_matrix_invert (&pdf_operators->font_matrix_inverse);
if (status == CAIRO_STATUS_INVALID_MATRIX)
return CAIRO_STATUS_SUCCESS;
if (status)
return status;
pdf_operators->is_new_text_object = FALSE;
if (pdf_operators->in_text_object == FALSE) {
_cairo_pdf_operators_begin_text (pdf_operators);
/* Force Tm and Tf to be emitted when starting a new text
* object.*/
pdf_operators->is_new_text_object = TRUE;
}
cairo_matrix_init_scale (&invert_y_axis, 1, -1);
text_matrix = scaled_font->scale;
/* Invert y axis in font space */
cairo_matrix_multiply (&text_matrix, &text_matrix, &invert_y_axis);
/* Invert y axis in device space */
cairo_matrix_multiply (&text_matrix, &invert_y_axis, &text_matrix);
if (pdf_operators->is_new_text_object ||
! _cairo_matrix_scale_equal (&pdf_operators->text_matrix, &text_matrix))
{
_cairo_pdf_operators_flush_glyphs (pdf_operators);
x = glyphs[0].x;
y = glyphs[0].y;
cairo_matrix_transform_point (&pdf_operators->cairo_to_pdf, &x, &y);
text_matrix.x0 = x;
text_matrix.y0 = y;
status = _cairo_pdf_operators_set_text_matrix (pdf_operators, &text_matrix);
if (status == CAIRO_STATUS_INVALID_MATRIX)
return CAIRO_STATUS_SUCCESS;
if (status)
return status;
}
if (num_clusters > 0) {
cur_text = utf8;
if (backward)
cur_glyph = glyphs + num_glyphs;
else
cur_glyph = glyphs;
for (i = 0; i < num_clusters; i++) {
if (backward)
cur_glyph -= clusters[i].num_glyphs;
status = _cairo_pdf_operators_emit_cluster (pdf_operators,
cur_text,
clusters[i].num_bytes,
cur_glyph,
clusters[i].num_glyphs,
backward,
scaled_font);
if (status)
return status;
cur_text += clusters[i].num_bytes;
if (!backward)
cur_glyph += clusters[i].num_glyphs;
}
} else {
for (i = 0; i < num_glyphs; i++) {
status = _cairo_pdf_operators_emit_cluster (pdf_operators,
NULL,
-1, /* no unicode string available */
&glyphs[i],
1,
FALSE,
scaled_font);
if (status)
return status;
}
}
return _cairo_output_stream_get_status (pdf_operators->stream);
}

Просмотреть файл

@ -90,8 +90,13 @@ typedef struct _cairo_pdf_smask_group
cairo_stroke_style_t *style;
cairo_matrix_t ctm;
cairo_matrix_t ctm_inverse;
char *utf8;
int utf8_len;
cairo_glyph_t *glyphs;
int num_glyphs;
cairo_text_cluster_t *clusters;
int num_clusters;
cairo_bool_t backward;
cairo_scaled_font_t *scaled_font;
} cairo_pdf_smask_group_t;
@ -153,6 +158,13 @@ struct _cairo_pdf_surface {
cairo_bool_t force_fallbacks;
cairo_bool_t current_pattern_is_solid_color;
cairo_bool_t current_color_is_stroke;
double current_color_red;
double current_color_green;
double current_color_blue;
double current_color_alpha;
cairo_surface_t *paginated_surface;
};

Просмотреть файл

@ -48,6 +48,7 @@
#include "cairo-paginated-private.h"
#include "cairo-output-stream-private.h"
#include "cairo-meta-surface-private.h"
#include "cairo-type3-glyph-surface-private.h"
#include <time.h>
#include <zlib.h>
@ -281,6 +282,7 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output,
surface->force_fallbacks = FALSE;
surface->select_pattern_gstate_saved = FALSE;
surface->current_pattern_is_solid_color = FALSE;
_cairo_pdf_operators_init (&surface->pdf_operators,
surface->output,
@ -301,9 +303,13 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output,
CAIRO_CONTENT_COLOR_ALPHA,
width, height,
&cairo_pdf_surface_paginated_backend);
status = surface->paginated_surface->status;
if (status == CAIRO_STATUS_SUCCESS)
if (status == CAIRO_STATUS_SUCCESS) {
/* paginated keeps the only reference to surface now, drop ours */
cairo_surface_destroy (&surface->base);
return surface->paginated_surface;
}
BAIL1:
_cairo_scaled_font_subsets_destroy (surface->font_subsets);
@ -741,8 +747,12 @@ _cairo_pdf_smask_group_destroy (cairo_pdf_smask_group_t *group)
cairo_pattern_destroy (group->source);
if (group->mask)
cairo_pattern_destroy (group->mask);
if (group->utf8)
free (group->utf8);
if (group->glyphs)
free (group->glyphs);
if (group->clusters)
free (group->clusters);
if (group->scaled_font)
cairo_scaled_font_destroy (group->scaled_font);
free (group);
@ -771,15 +781,23 @@ _cairo_pdf_surface_add_pdf_pattern (cairo_pdf_surface_t *surface,
return CAIRO_STATUS_SUCCESS;
}
/* Gradients with zero stops do not produce any output */
if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR ||
pattern->type == CAIRO_PATTERN_TYPE_RADIAL)
{
cairo_gradient_pattern_t *gradient;
gradient = (cairo_gradient_pattern_t *) pattern;
/* Gradients with zero stops do not produce any output */
if (gradient->n_stops == 0)
return CAIRO_INT_STATUS_NOTHING_TO_DO;
/* Gradients with one stop are the same as solid colors */
if (gradient->n_stops == 1) {
pattern_res->id = 0;
gstate_res->id = 0;
return CAIRO_STATUS_SUCCESS;
}
}
pdf_pattern.pattern = cairo_pattern_reference (pattern);
@ -851,6 +869,8 @@ _cairo_pdf_surface_open_stream (cairo_pdf_surface_t *surface,
surface->pdf_stream.self = self;
surface->pdf_stream.length = length;
surface->pdf_stream.compressed = compressed;
surface->current_pattern_is_solid_color = FALSE;
_cairo_pdf_operators_reset (&surface->pdf_operators);
_cairo_output_stream_printf (surface->output,
"%d 0 obj\n"
@ -892,6 +912,10 @@ _cairo_pdf_surface_close_stream (cairo_pdf_surface_t *surface)
if (! surface->pdf_stream.active)
return CAIRO_STATUS_SUCCESS;
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (status)
return status;
if (surface->pdf_stream.compressed) {
status = _cairo_output_stream_destroy (surface->output);
surface->output = surface->pdf_stream.old_output;
@ -982,6 +1006,8 @@ _cairo_pdf_surface_open_group (cairo_pdf_surface_t *surface,
assert (surface->group_stream.active == FALSE);
surface->group_stream.active = TRUE;
surface->current_pattern_is_solid_color = FALSE;
_cairo_pdf_operators_reset (&surface->pdf_operators);
surface->group_stream.mem_stream = _cairo_memory_stream_create ();
@ -1033,6 +1059,10 @@ _cairo_pdf_surface_close_group (cairo_pdf_surface_t *surface,
assert (surface->pdf_stream.active == FALSE);
assert (surface->group_stream.active == TRUE);
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (status)
return status;
if (surface->compress_content) {
status = _cairo_output_stream_destroy (surface->group_stream.stream);
surface->group_stream.stream = NULL;
@ -1116,6 +1146,10 @@ _cairo_pdf_surface_close_content_stream (cairo_pdf_surface_t *surface)
assert (surface->pdf_stream.active == TRUE);
assert (surface->group_stream.active == FALSE);
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (status)
return status;
_cairo_output_stream_printf (surface->output, "Q\n");
status = _cairo_pdf_surface_close_stream (surface);
if (status)
@ -1181,7 +1215,10 @@ _cairo_pdf_surface_finish (void *abstract_surface)
"%%%%EOF\n",
offset);
_cairo_pdf_operators_fini (&surface->pdf_operators);
status2 = _cairo_pdf_operators_fini (&surface->pdf_operators);
/* pdf_operators has already been flushed when the last stream was
* closed so we should never be writing anything here. */
assert(status2 == CAIRO_STATUS_SUCCESS);
/* close any active streams still open due to fatal errors */
status2 = _cairo_pdf_surface_close_stream (surface);
@ -1230,13 +1267,23 @@ _cairo_pdf_surface_finish (void *abstract_surface)
static cairo_int_status_t
_cairo_pdf_surface_start_page (void *abstract_surface)
{
cairo_pdf_surface_t *surface = abstract_surface;
_cairo_pdf_group_resources_clear (&surface->resources);
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
_cairo_pdf_surface_has_fallback_images (void *abstract_surface,
cairo_bool_t has_fallbacks)
{
cairo_status_t status;
cairo_pdf_surface_t *surface = abstract_surface;
surface->has_fallback_images = FALSE;
_cairo_pdf_group_resources_clear (&surface->resources);
status = _cairo_pdf_surface_open_content_stream (surface, TRUE);
surface->has_fallback_images = has_fallbacks;
status = _cairo_pdf_surface_open_content_stream (surface, has_fallbacks);
if (status)
return status;
@ -1496,7 +1543,7 @@ _cairo_pdf_surface_emit_meta_surface (cairo_pdf_surface_t *surface,
cairo_paginated_mode_t old_paginated_mode;
cairo_clip_t *old_clip;
cairo_rectangle_int_t meta_extents;
cairo_status_t status, status2;
cairo_status_t status;
int alpha = 0;
status = _cairo_surface_get_extents (meta_surface, &meta_extents);
@ -1524,7 +1571,7 @@ _cairo_pdf_surface_emit_meta_surface (cairo_pdf_surface_t *surface,
if (cairo_surface_get_content (meta_surface) == CAIRO_CONTENT_COLOR) {
status = _cairo_pdf_surface_add_alpha (surface, 1.0, &alpha);
if (status)
goto CLEANUP_GROUP;
return status;
_cairo_output_stream_printf (surface->output,
"q /a%d gs 0 0 0 rg 0 0 %f %f re f Q\n",
@ -1537,18 +1584,18 @@ _cairo_pdf_surface_emit_meta_surface (cairo_pdf_surface_t *surface,
CAIRO_META_REGION_NATIVE);
assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
if (status)
goto CLEANUP_GROUP;
return status;
status = _cairo_surface_set_clip (&surface->base, old_clip);
if (status)
return status;
status = _cairo_pdf_surface_close_content_stream (surface);
CLEANUP_GROUP:
_cairo_pdf_surface_set_size_internal (surface,
old_width,
old_height);
surface->paginated_mode = old_paginated_mode;
status2 = _cairo_surface_set_clip (&surface->base, old_clip);
if (status == CAIRO_STATUS_SUCCESS)
status = status2;
return status;
}
@ -2562,29 +2609,73 @@ _cairo_pdf_surface_select_pattern (cairo_pdf_surface_t *surface,
{
cairo_status_t status;
int alpha;
cairo_bool_t is_solid_color = FALSE;
cairo_color_t *solid_color;
if (pattern->type == CAIRO_PATTERN_TYPE_SOLID) {
cairo_solid_pattern_t *solid_pattern = (cairo_solid_pattern_t *) pattern;
cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) pattern;
status = _cairo_pdf_surface_add_alpha (surface, solid_pattern->color.alpha, &alpha);
if (status)
return status;
is_solid_color = TRUE;
solid_color = &solid->color;
}
_cairo_output_stream_printf (surface->output,
"%f %f %f ",
solid_pattern->color.red,
solid_pattern->color.green,
solid_pattern->color.blue);
if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR ||
pattern->type == CAIRO_PATTERN_TYPE_RADIAL)
{
cairo_gradient_pattern_t *gradient = (cairo_gradient_pattern_t *) pattern;
if (is_stroke)
_cairo_output_stream_printf (surface->output, "RG ");
else
_cairo_output_stream_printf (surface->output, "rg ");
if (gradient->n_stops == 1) {
is_solid_color = TRUE;
solid_color = &gradient->stops[0].color;
}
}
_cairo_output_stream_printf (surface->output,
"/a%d gs\n",
alpha);
surface->select_pattern_gstate_saved = FALSE;
if (is_solid_color) {
if (surface->current_pattern_is_solid_color == FALSE ||
surface->current_color_red != solid_color->red ||
surface->current_color_green != solid_color->green ||
surface->current_color_blue != solid_color->blue ||
surface->current_color_is_stroke != is_stroke)
{
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (status)
return status;
_cairo_output_stream_printf (surface->output,
"%f %f %f ",
solid_color->red,
solid_color->green,
solid_color->blue);
if (is_stroke)
_cairo_output_stream_printf (surface->output, "RG ");
else
_cairo_output_stream_printf (surface->output, "rg ");
surface->current_color_red = solid_color->red;
surface->current_color_green = solid_color->green;
surface->current_color_blue = solid_color->blue;
surface->current_color_is_stroke = is_stroke;
}
if (surface->current_pattern_is_solid_color == FALSE ||
surface->current_color_alpha != solid_color->alpha)
{
status = _cairo_pdf_surface_add_alpha (surface, solid_color->alpha, &alpha);
if (status)
return status;
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (status)
return status;
_cairo_output_stream_printf (surface->output,
"/a%d gs\n",
alpha);
surface->current_color_alpha = solid_color->alpha;
}
surface->current_pattern_is_solid_color = TRUE;
} else {
status = _cairo_pdf_surface_add_alpha (surface, 1.0, &alpha);
if (status)
@ -2594,6 +2685,10 @@ _cairo_pdf_surface_select_pattern (cairo_pdf_surface_t *surface,
if (status)
return status;
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (status)
return status;
/* fill-stroke calls select_pattern twice. Don't save if the
* gstate is already saved. */
if (!surface->select_pattern_gstate_saved)
@ -2612,17 +2707,28 @@ _cairo_pdf_surface_select_pattern (cairo_pdf_surface_t *surface,
"/a%d gs\n",
alpha);
surface->select_pattern_gstate_saved = TRUE;
surface->current_pattern_is_solid_color = FALSE;
}
return _cairo_output_stream_get_status (surface->output);
}
static void
static cairo_int_status_t
_cairo_pdf_surface_unselect_pattern (cairo_pdf_surface_t *surface)
{
if (surface->select_pattern_gstate_saved)
cairo_int_status_t status;
if (surface->select_pattern_gstate_saved) {
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (status)
return status;
_cairo_output_stream_printf (surface->output, "Q\n");
_cairo_pdf_operators_reset (&surface->pdf_operators);
}
surface->select_pattern_gstate_saved = FALSE;
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
@ -2671,9 +2777,17 @@ _cairo_pdf_surface_intersect_clip_path (void *abstract_surface,
cairo_antialias_t antialias)
{
cairo_pdf_surface_t *surface = abstract_surface;
cairo_int_status_t status;
if (path == NULL) {
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (status)
return status;
_cairo_output_stream_printf (surface->output, "Q q\n");
surface->current_pattern_is_solid_color = FALSE;
_cairo_pdf_operators_reset (&surface->pdf_operators);
return CAIRO_STATUS_SUCCESS;
}
@ -2743,34 +2857,54 @@ _cairo_pdf_surface_write_pages (cairo_pdf_surface_t *surface)
"endobj\n");
}
static cairo_status_t
_cairo_pdf_surface_emit_unicode_for_glyph (cairo_pdf_surface_t *surface,
const char *utf8)
{
uint16_t *utf16 = NULL;
int utf16_len = 0;
cairo_status_t status;
int i;
if (utf8 && *utf8) {
status = _cairo_utf8_to_utf16 (utf8, -1, &utf16, &utf16_len);
if (status && status != CAIRO_STATUS_INVALID_STRING)
return status;
}
_cairo_output_stream_printf (surface->output, "<");
if (utf16 == NULL || utf16_len == 0) {
/* According to the "ToUnicode Mapping File Tutorial"
* http://www.adobe.com/devnet/acrobat/pdfs/5411.ToUnicode.pdf
*
* Glyphs that do not map to a Unicode code point must be
* mapped to 0xfffd "REPLACEMENT CHARACTER".
*/
_cairo_output_stream_printf (surface->output,
"fffd");
} else {
for (i = 0; i < utf16_len; i++)
_cairo_output_stream_printf (surface->output,
"%04x", (int) (utf16[i]));
}
_cairo_output_stream_printf (surface->output, ">");
if (utf16)
free (utf16);
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
_cairo_pdf_surface_emit_to_unicode_stream (cairo_pdf_surface_t *surface,
cairo_scaled_font_subset_t *font_subset,
cairo_bool_t is_composite,
cairo_pdf_resource_t *stream)
{
const cairo_scaled_font_backend_t *backend;
unsigned int i, num_bfchar;
cairo_int_status_t status;
stream->id = 0;
if (font_subset->to_unicode == NULL)
return CAIRO_INT_STATUS_UNSUPPORTED;
status = _cairo_truetype_create_glyph_to_unicode_map (font_subset);
if (status) {
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
backend = font_subset->scaled_font->backend;
if (backend->map_glyphs_to_unicode == NULL)
return CAIRO_INT_STATUS_UNSUPPORTED;
status = backend->map_glyphs_to_unicode (font_subset->scaled_font,
font_subset);
if (status)
return status;
}
status = _cairo_pdf_surface_open_stream (surface,
NULL,
@ -2804,10 +2938,12 @@ _cairo_pdf_surface_emit_to_unicode_stream (cairo_pdf_surface_t *surface,
"endcodespacerange\n");
num_bfchar = font_subset->num_glyphs - 1;
/* The CMap specification has a limit of 100 characters per beginbfchar operator */
_cairo_output_stream_printf (surface->output,
"%d beginbfchar\n",
num_bfchar > 100 ? 100 : num_bfchar);
for (i = 0; i < num_bfchar; i++) {
if (i != 0 && i % 100 == 0) {
_cairo_output_stream_printf (surface->output,
@ -2817,13 +2953,16 @@ _cairo_pdf_surface_emit_to_unicode_stream (cairo_pdf_surface_t *surface,
}
if (is_composite) {
_cairo_output_stream_printf (surface->output,
"<%04x> <%04lx>\n",
i + 1, font_subset->to_unicode[i + 1]);
"<%04x> ",
i + 1);
} else {
_cairo_output_stream_printf (surface->output,
"<%02x> <%04lx>\n",
i + 1, font_subset->to_unicode[i + 1]);
"<%02x> ",
i + 1);
}
_cairo_pdf_surface_emit_unicode_for_glyph (surface, font_subset->utf8[i + 1]);
_cairo_output_stream_printf (surface->output,
"\n");
}
_cairo_output_stream_printf (surface->output,
"endbfchar\n");
@ -3301,71 +3440,18 @@ _cairo_pdf_surface_emit_truetype_font_subset (cairo_pdf_surface_t *surface,
return status;
}
static cairo_int_status_t
_cairo_pdf_surface_emit_bitmap_glyph (cairo_pdf_surface_t *surface,
cairo_scaled_font_t *scaled_font,
unsigned long glyph_index,
cairo_pdf_resource_t *glyph_ret,
cairo_box_t *bbox,
double *width)
static cairo_status_t
_cairo_pdf_emit_imagemask (cairo_image_surface_t *image,
cairo_output_stream_t *stream)
{
cairo_scaled_glyph_t *scaled_glyph;
cairo_status_t status;
cairo_image_surface_t *image;
unsigned char *row, *byte;
int rows, cols;
double x_advance, y_advance;
unsigned char *byte, output_byte;
int row, col, num_cols;
status = _cairo_scaled_glyph_lookup (scaled_font,
glyph_index,
CAIRO_SCALED_GLYPH_INFO_METRICS|
CAIRO_SCALED_GLYPH_INFO_SURFACE,
&scaled_glyph);
if (status)
return status;
/* The only image type supported by Type 3 fonts are 1-bit image
* masks */
assert (image->format == CAIRO_FORMAT_A1);
x_advance = scaled_glyph->metrics.x_advance;
y_advance = scaled_glyph->metrics.y_advance;
cairo_matrix_transform_distance (&scaled_font->ctm, &x_advance, &y_advance);
*bbox = scaled_glyph->bbox;
*width = x_advance;
image = scaled_glyph->surface;
if (image->format != CAIRO_FORMAT_A1) {
image = _cairo_image_surface_clone (image, CAIRO_FORMAT_A1);
status = cairo_surface_status (&image->base);
if (status)
return status;
}
status = _cairo_pdf_surface_open_stream (surface,
NULL,
surface->compress_content,
NULL);
if (status) {
if (image != scaled_glyph->surface)
cairo_surface_destroy (&image->base);
return status;
}
*glyph_ret = surface->pdf_stream.self;
_cairo_output_stream_printf (surface->output,
"%f 0 %f %f %f %f d1\n",
x_advance,
_cairo_fixed_to_double (scaled_glyph->bbox.p1.x),
_cairo_fixed_to_double (scaled_glyph->bbox.p2.y),
_cairo_fixed_to_double (scaled_glyph->bbox.p2.x),
_cairo_fixed_to_double (scaled_glyph->bbox.p1.y));
_cairo_output_stream_printf (surface->output,
"%f 0 0 %f %f %f cm\n",
_cairo_fixed_to_double (scaled_glyph->bbox.p2.x) - _cairo_fixed_to_double (scaled_glyph->bbox.p1.x),
_cairo_fixed_to_double (scaled_glyph->bbox.p1.y) - _cairo_fixed_to_double (scaled_glyph->bbox.p2.y),
_cairo_fixed_to_double (scaled_glyph->bbox.p1.x),
_cairo_fixed_to_double (scaled_glyph->bbox.p2.y));
_cairo_output_stream_printf (surface->output,
_cairo_output_stream_printf (stream,
"BI\n"
"/IM true\n"
"/W %d\n"
@ -3375,23 +3461,23 @@ _cairo_pdf_surface_emit_bitmap_glyph (cairo_pdf_surface_t *surface,
image->width,
image->height);
_cairo_output_stream_printf (surface->output,
_cairo_output_stream_printf (stream,
"ID ");
for (row = image->data, rows = image->height; rows; row += image->stride, rows--) {
for (byte = row, cols = (image->width + 7) / 8; cols; byte++, cols--) {
unsigned char output_byte = CAIRO_BITSWAP8_IF_LITTLE_ENDIAN (*byte);
_cairo_output_stream_write (surface->output, &output_byte, 1);
num_cols = (image->width + 7) / 8;
for (row = 0; row < image->height; row++) {
byte = image->data + row * image->stride;
for (col = 0; col < num_cols; col++) {
output_byte = CAIRO_BITSWAP8_IF_LITTLE_ENDIAN (*byte);
_cairo_output_stream_write (stream, &output_byte, 1);
byte++;
}
}
_cairo_output_stream_printf (surface->output,
_cairo_output_stream_printf (stream,
"\nEI\n");
status = _cairo_pdf_surface_close_stream (surface);
if (image != scaled_glyph->surface)
cairo_surface_destroy (&image->base);
return status;
return _cairo_output_stream_get_status (stream);
}
static cairo_status_t
@ -3406,6 +3492,7 @@ _cairo_pdf_surface_emit_type3_font_subset (cairo_pdf_surface_t *surface,
unsigned int i;
cairo_box_t font_bbox = {{0,0},{0,0}};
cairo_box_t bbox = {{0,0},{0,0}};
cairo_surface_t *type3_surface;
if (font_subset->num_glyphs == 0)
return CAIRO_STATUS_SUCCESS;
@ -3426,13 +3513,29 @@ _cairo_pdf_surface_emit_type3_font_subset (cairo_pdf_surface_t *surface,
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
type3_surface = _cairo_type3_glyph_surface_create (font_subset->scaled_font,
NULL,
_cairo_pdf_emit_imagemask);
for (i = 0; i < font_subset->num_glyphs; i++) {
status = _cairo_pdf_surface_emit_bitmap_glyph (surface,
font_subset->scaled_font,
font_subset->glyphs[i],
&glyphs[i],
&bbox,
&widths[i]);
status = _cairo_pdf_surface_open_stream (surface,
NULL,
surface->compress_content,
NULL);
glyphs[i] = surface->pdf_stream.self;
if (i == 0) {
status = _cairo_type3_glyph_surface_emit_notdef_glyph (type3_surface,
surface->output,
&bbox,
&widths[i]);
} else {
status = _cairo_type3_glyph_surface_emit_glyph (type3_surface,
surface->output,
font_subset->glyphs[i],
&bbox,
&widths[i]);
}
status = _cairo_pdf_surface_close_stream (surface);
if (status)
break;
@ -3452,6 +3555,7 @@ _cairo_pdf_surface_emit_type3_font_subset (cairo_pdf_surface_t *surface,
font_bbox.p2.y = bbox.p2.y;
}
}
cairo_surface_destroy (type3_surface);
if (status) {
free (glyphs);
free (widths);
@ -3512,20 +3616,16 @@ _cairo_pdf_surface_emit_type3_font_subset (cairo_pdf_surface_t *surface,
"<< /Type /Font\n"
" /Subtype /Type3\n"
" /FontBBox [%f %f %f %f]\n"
" /FontMatrix [ %f %f %f %f 0 0 ]\n"
" /FontMatrix [ 1 0 0 1 0 0 ]\n"
" /Encoding %d 0 R\n"
" /CharProcs %d 0 R\n"
" /FirstChar 0\n"
" /LastChar %d\n",
subset_resource.id,
_cairo_fixed_to_double (font_bbox.p1.x),
_cairo_fixed_to_double (font_bbox.p1.y),
- _cairo_fixed_to_double (font_bbox.p2.y),
_cairo_fixed_to_double (font_bbox.p2.x),
_cairo_fixed_to_double (font_bbox.p2.y),
matrix.xx,
matrix.yx,
-matrix.xy,
-matrix.yy,
- _cairo_fixed_to_double (font_bbox.p1.y),
encoding.id,
char_procs.id,
font_subset->num_glyphs - 1);
@ -3582,6 +3682,7 @@ _cairo_pdf_surface_emit_unscaled_font_subset (cairo_scaled_font_subset_t *font_s
status = _cairo_pdf_surface_emit_type1_fallback_font (surface, font_subset);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
}
ASSERT_NOT_REACHED;
@ -3730,7 +3831,9 @@ _cairo_pdf_surface_write_mask_group (cairo_pdf_surface_t *surface,
"0 0 %f %f re f\n",
surface->width, surface->height);
_cairo_pdf_surface_unselect_pattern (surface);
status = _cairo_pdf_surface_unselect_pattern (surface);
if (status)
return status;
}
status = _cairo_pdf_surface_close_group (surface, &mask_group);
@ -3783,7 +3886,9 @@ _cairo_pdf_surface_write_mask_group (cairo_pdf_surface_t *surface,
"0 0 %f %f re f\n",
surface->width, surface->height);
_cairo_pdf_surface_unselect_pattern (surface);
status = _cairo_pdf_surface_unselect_pattern (surface);
if (status)
return status;
}
status = _cairo_pdf_surface_close_group (surface, NULL);
@ -3872,16 +3977,21 @@ _cairo_pdf_surface_write_smask_group (cairo_pdf_surface_t *surface,
&group->ctm_inverse);
break;
case PDF_SHOW_GLYPHS:
status = _cairo_pdf_operators_show_glyphs (&surface->pdf_operators,
group->glyphs,
group->num_glyphs,
group->scaled_font);
status = _cairo_pdf_operators_show_text_glyphs (&surface->pdf_operators,
group->utf8, group->utf8_len,
group->glyphs, group->num_glyphs,
group->clusters, group->num_clusters,
group->backward,
group->scaled_font);
break;
}
if (status)
return status;
_cairo_pdf_surface_unselect_pattern (surface);
status = _cairo_pdf_surface_unselect_pattern (surface);
if (status)
return status;
status = _cairo_pdf_surface_close_group (surface, NULL);
_cairo_pdf_surface_set_size_internal (surface,
@ -4161,8 +4271,19 @@ _cairo_pdf_surface_analyze_operation (cairo_pdf_surface_t *surface,
cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern;
if (_cairo_surface_is_meta (surface_pattern->surface)) {
if (_cairo_pattern_is_opaque (pattern))
if (_cairo_pattern_is_opaque (pattern)) {
return CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN;
} else {
/* FIXME: The analysis surface does not yet have
* the capability to analyze a non opaque meta
* surface and mark it supported if there is
* nothing underneath. For now meta surfaces of
* type CONTENT_COLOR_ALPHA painted with
* OPERATOR_SOURCE will result in a fallback
* image. */
return CAIRO_INT_STATUS_UNSUPPORTED;
}
} else {
return _cairo_pdf_surface_analyze_surface_pattern_transparency (surface,
surface_pattern);
@ -4202,7 +4323,6 @@ _cairo_pdf_surface_start_fallback (cairo_pdf_surface_t *surface)
if (status)
return status;
surface->has_fallback_images = TRUE;
_cairo_pdf_group_resources_clear (&surface->resources);
return _cairo_pdf_surface_open_content_stream (surface, TRUE);
}
@ -4257,6 +4377,10 @@ _cairo_pdf_surface_paint (void *abstract_surface,
if (status)
return status;
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (status)
return status;
_cairo_output_stream_printf (surface->output,
"q /s%d gs /x%d Do Q\n",
gstate_res.id,
@ -4270,7 +4394,9 @@ _cairo_pdf_surface_paint (void *abstract_surface,
"0 0 %f %f re f\n",
surface->width, surface->height);
_cairo_pdf_surface_unselect_pattern (surface);
status = _cairo_pdf_surface_unselect_pattern (surface);
if (status)
return status;
}
return _cairo_output_stream_get_status (surface->output);
@ -4333,6 +4459,10 @@ _cairo_pdf_surface_mask (void *abstract_surface,
if (status)
return status;
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (status)
return status;
_cairo_output_stream_printf (surface->output,
"q /s%d gs /x%d Do Q\n",
group->group_res.id,
@ -4401,6 +4531,10 @@ _cairo_pdf_surface_stroke (void *abstract_surface,
if (status)
return status;
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (status)
return status;
_cairo_output_stream_printf (surface->output,
"q /s%d gs /x%d Do Q\n",
gstate_res.id,
@ -4418,7 +4552,9 @@ _cairo_pdf_surface_stroke (void *abstract_surface,
if (status)
return status;
_cairo_pdf_surface_unselect_pattern (surface);
status = _cairo_pdf_surface_unselect_pattern (surface);
if (status)
return status;
}
return _cairo_output_stream_get_status (surface->output);
@ -4485,6 +4621,10 @@ _cairo_pdf_surface_fill (void *abstract_surface,
if (status)
return status;
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (status)
return status;
_cairo_output_stream_printf (surface->output,
"q /s%d gs /x%d Do Q\n",
gstate_res.id,
@ -4500,7 +4640,9 @@ _cairo_pdf_surface_fill (void *abstract_surface,
if (status)
return status;
_cairo_pdf_surface_unselect_pattern (surface);
status = _cairo_pdf_surface_unselect_pattern (surface);
if (status)
return status;
}
return _cairo_output_stream_get_status (surface->output);
@ -4587,18 +4729,31 @@ _cairo_pdf_surface_fill_stroke (void *abstract_surface,
if (status)
return status;
_cairo_pdf_surface_unselect_pattern (surface);
status = _cairo_pdf_surface_unselect_pattern (surface);
if (status)
return status;
return _cairo_output_stream_get_status (surface->output);
}
static cairo_bool_t
_cairo_pdf_surface_has_show_text_glyphs (void *abstract_surface)
{
return TRUE;
}
static cairo_int_status_t
_cairo_pdf_surface_show_glyphs (void *abstract_surface,
cairo_operator_t op,
cairo_pattern_t *source,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font)
_cairo_pdf_surface_show_text_glyphs (void *abstract_surface,
cairo_operator_t op,
cairo_pattern_t *source,
const char *utf8,
int utf8_len,
cairo_glyph_t *glyphs,
int num_glyphs,
const cairo_text_cluster_t *clusters,
int num_clusters,
cairo_bool_t backward,
cairo_scaled_font_t *scaled_font)
{
cairo_pdf_surface_t *surface = abstract_surface;
cairo_status_t status;
@ -4626,13 +4781,37 @@ _cairo_pdf_surface_show_glyphs (void *abstract_surface,
group->operation = PDF_SHOW_GLYPHS;
group->source = cairo_pattern_reference (source);
group->source_res = pattern_res;
group->glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
if (group->glyphs == NULL) {
_cairo_pdf_smask_group_destroy (group);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
if (utf8_len) {
group->utf8 = malloc(utf8_len);
if (group->utf8) {
_cairo_pdf_smask_group_destroy (group);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
memcpy (group->utf8, utf8, utf8_len);
}
group->utf8_len = utf8_len;
if (num_glyphs) {
group->glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
if (group->glyphs == NULL) {
_cairo_pdf_smask_group_destroy (group);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
memcpy (group->glyphs, glyphs, sizeof (cairo_glyph_t) * num_glyphs);
}
memcpy (group->glyphs, glyphs, sizeof (cairo_glyph_t) * num_glyphs);
group->num_glyphs = num_glyphs;
if (num_clusters) {
group->clusters = _cairo_malloc_ab (num_clusters, sizeof (cairo_text_cluster_t));
if (group->clusters) {
_cairo_pdf_smask_group_destroy (group);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
memcpy (group->clusters, clusters, sizeof (cairo_text_cluster_t) * num_clusters);
}
group->num_clusters = num_clusters;
group->scaled_font = cairo_scaled_font_reference (scaled_font);
status = _cairo_pdf_surface_add_smask_group (surface, group);
if (status) {
@ -4648,6 +4827,10 @@ _cairo_pdf_surface_show_glyphs (void *abstract_surface,
if (status)
return status;
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (status)
return status;
_cairo_output_stream_printf (surface->output,
"q /s%d gs /x%d Do Q\n",
gstate_res.id,
@ -4657,19 +4840,34 @@ _cairo_pdf_surface_show_glyphs (void *abstract_surface,
if (status)
return status;
status = _cairo_pdf_operators_show_glyphs (&surface->pdf_operators,
glyphs,
num_glyphs,
scaled_font);
/* Each call to show_glyphs() with a transclucent pattern must
* be in a separate text object otherwise overlapping text
* from separate calls to show_glyphs will not composite with
* each other. */
if (! _cairo_pattern_is_opaque (source)) {
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (status)
return status;
}
status = _cairo_pdf_operators_show_text_glyphs (&surface->pdf_operators,
utf8, utf8_len,
glyphs, num_glyphs,
clusters, num_clusters,
backward,
scaled_font);
if (status)
return status;
_cairo_pdf_surface_unselect_pattern (surface);
status = _cairo_pdf_surface_unselect_pattern (surface);
if (status)
return status;
}
return _cairo_output_stream_get_status (surface->output);
}
static void
_cairo_pdf_surface_set_paginated_mode (void *abstract_surface,
cairo_paginated_mode_t paginated_mode)
@ -4709,15 +4907,20 @@ static const cairo_surface_backend_t cairo_pdf_surface_backend = {
_cairo_pdf_surface_mask,
_cairo_pdf_surface_stroke,
_cairo_pdf_surface_fill,
_cairo_pdf_surface_show_glyphs,
NULL, /* show_glyphs */
NULL, /* snapshot */
NULL, /* is_compatible */
NULL, /* reset */
_cairo_pdf_surface_fill_stroke,
NULL, /* create_solid_pattern_surface */
_cairo_pdf_surface_has_show_text_glyphs,
_cairo_pdf_surface_show_text_glyphs,
};
static const cairo_paginated_surface_backend_t cairo_pdf_surface_paginated_backend = {
_cairo_pdf_surface_start_page,
_cairo_pdf_surface_set_paginated_mode
_cairo_pdf_surface_set_paginated_mode,
NULL, /* set_bounding_box */
_cairo_pdf_surface_has_fallback_images,
};

Просмотреть файл

@ -37,7 +37,7 @@
#ifndef CAIRO_PDF_H
#define CAIRO_PDF_H
#include <cairo.h>
#include "cairo.h"
#if CAIRO_HAS_PDF_SURFACE

Просмотреть файл

@ -45,15 +45,6 @@ _cairo_pen_compute_slopes (cairo_pen_t *pen);
static void
_cairo_pen_stroke_spline_half (cairo_pen_t *pen, cairo_spline_t *spline, cairo_direction_t dir, cairo_polygon_t *polygon);
void
_cairo_pen_init_empty (cairo_pen_t *pen)
{
pen->radius = 0;
pen->tolerance = 0;
pen->vertices = NULL;
pen->num_vertices = 0;
}
cairo_status_t
_cairo_pen_init (cairo_pen_t *pen,
double radius,
@ -78,10 +69,14 @@ _cairo_pen_init (cairo_pen_t *pen,
radius,
ctm);
pen->vertices = _cairo_malloc_ab (pen->num_vertices,
sizeof (cairo_pen_vertex_t));
if (pen->vertices == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
if (pen->num_vertices > ARRAY_LENGTH (pen->vertices_embedded)) {
pen->vertices = _cairo_malloc_ab (pen->num_vertices,
sizeof (cairo_pen_vertex_t));
if (pen->vertices == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} else {
pen->vertices = pen->vertices_embedded;
}
/*
* Compute pen coordinates. To generate the right ellipse, compute points around
@ -107,10 +102,11 @@ _cairo_pen_init (cairo_pen_t *pen,
void
_cairo_pen_fini (cairo_pen_t *pen)
{
free (pen->vertices);
pen->vertices = NULL;
if (pen->vertices != pen->vertices_embedded)
free (pen->vertices);
_cairo_pen_init_empty (pen);
pen->vertices = pen->vertices_embedded;
pen->num_vertices = 0;
}
cairo_status_t
@ -118,13 +114,17 @@ _cairo_pen_init_copy (cairo_pen_t *pen, cairo_pen_t *other)
{
*pen = *other;
pen->vertices = pen->vertices_embedded;
if (pen->num_vertices) {
pen->vertices = _cairo_malloc_ab (pen->num_vertices,
sizeof (cairo_pen_vertex_t));
if (pen->vertices == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
if (pen->num_vertices > ARRAY_LENGTH (pen->vertices_embedded)) {
pen->vertices = _cairo_malloc_ab (pen->num_vertices,
sizeof (cairo_pen_vertex_t));
if (pen->vertices == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
memcpy (pen->vertices, other->vertices, pen->num_vertices * sizeof (cairo_pen_vertex_t));
memcpy (pen->vertices, other->vertices,
pen->num_vertices * sizeof (cairo_pen_vertex_t));
}
return CAIRO_STATUS_SUCCESS;
@ -133,18 +133,35 @@ _cairo_pen_init_copy (cairo_pen_t *pen, cairo_pen_t *other)
cairo_status_t
_cairo_pen_add_points (cairo_pen_t *pen, cairo_point_t *point, int num_points)
{
cairo_pen_vertex_t *vertices;
cairo_status_t status;
int num_vertices;
int i;
num_vertices = pen->num_vertices + num_points;
vertices = _cairo_realloc_ab (pen->vertices,
num_vertices, sizeof (cairo_pen_vertex_t));
if (vertices == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
if (num_vertices > ARRAY_LENGTH (pen->vertices_embedded) ||
pen->vertices != pen->vertices_embedded)
{
cairo_pen_vertex_t *vertices;
if (pen->vertices == pen->vertices_embedded) {
vertices = _cairo_malloc_ab (num_vertices,
sizeof (cairo_pen_vertex_t));
if (vertices == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
memcpy (vertices, pen->vertices,
pen->num_vertices * sizeof (cairo_pen_vertex_t));
} else {
vertices = _cairo_realloc_ab (pen->vertices,
num_vertices,
sizeof (cairo_pen_vertex_t));
if (vertices == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
pen->vertices = vertices;
}
pen->vertices = vertices;
pen->num_vertices = num_vertices;
/* initialize new vertices */

Просмотреть файл

@ -197,6 +197,9 @@ write_png (cairo_surface_t *surface,
case CAIRO_FORMAT_A1:
depth = 1;
png_color_type = PNG_COLOR_TYPE_GRAY;
#ifndef WORDS_BIGENDIAN
png_set_packswap (png);
#endif
break;
default:
status = _cairo_error (CAIRO_STATUS_INVALID_FORMAT);
@ -274,7 +277,7 @@ stdio_write_func (png_structp png, png_bytep data, png_size_t size)
* Return value: %CAIRO_STATUS_SUCCESS if the PNG file was written
* successfully. Otherwise, %CAIRO_STATUS_NO_MEMORY if memory could not
* be allocated for the operation or
* CAIRO_STATUS_SURFACE_TYPE_MISMATCH if the surface does not have
* %CAIRO_STATUS_SURFACE_TYPE_MISMATCH if the surface does not have
* pixel contents, or %CAIRO_STATUS_WRITE_ERROR if an I/O error occurs
* while attempting to write the file.
**/
@ -341,7 +344,7 @@ stream_write_func (png_structp png, png_bytep data, png_size_t size)
* Return value: %CAIRO_STATUS_SUCCESS if the PNG file was written
* successfully. Otherwise, %CAIRO_STATUS_NO_MEMORY is returned if
* memory could not be allocated for the operation,
* CAIRO_STATUS_SURFACE_TYPE_MISMATCH if the surface does not have
* %CAIRO_STATUS_SURFACE_TYPE_MISMATCH if the surface does not have
* pixel contents.
**/
cairo_status_t
@ -351,6 +354,12 @@ cairo_surface_write_to_png_stream (cairo_surface_t *surface,
{
struct png_write_closure_t png_closure;
if (surface->status)
return surface->status;
if (surface->finished)
return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED);
png_closure.write_func = write_func;
png_closure.closure = closure;
@ -498,25 +507,37 @@ read_png (png_rw_ptr read_func,
if (interlace != PNG_INTERLACE_NONE)
png_set_interlace_handling (png);
png_set_filler (png, 0xff, PNG_FILLER_AFTER);
/* recheck header after setting EXPAND options */
png_read_update_info (png, info);
png_get_IHDR (png, info,
&png_width, &png_height, &depth,
&color_type, &interlace, NULL, NULL);
if (depth != 8 || interlace != PNG_INTERLACE_NONE ||
! (color_type == PNG_COLOR_TYPE_RGB ||
color_type == PNG_COLOR_TYPE_RGB_ALPHA))
{
surface = _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_READ_ERROR));
goto BAIL;
}
switch (color_type) {
default:
case PNG_COLOR_TYPE_GRAY_ALPHA:
ASSERT_NOT_REACHED;
/* fall-through just in case ;-) */
case PNG_COLOR_TYPE_RGB_ALPHA:
format = CAIRO_FORMAT_ARGB32;
png_set_read_user_transform_fn (png, premultiply_data);
break;
case PNG_COLOR_TYPE_GRAY:
case PNG_COLOR_TYPE_PALETTE:
case PNG_COLOR_TYPE_RGB:
format = CAIRO_FORMAT_RGB24;
png_set_read_user_transform_fn (png, convert_bytes_to_data);
png_set_filler (png, 0xff, PNG_FILLER_AFTER);
break;
}
png_read_update_info (png, info);
stride = cairo_format_stride_for_width (format, png_width);
if (stride < 0) {
surface = _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_STRIDE));
@ -597,9 +618,9 @@ stdio_read_func (png_structp png, png_bytep data, png_size_t size)
* surface can be checked for with cairo_surface_status(surface) which
* may return one of the following values:
*
* CAIRO_STATUS_NO_MEMORY
* CAIRO_STATUS_FILE_NOT_FOUND
* CAIRO_STATUS_READ_ERROR
* %CAIRO_STATUS_NO_MEMORY
* %CAIRO_STATUS_FILE_NOT_FOUND
* %CAIRO_STATUS_READ_ERROR
**/
cairo_surface_t *
cairo_image_surface_create_from_png (const char *filename)

Просмотреть файл

@ -48,8 +48,8 @@ _cairo_polygon_init (cairo_polygon_t *polygon)
polygon->num_edges = 0;
polygon->edges_size = 0;
polygon->edges = NULL;
polygon->edges = polygon->edges_embedded;
polygon->edges_size = ARRAY_LENGTH (polygon->edges_embedded);
polygon->has_current_point = FALSE;
}
@ -79,26 +79,17 @@ _cairo_polygon_grow (cairo_polygon_t *polygon)
{
cairo_edge_t *new_edges;
int old_size = polygon->edges_size;
int embedded_size = ARRAY_LENGTH (polygon->edges_embedded);
int new_size = 2 * MAX (old_size, 16);
/* we have a local buffer at polygon->edges_embedded. try to fulfill the request
* from there. */
if (old_size < embedded_size) {
polygon->edges = polygon->edges_embedded;
polygon->edges_size = embedded_size;
return CAIRO_STATUS_SUCCESS;
}
int new_size = 2 * old_size;
assert (polygon->num_edges <= polygon->edges_size);
if (polygon->edges == polygon->edges_embedded) {
new_edges = _cairo_malloc_ab (new_size, sizeof (cairo_edge_t));
if (new_edges)
if (new_edges != NULL)
memcpy (new_edges, polygon->edges, old_size * sizeof (cairo_edge_t));
} else {
new_edges = _cairo_realloc_ab (polygon->edges,
new_size, sizeof (cairo_edge_t));
new_size, sizeof (cairo_edge_t));
}
if (new_edges == NULL)

Просмотреть файл

@ -49,6 +49,7 @@ struct _cairo {
cairo_gstate_t *gstate;
cairo_gstate_t gstate_tail[1];
cairo_gstate_t *gstate_freelist;
cairo_path_fixed_t path[1];
};

Просмотреть файл

@ -69,6 +69,12 @@ typedef struct cairo_ps_surface {
void *image_extra;
cairo_bool_t use_string_datasource;
cairo_bool_t current_pattern_is_solid_color;
double current_color_red;
double current_color_green;
double current_color_blue;
double current_color_alpha;
int num_pages;
cairo_paginated_mode_t paginated_mode;

Просмотреть файл

@ -49,6 +49,7 @@
#include "cairo-paginated-private.h"
#include "cairo-meta-surface-private.h"
#include "cairo-output-stream-private.h"
#include "cairo-type3-glyph-surface-private.h"
#include <stdio.h>
#include <ctype.h>
@ -172,24 +173,35 @@ _cairo_ps_surface_emit_header (cairo_ps_surface_t *surface)
"/n { newpath } bind def\n"
"/W { clip } bind def\n"
"/W* { eoclip } bind def\n"
"/Tf { pop /cairo_font exch def } bind def\n"
"/BT { } bind def\n"
"/ET { } bind def\n"
"/Tj { show } bind def\n"
"/pdfmark where { pop globaldict /?pdfmark /exec load put }\n"
" { globaldict begin /?pdfmark /pop load def /pdfmark\n"
" /cleartomark load def end } ifelse\n"
"/BDC { mark 3 1 roll /BDC pdfmark } bind def\n"
"/EMC { mark /EMC pdfmark } bind def\n"
"/cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def\n"
"/Tj { show currentpoint cairo_store_point } bind def\n"
"/TJ {\n"
" {\n"
" dup\n"
" type /stringtype eq\n"
" { show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse\n"
" } forall\n"
" currentpoint cairo_store_point\n"
"} bind def\n"
"/Td { matrix translate cairo_font_matrix matrix concatmatrix aload\n"
" /cairo_font_matrix exch def 6 2 roll 0 0 6 array astore\n"
" cairo_font exch selectfont moveto } bind def\n"
"/Tm { 6 copy 6 array astore /cairo_font_matrix exch def 6 2 roll 0 0\n"
" 6 array astore cairo_font exch selectfont moveto } bind def\n"
"/cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore\n"
" cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def\n"
"/Tf { pop /cairo_font exch def /cairo_font_matrix where\n"
" { cairo_selectfont } if } bind def\n"
"/Td { matrix translate cairo_font_matrix matrix concatmatrix dup\n"
" /cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point\n"
" /cairo_font where { cairo_selectfont } if } bind def\n"
"/Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def\n"
" cairo_store_point /cairo_font where { cairo_selectfont } if } bind def\n"
"/g { setgray } bind def\n"
"/rg { setrgbcolor } bind def\n");
"/rg { setrgbcolor } bind def\n"
"/d1 { setcachedevice } bind def\n");
_cairo_output_stream_printf (surface->final_stream,
"%%%%EndProlog\n");
@ -369,113 +381,49 @@ _cairo_ps_surface_emit_truetype_font_subset (cairo_ps_surface_t *surface,
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
_cairo_ps_surface_emit_bitmap_glyph_data (cairo_ps_surface_t *surface,
cairo_scaled_font_t *scaled_font,
unsigned long glyph_index,
cairo_box_t *bbox)
static cairo_status_t
_cairo_ps_emit_imagemask (cairo_image_surface_t *image,
cairo_output_stream_t *stream)
{
cairo_scaled_glyph_t *scaled_glyph;
cairo_status_t status;
cairo_image_surface_t *image;
unsigned char *row, *byte;
int rows, cols;
double x_advance, y_advance;
status = _cairo_scaled_glyph_lookup (scaled_font,
glyph_index,
CAIRO_SCALED_GLYPH_INFO_METRICS|
CAIRO_SCALED_GLYPH_INFO_SURFACE,
&scaled_glyph);
if (status)
return status;
/* The only image type supported by Type 3 fonts are 1-bit image
* masks */
assert (image->format == CAIRO_FORMAT_A1);
*bbox = scaled_glyph->bbox;
x_advance = scaled_glyph->metrics.x_advance;
y_advance = scaled_glyph->metrics.y_advance;
cairo_matrix_transform_distance (&scaled_font->ctm, &x_advance, &y_advance);
image = scaled_glyph->surface;
if (image->format != CAIRO_FORMAT_A1) {
image = _cairo_image_surface_clone (image, CAIRO_FORMAT_A1);
if (cairo_surface_status (&image->base))
return cairo_surface_status (&image->base);
}
_cairo_output_stream_printf (surface->final_stream,
"%f 0 %f %f %f %f setcachedevice\n",
x_advance,
_cairo_fixed_to_double (scaled_glyph->bbox.p1.x),
_cairo_fixed_to_double (scaled_glyph->bbox.p2.y),
_cairo_fixed_to_double (scaled_glyph->bbox.p2.x),
_cairo_fixed_to_double (scaled_glyph->bbox.p1.y));
_cairo_output_stream_printf (surface->final_stream,
_cairo_output_stream_printf (stream,
"<<\n"
" /ImageType 1\n"
" /Width %d\n"
" /Height %d\n"
" /ImageMatrix [%f %f %f %f %f %f]\n"
" /ImageMatrix [%d 0 0 %d 0 %d]\n"
" /Decode [1 0]\n"
" /BitsPerComponent 1\n",
image->width,
image->height,
image->base.device_transform.xx,
image->base.device_transform.yx,
image->base.device_transform.xy,
image->base.device_transform.yy,
image->base.device_transform.x0,
image->base.device_transform.y0);
image->width,
-image->height,
image->height);
_cairo_output_stream_printf (surface->final_stream,
_cairo_output_stream_printf (stream,
" /DataSource {<");
for (row = image->data, rows = image->height; rows; row += image->stride, rows--) {
for (byte = row, cols = (image->width + 7) / 8; cols; byte++, cols--) {
unsigned char output_byte = CAIRO_BITSWAP8_IF_LITTLE_ENDIAN (*byte);
_cairo_output_stream_printf (surface->final_stream, "%02x ", output_byte);
_cairo_output_stream_printf (stream, "%02x ", output_byte);
}
_cairo_output_stream_printf (surface->final_stream, "\n ");
_cairo_output_stream_printf (stream, "\n ");
}
_cairo_output_stream_printf (surface->final_stream,
_cairo_output_stream_printf (stream,
" >}\n");
_cairo_output_stream_printf (surface->final_stream,
_cairo_output_stream_printf (stream,
">>\n");
_cairo_output_stream_printf (surface->final_stream,
_cairo_output_stream_printf (stream,
"imagemask\n");
if (image != scaled_glyph->surface)
cairo_surface_destroy (&image->base);
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_ps_surface_emit_glyph (cairo_ps_surface_t *surface,
cairo_scaled_font_t *scaled_font,
unsigned long scaled_font_glyph_index,
unsigned int subset_glyph_index,
cairo_box_t *bbox)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
_cairo_output_stream_printf (surface->final_stream,
"\t\t{ %% %d\n", subset_glyph_index);
if (subset_glyph_index != 0) {
status = _cairo_ps_surface_emit_bitmap_glyph_data (surface,
scaled_font,
scaled_font_glyph_index,
bbox);
}
_cairo_output_stream_printf (surface->final_stream,
"\t\t}\n");
if (status)
status = _cairo_surface_set_error (&surface->base, status);
return status;
return _cairo_output_stream_get_status (stream);
}
static cairo_status_t
@ -489,6 +437,8 @@ _cairo_ps_surface_emit_type3_font_subset (cairo_ps_surface_t *surface,
unsigned int i;
cairo_box_t font_bbox = {{0,0},{0,0}};
cairo_box_t bbox = {{0,0},{0,0}};
cairo_surface_t *type3_surface;
double width;
#if DEBUG_PS
_cairo_output_stream_printf (surface->final_stream,
@ -499,13 +449,13 @@ _cairo_ps_surface_emit_type3_font_subset (cairo_ps_surface_t *surface,
_cairo_output_stream_printf (surface->final_stream,
"8 dict begin\n"
"/FontType 3 def\n"
"/FontMatrix [%f %f %f %f 0 0] def\n"
"/FontMatrix [1 0 0 1 0 0] def\n"
"/Encoding 256 array def\n"
"0 1 255 { Encoding exch /.notdef put } for\n",
matrix.xx,
matrix.yx,
-matrix.xy,
-matrix.yy);
"0 1 255 { Encoding exch /.notdef put } for\n");
type3_surface = _cairo_type3_glyph_surface_create (font_subset->scaled_font,
NULL,
_cairo_ps_emit_imagemask);
for (i = 1; i < font_subset->num_glyphs; i++) {
if (font_subset->glyph_names != NULL) {
@ -522,13 +472,25 @@ _cairo_ps_surface_emit_type3_font_subset (cairo_ps_surface_t *surface,
"/Glyphs [\n");
for (i = 0; i < font_subset->num_glyphs; i++) {
status = _cairo_ps_surface_emit_glyph (surface,
font_subset->scaled_font,
font_subset->glyphs[i], i,
&bbox);
_cairo_output_stream_printf (surface->final_stream,
" { %% %d\n", i);
if (i == 0) {
status = _cairo_type3_glyph_surface_emit_notdef_glyph (type3_surface,
surface->final_stream,
&bbox,
&width);
} else {
status = _cairo_type3_glyph_surface_emit_glyph (type3_surface,
surface->final_stream,
font_subset->glyphs[i],
&bbox,
&width);
}
if (status)
return status;
_cairo_output_stream_printf (surface->final_stream,
" }\n");
if (i == 0) {
font_bbox.p1.x = bbox.p1.x;
font_bbox.p1.y = bbox.p1.y;
@ -545,6 +507,7 @@ _cairo_ps_surface_emit_type3_font_subset (cairo_ps_surface_t *surface,
font_bbox.p2.y = bbox.p2.y;
}
}
cairo_surface_destroy (type3_surface);
_cairo_output_stream_printf (surface->final_stream,
"] def\n"
@ -557,9 +520,9 @@ _cairo_ps_surface_emit_type3_font_subset (cairo_ps_surface_t *surface,
"end\n"
"/f-%d-%d exch definefont pop\n",
_cairo_fixed_to_double (font_bbox.p1.x),
_cairo_fixed_to_double (font_bbox.p1.y),
- _cairo_fixed_to_double (font_bbox.p2.y),
_cairo_fixed_to_double (font_bbox.p2.x),
_cairo_fixed_to_double (font_bbox.p2.y),
- _cairo_fixed_to_double (font_bbox.p1.y),
font_subset->font_id,
font_subset->subset_id);
@ -728,6 +691,7 @@ _cairo_ps_surface_create_for_stream_internal (cairo_output_stream_t *stream,
surface->force_fallbacks = FALSE;
surface->content = CAIRO_CONTENT_COLOR_ALPHA;
surface->use_string_datasource = FALSE;
surface->current_pattern_is_solid_color = FALSE;
_cairo_pdf_operators_init (&surface->pdf_operators,
surface->stream,
@ -747,8 +711,11 @@ _cairo_ps_surface_create_for_stream_internal (cairo_output_stream_t *stream,
width, height,
&cairo_ps_surface_paginated_backend);
status = surface->paginated_surface->status;
if (status == CAIRO_STATUS_SUCCESS)
if (status == CAIRO_STATUS_SUCCESS) {
/* paginated keeps the only reference to surface now, drop ours */
cairo_surface_destroy (&surface->base);
return surface->paginated_surface;
}
_cairo_scaled_font_subsets_destroy (surface->font_subsets);
CLEANUP_OUTPUT_STREAM:
@ -1324,19 +1291,30 @@ _cairo_ps_surface_start_page (void *abstract_surface)
return CAIRO_STATUS_SUCCESS;
}
static void
static cairo_int_status_t
_cairo_ps_surface_end_page (cairo_ps_surface_t *surface)
{
cairo_int_status_t status;
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (status)
return status;
_cairo_output_stream_printf (surface->stream,
"Q\n");
return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
_cairo_ps_surface_show_page (void *abstract_surface)
{
cairo_ps_surface_t *surface = abstract_surface;
cairo_int_status_t status;
_cairo_ps_surface_end_page (surface);
status = _cairo_ps_surface_end_page (surface);
if (status)
return status;
_cairo_output_stream_printf (surface->stream, "showpage\n");
@ -1718,7 +1696,7 @@ _cairo_ps_surface_flatten_image_transparency (cairo_ps_surface_t *surface,
{
const cairo_color_t *background_color;
cairo_surface_t *opaque;
cairo_pattern_union_t pattern;
cairo_surface_pattern_t pattern;
cairo_status_t status;
if (surface->content == CAIRO_CONTENT_COLOR_ALPHA)
@ -1732,7 +1710,7 @@ _cairo_ps_surface_flatten_image_transparency (cairo_ps_surface_t *surface,
if (opaque->status)
return opaque->status;
_cairo_pattern_init_for_surface (&pattern.surface, &image->base);
_cairo_pattern_init_for_surface (&pattern, &image->base);
status = _cairo_surface_fill_rectangle (opaque,
CAIRO_OPERATOR_SOURCE,
@ -2052,6 +2030,8 @@ _cairo_ps_surface_emit_meta_surface (cairo_ps_surface_t *surface,
old_clip = _cairo_surface_get_clip (&surface->base);
surface->width = meta_extents.width;
surface->height = meta_extents.height;
surface->current_pattern_is_solid_color = FALSE;
_cairo_pdf_operators_reset (&surface->pdf_operators);
cairo_matrix_init (&surface->cairo_to_ps, 1, 0, 0, -1, 0, surface->height);
_cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators,
&surface->cairo_to_ps);
@ -2075,11 +2055,17 @@ _cairo_ps_surface_emit_meta_surface (cairo_ps_surface_t *surface,
if (status)
return status;
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (status)
return status;
_cairo_output_stream_printf (surface->stream,
" Q\n");
surface->content = old_content;
surface->width = old_width;
surface->height = old_height;
surface->current_pattern_is_solid_color = FALSE;
_cairo_pdf_operators_reset (&surface->pdf_operators);
surface->cairo_to_ps = old_cairo_to_ps;
status = _cairo_surface_set_clip (&surface->base, old_clip);
if (status)
@ -2618,6 +2604,19 @@ _cairo_ps_surface_emit_linear_pattern (cairo_ps_surface_t *surface,
if (pattern->base.n_stops == 0)
return CAIRO_INT_STATUS_NOTHING_TO_DO;
if (pattern->base.n_stops == 1) {
cairo_solid_pattern_t solid;
_cairo_pattern_init_solid (&solid,
&pattern->base.stops[0].color,
CAIRO_CONTENT_COLOR_ALPHA);
_cairo_ps_surface_emit_solid_pattern (surface,
&solid);
_cairo_pattern_fini (&solid.base);
return CAIRO_STATUS_SUCCESS;
}
extend = cairo_pattern_get_extend (&pattern->base.base);
pat_to_ps = pattern->base.base.matrix;
@ -2745,6 +2744,19 @@ _cairo_ps_surface_emit_radial_pattern (cairo_ps_surface_t *surface,
if (pattern->base.n_stops == 0)
return CAIRO_INT_STATUS_NOTHING_TO_DO;
if (pattern->base.n_stops == 1) {
cairo_solid_pattern_t solid;
_cairo_pattern_init_solid (&solid,
&pattern->base.stops[0].color,
CAIRO_CONTENT_COLOR_ALPHA);
_cairo_ps_surface_emit_solid_pattern (surface,
&solid);
_cairo_pattern_fini (&solid.base);
return CAIRO_STATUS_SUCCESS;
}
extend = cairo_pattern_get_extend (&pattern->base.base);
pat_to_ps = pattern->base.base.matrix;
@ -2801,13 +2813,41 @@ _cairo_ps_surface_emit_pattern (cairo_ps_surface_t *surface,
cairo_pattern_t *pattern,
cairo_operator_t op)
{
/* FIXME: We should keep track of what pattern is currently set in
* the postscript file and only emit code if we're setting a
* different pattern. */
cairo_status_t status;
if (pattern->type == CAIRO_PATTERN_TYPE_SOLID) {
cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) pattern;
if (surface->current_pattern_is_solid_color == FALSE ||
surface->current_color_red != solid->color.red ||
surface->current_color_green != solid->color.green ||
surface->current_color_blue != solid->color.blue ||
surface->current_color_alpha != solid->color.alpha)
{
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (status)
return status;
_cairo_ps_surface_emit_solid_pattern (surface, (cairo_solid_pattern_t *) pattern);
surface->current_pattern_is_solid_color = TRUE;
surface->current_color_red = solid->color.red;
surface->current_color_green = solid->color.green;
surface->current_color_blue = solid->color.blue;
surface->current_color_alpha = solid->color.alpha;
}
return CAIRO_STATUS_SUCCESS;
}
surface->current_pattern_is_solid_color = FALSE;
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (status)
return status;
switch (pattern->type) {
case CAIRO_PATTERN_TYPE_SOLID:
_cairo_ps_surface_emit_solid_pattern (surface, (cairo_solid_pattern_t *) pattern);
break;
@ -2846,6 +2886,7 @@ _cairo_ps_surface_intersect_clip_path (void *abstract_surface,
{
cairo_ps_surface_t *surface = abstract_surface;
cairo_output_stream_t *stream = surface->stream;
cairo_status_t status;
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
return CAIRO_STATUS_SUCCESS;
@ -2856,7 +2897,14 @@ _cairo_ps_surface_intersect_clip_path (void *abstract_surface,
#endif
if (path == NULL) {
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (status)
return status;
_cairo_output_stream_printf (stream, "Q q\n");
surface->current_pattern_is_solid_color = FALSE;
_cairo_pdf_operators_reset (&surface->pdf_operators);
return CAIRO_STATUS_SUCCESS;
}
@ -2919,6 +2967,10 @@ _cairo_ps_surface_paint (void *abstract_surface,
if (status)
return status;
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (status)
return status;
if (source->type == CAIRO_PATTERN_TYPE_SURFACE &&
(source->extend == CAIRO_EXTEND_NONE ||
source->extend == CAIRO_EXTEND_PAD))
@ -3011,6 +3063,10 @@ _cairo_ps_surface_fill (void *abstract_surface,
(source->extend == CAIRO_EXTEND_NONE ||
source->extend == CAIRO_EXTEND_PAD))
{
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (status)
return status;
_cairo_output_stream_printf (surface->stream, "q\n");
status = _cairo_pdf_operators_clip (&surface->pdf_operators,
@ -3026,6 +3082,7 @@ _cairo_ps_surface_fill (void *abstract_surface,
return status;
_cairo_output_stream_printf (surface->stream, "Q\n");
_cairo_pdf_operators_reset (&surface->pdf_operators);
} else {
status = _cairo_ps_surface_emit_pattern (surface, source, op);
if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
@ -3048,7 +3105,8 @@ _cairo_ps_surface_show_glyphs (void *abstract_surface,
cairo_pattern_t *source,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font)
cairo_scaled_font_t *scaled_font,
int *remaining_glyphs)
{
cairo_ps_surface_t *surface = abstract_surface;
cairo_status_t status;
@ -3073,10 +3131,12 @@ _cairo_ps_surface_show_glyphs (void *abstract_surface,
if (status)
return status;
return _cairo_pdf_operators_show_glyphs (&surface->pdf_operators,
glyphs,
num_glyphs,
scaled_font);
return _cairo_pdf_operators_show_text_glyphs (&surface->pdf_operators,
NULL, 0,
glyphs, num_glyphs,
NULL, 0,
FALSE,
scaled_font);
}
static void
@ -3150,6 +3210,8 @@ _cairo_ps_surface_set_bounding_box (void *abstract_surface,
if (y2 > surface->bbox_y2)
surface->bbox_y2 = y2;
}
surface->current_pattern_is_solid_color = FALSE;
_cairo_pdf_operators_reset (&surface->pdf_operators);
return _cairo_output_stream_get_status (surface->stream);
}

Просмотреть файл

@ -37,7 +37,7 @@
#ifndef CAIRO_PS_H
#define CAIRO_PS_H
#include <cairo.h>
#include "cairo.h"
#if CAIRO_HAS_PS_SURFACE

Просмотреть файл

@ -127,9 +127,9 @@ struct _cairo_quartz_font_face {
CGFontRef cgFont;
};
/**
** font face backend
**/
/*
* font face backend
*/
static void
_cairo_quartz_font_face_destroy (void *abstract_face)
@ -165,7 +165,7 @@ _cairo_quartz_font_face_scaled_font_create (void *abstract_face,
status = _cairo_scaled_font_init (&font->base,
&font_face->base, font_matrix, ctm, options,
&cairo_quartz_scaled_font_backend);
&_cairo_quartz_scaled_font_backend);
if (status)
goto FINISH;
@ -188,6 +188,7 @@ _cairo_quartz_font_face_scaled_font_create (void *abstract_face,
quartz_CGFontMetrics *m;
m = CGFontGetHMetricsPtr (font_face->cgFont);
/* On OX 10.4, GetHMetricsPtr sometimes returns NULL for unknown reasons */
if (!m) {
status = _cairo_error(CAIRO_STATUS_NULL_POINTER);
goto FINISH;
@ -260,9 +261,9 @@ cairo_quartz_font_face_create_for_cgfont (CGFontRef font)
return &font_face->base;
}
/**
** scaled font backend
**/
/*
* scaled font backend
*/
static cairo_quartz_font_face_t *
_cairo_quartz_scaled_to_face (void *abstract_font)
@ -740,7 +741,7 @@ _cairo_quartz_ucs4_to_index (void *abstract_font,
return glyph;
}
const cairo_scaled_font_backend_t cairo_quartz_scaled_font_backend = {
const cairo_scaled_font_backend_t _cairo_quartz_scaled_font_backend = {
CAIRO_FONT_TYPE_QUARTZ,
_cairo_quartz_font_create_toy,
_cairo_quartz_font_fini,

Просмотреть файл

@ -43,6 +43,7 @@
#include "cairo-quartz-private.h"
#define SURFACE_ERROR_NO_MEMORY (_cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_NO_MEMORY)))
#define SURFACE_ERROR_TYPE_MISMATCH (_cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_SURFACE_TYPE_MISMATCH)))
#define SURFACE_ERROR_INVALID_FORMAT (_cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_INVALID_FORMAT)))
CGImageRef
@ -300,7 +301,7 @@ cairo_quartz_image_surface_create (cairo_surface_t *surface)
unsigned char *data;
if (cairo_surface_get_type(surface) != CAIRO_SURFACE_TYPE_IMAGE)
return SURFACE_ERROR_NO_MEMORY;
return SURFACE_ERROR_TYPE_MISMATCH;
image_surface = (cairo_image_surface_t*) surface;
width = image_surface->width;
@ -337,7 +338,7 @@ cairo_quartz_image_surface_create (cairo_surface_t *surface)
TRUE,
NULL,
DataProviderReleaseCallback,
surface);
image_surface);
if (!image) {
free (qisurf);

Просмотреть файл

@ -36,7 +36,7 @@
#ifndef CAIRO_QUARTZ_IMAGE_H
#define CAIRO_QUARTZ_IMAGE_H
#include <cairo.h>
#include "cairo.h"
#if CAIRO_HAS_QUARTZ_IMAGE_SURFACE

Просмотреть файл

@ -41,7 +41,7 @@
#include "cairoint.h"
#ifdef CAIRO_HAS_QUARTZ_SURFACE
#include <cairo-quartz.h>
#include "cairo-quartz.h"
typedef struct cairo_quartz_surface {
cairo_surface_t base;

Просмотреть файл

@ -695,6 +695,13 @@ CreateRepeatingGradientFunction (cairo_quartz_surface_t *surface,
/* Obtain a CGImageRef from a #cairo_surface_t * */
static void
DataProviderReleaseCallback (void *info, const void *data, size_t size)
{
cairo_surface_t *surface = (cairo_surface_t *) info;
cairo_surface_destroy (surface);
}
static cairo_status_t
_cairo_surface_to_cgimage (cairo_surface_t *target,
cairo_surface_t *source,
@ -737,17 +744,22 @@ _cairo_surface_to_cgimage (cairo_surface_t *target,
if (isurf->width == 0 || isurf->height == 0) {
*image_out = NULL;
} else {
image = _cairo_quartz_create_cgimage (isurf->format,
isurf->width,
isurf->height,
isurf->stride,
isurf->data,
TRUE,
NULL, NULL, NULL);
cairo_image_surface_t *isurf_snap = NULL;
isurf_snap = _cairo_surface_snapshot (isurf);
if (isurf_snap == NULL)
return CAIRO_STATUS_NO_MEMORY;
/* Create a copy to ensure that the CGImageRef doesn't depend on the image surface's backing store */
*image_out = CGImageCreateCopy (image);
CGImageRelease (image);
image = _cairo_quartz_create_cgimage (isurf_snap->format,
isurf_snap->width,
isurf_snap->height,
isurf_snap->stride,
isurf_snap->data,
TRUE,
NULL,
DataProviderReleaseCallback,
isurf_snap);
*image_out = image;
}
if ((cairo_surface_t*) isurf != source)
@ -1875,7 +1887,8 @@ _cairo_quartz_surface_show_glyphs (void *abstract_surface,
cairo_pattern_t *source,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font)
cairo_scaled_font_t *scaled_font,
int *remaining_glyphs)
{
CGAffineTransform textTransform, ctm;
#define STATIC_BUF_SIZE 64
@ -2154,7 +2167,7 @@ _cairo_quartz_surface_mask_with_generic (cairo_quartz_surface_t *surface,
cairo_surface_t *gradient_surf = NULL;
cairo_t *gradient_surf_cr = NULL;
cairo_pattern_union_t surface_pattern;
cairo_surface_pattern_t surface_pattern;
cairo_int_status_t status;
/* Render the gradient to a surface */
@ -2171,9 +2184,9 @@ _cairo_quartz_surface_mask_with_generic (cairo_quartz_surface_t *surface,
if (status)
goto BAIL;
_cairo_pattern_init_for_surface (&surface_pattern.surface, gradient_surf);
_cairo_pattern_init_for_surface (&surface_pattern, gradient_surf);
status = _cairo_quartz_surface_mask_with_surface (surface, op, source, &surface_pattern.surface);
status = _cairo_quartz_surface_mask_with_surface (surface, op, source, &surface_pattern);
_cairo_pattern_fini (&surface_pattern.base);

Просмотреть файл

@ -36,7 +36,7 @@
#ifndef CAIRO_QUARTZ_H
#define CAIRO_QUARTZ_H
#include <cairo.h>
#include "cairo.h"
#if CAIRO_HAS_QUARTZ_SURFACE

Просмотреть файл

@ -39,6 +39,38 @@
#include "cairoint.h"
cairo_private void
_cairo_box_from_doubles (cairo_box_t *box,
double *x1, double *y1,
double *x2, double *y2)
{
box->p1.x = _cairo_fixed_from_double (*x1);
box->p1.y = _cairo_fixed_from_double (*y1);
box->p2.x = _cairo_fixed_from_double (*x2);
box->p2.y = _cairo_fixed_from_double (*y2);
}
cairo_private void
_cairo_box_to_doubles (const cairo_box_t *box,
double *x1, double *y1,
double *x2, double *y2)
{
*x1 = _cairo_fixed_to_double (box->p1.x);
*y1 = _cairo_fixed_to_double (box->p1.y);
*x2 = _cairo_fixed_to_double (box->p2.x);
*y2 = _cairo_fixed_to_double (box->p2.y);
}
void
_cairo_box_from_rectangle (cairo_box_t *box,
const cairo_rectangle_int_t *rect)
{
box->p1.x = _cairo_fixed_from_int (rect->x);
box->p1.y = _cairo_fixed_from_int (rect->y);
box->p2.x = _cairo_fixed_from_int (rect->x + rect->width);
box->p2.y = _cairo_fixed_from_int (rect->y + rect->height);
}
/* XXX We currently have a confusing mix of boxes and rectangles as
* exemplified by this function. A #cairo_box_t is a rectangular area
* represented by the coordinates of the upper left and lower right
@ -54,7 +86,8 @@
*/
void
_cairo_box_round_to_rectangle (cairo_box_t *box, cairo_rectangle_int_t *rectangle)
_cairo_box_round_to_rectangle (const cairo_box_t *box,
cairo_rectangle_int_t *rectangle)
{
rectangle->x = _cairo_fixed_integer_floor (box->p1.x);
rectangle->y = _cairo_fixed_integer_floor (box->p1.y);

Просмотреть файл

@ -44,7 +44,7 @@
/* #cairo_region_t is defined in cairoint.h */
struct _cairo_region {
pixman_region16_t rgn;
pixman_region32_t rgn;
};
cairo_private void

Просмотреть файл

@ -40,14 +40,14 @@
void
_cairo_region_init (cairo_region_t *region)
{
pixman_region_init (&region->rgn);
pixman_region32_init (&region->rgn);
}
void
_cairo_region_init_rect (cairo_region_t *region,
cairo_rectangle_int_t *rect)
{
pixman_region_init_rect (&region->rgn,
pixman_region32_init_rect (&region->rgn,
rect->x, rect->y,
rect->width, rect->height);
}
@ -57,13 +57,13 @@ _cairo_region_init_boxes (cairo_region_t *region,
cairo_box_int_t *boxes,
int count)
{
pixman_box16_t stack_pboxes[CAIRO_STACK_ARRAY_LENGTH (pixman_box16_t)];
pixman_box16_t *pboxes = stack_pboxes;
pixman_box32_t stack_pboxes[CAIRO_STACK_ARRAY_LENGTH (pixman_box32_t)];
pixman_box32_t *pboxes = stack_pboxes;
cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
int i;
if (count > ARRAY_LENGTH(stack_pboxes)) {
pboxes = _cairo_malloc_ab (count, sizeof(pixman_box16_t));
pboxes = _cairo_malloc_ab (count, sizeof(pixman_box32_t));
if (pboxes == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
@ -75,7 +75,7 @@ _cairo_region_init_boxes (cairo_region_t *region,
pboxes[i].y2 = boxes[i].p2.y;
}
if (!pixman_region_init_rects (&region->rgn, pboxes, count))
if (!pixman_region32_init_rects (&region->rgn, pboxes, count))
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
if (pboxes != stack_pboxes)
@ -87,13 +87,13 @@ _cairo_region_init_boxes (cairo_region_t *region,
void
_cairo_region_fini (cairo_region_t *region)
{
pixman_region_fini (&region->rgn);
pixman_region32_fini (&region->rgn);
}
cairo_int_status_t
_cairo_region_copy (cairo_region_t *dst, cairo_region_t *src)
{
if (!pixman_region_copy (&dst->rgn, &src->rgn))
if (!pixman_region32_copy (&dst->rgn, &src->rgn))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
return CAIRO_STATUS_SUCCESS;
@ -102,18 +102,18 @@ _cairo_region_copy (cairo_region_t *dst, cairo_region_t *src)
int
_cairo_region_num_boxes (cairo_region_t *region)
{
return pixman_region_n_rects (&region->rgn);
return pixman_region32_n_rects (&region->rgn);
}
cairo_int_status_t
_cairo_region_get_boxes (cairo_region_t *region, int *num_boxes, cairo_box_int_t **boxes)
{
int nboxes;
pixman_box16_t *pboxes;
pixman_box32_t *pboxes;
cairo_box_int_t *cboxes;
int i;
pboxes = pixman_region_rectangles (&region->rgn, &nboxes);
pboxes = pixman_region32_rectangles (&region->rgn, &nboxes);
if (nboxes == 0) {
*num_boxes = 0;
@ -154,7 +154,7 @@ _cairo_region_boxes_fini (cairo_region_t *region, cairo_box_int_t *boxes)
void
_cairo_region_get_extents (cairo_region_t *region, cairo_rectangle_int_t *extents)
{
pixman_box16_t *pextents = pixman_region_extents (&region->rgn);
pixman_box32_t *pextents = pixman_region32_extents (&region->rgn);
extents->x = pextents->x1;
extents->y = pextents->y1;
@ -165,7 +165,7 @@ _cairo_region_get_extents (cairo_region_t *region, cairo_rectangle_int_t *extent
cairo_int_status_t
_cairo_region_subtract (cairo_region_t *dst, cairo_region_t *a, cairo_region_t *b)
{
if (!pixman_region_subtract (&dst->rgn, &a->rgn, &b->rgn))
if (!pixman_region32_subtract (&dst->rgn, &a->rgn, &b->rgn))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
return CAIRO_STATUS_SUCCESS;
@ -174,7 +174,7 @@ _cairo_region_subtract (cairo_region_t *dst, cairo_region_t *a, cairo_region_t *
cairo_int_status_t
_cairo_region_intersect (cairo_region_t *dst, cairo_region_t *a, cairo_region_t *b)
{
if (!pixman_region_intersect (&dst->rgn, &a->rgn, &b->rgn))
if (!pixman_region32_intersect (&dst->rgn, &a->rgn, &b->rgn))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
return CAIRO_STATUS_SUCCESS;
@ -185,7 +185,7 @@ _cairo_region_union_rect (cairo_region_t *dst,
cairo_region_t *src,
cairo_rectangle_int_t *rect)
{
if (!pixman_region_union_rect (&dst->rgn, &src->rgn,
if (!pixman_region32_union_rect (&dst->rgn, &src->rgn,
rect->x, rect->y,
rect->width, rect->height))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
@ -196,25 +196,25 @@ _cairo_region_union_rect (cairo_region_t *dst,
cairo_bool_t
_cairo_region_not_empty (cairo_region_t *region)
{
return (cairo_bool_t) pixman_region_not_empty (&region->rgn);
return (cairo_bool_t) pixman_region32_not_empty (&region->rgn);
}
void
_cairo_region_translate (cairo_region_t *region,
int x, int y)
{
pixman_region_translate (&region->rgn, x, y);
pixman_region32_translate (&region->rgn, x, y);
}
pixman_region_overlap_t
_cairo_region_contains_rectangle (cairo_region_t *region, cairo_rectangle_int_t *rect)
{
pixman_box16_t pbox;
pixman_box32_t pbox;
pbox.x1 = rect->x;
pbox.y1 = rect->y;
pbox.x2 = rect->x + rect->width;
pbox.y2 = rect->y + rect->height;
return pixman_region_contains_rectangle (&region->rgn, &pbox);
return pixman_region32_contains_rectangle (&region->rgn, &pbox);
}

Просмотреть файл

@ -81,6 +81,7 @@
#define cairo_glyph_extents _moz_cairo_glyph_extents
#define cairo_glyph_path _moz_cairo_glyph_path
#define cairo_has_current_point _moz_cairo_has_current_point
#define cairo_has_show_text_glyphs _moz_cairo_has_show_text_glyphs
#define cairo_identity_matrix _moz_cairo_identity_matrix
#define cairo_image_surface_create _moz_cairo_image_surface_create
#define cairo_image_surface_create_for_data _moz_cairo_image_surface_create_for_data
@ -193,6 +194,7 @@
#define cairo_scaled_font_get_font_matrix _moz_cairo_scaled_font_get_font_matrix
#define cairo_scaled_font_get_font_options _moz_cairo_scaled_font_get_font_options
#define cairo_scaled_font_get_reference_count _moz_cairo_scaled_font_get_reference_count
#define cairo_scaled_font_get_scale_matrix _moz_cairo_scaled_font_get_scale_matrix
#define cairo_scaled_font_get_type _moz_cairo_scaled_font_get_type
#define cairo_scaled_font_get_user_data _moz_cairo_scaled_font_get_user_data
#define cairo_scaled_font_glyph_extents _moz_cairo_scaled_font_glyph_extents
@ -224,6 +226,7 @@
#define cairo_show_glyphs _moz_cairo_show_glyphs
#define cairo_show_page _moz_cairo_show_page
#define cairo_show_text _moz_cairo_show_text
#define cairo_show_text_glyphs _moz_cairo_show_text_glyphs
#define cairo_status _moz_cairo_status
#define cairo_status_to_string _moz_cairo_status_to_string
#define cairo_stroke _moz_cairo_stroke
@ -237,6 +240,7 @@
#define cairo_surface_flush _moz_cairo_surface_flush
#define cairo_surface_get_content _moz_cairo_surface_get_content
#define cairo_surface_get_device_offset _moz_cairo_surface_get_device_offset
#define cairo_surface_get_fallback_resolution _moz_cairo_surface_get_fallback_resolution
#define cairo_surface_get_font_options _moz_cairo_surface_get_font_options
#define cairo_surface_get_reference_count _moz_cairo_surface_get_reference_count
#define cairo_surface_get_type _moz_cairo_surface_get_type
@ -260,6 +264,15 @@
#define cairo_text_path _moz_cairo_text_path
#define cairo_transform _moz_cairo_transform
#define cairo_translate _moz_cairo_translate
#define cairo_user_font_face_create _moz_cairo_user_font_face_create
#define cairo_user_font_face_get_init_func _moz_cairo_user_font_face_get_init_func
#define cairo_user_font_face_get_render_glyph_func _moz_cairo_user_font_face_get_render_glyph_func
#define cairo_user_font_face_get_text_to_glyphs_func _moz_cairo_user_font_face_get_text_to_glyphs_func
#define cairo_user_font_face_get_unicode_to_glyph_func _moz_cairo_user_font_face_get_unicode_to_glyph_func
#define cairo_user_font_face_set_init_func _moz_cairo_user_font_face_set_init_func
#define cairo_user_font_face_set_render_glyph_func _moz_cairo_user_font_face_set_render_glyph_func
#define cairo_user_font_face_set_text_to_glyphs_func _moz_cairo_user_font_face_set_text_to_glyphs_func
#define cairo_user_font_face_set_unicode_to_glyph_func _moz_cairo_user_font_face_set_unicode_to_glyph_func
#define cairo_user_to_device _moz_cairo_user_to_device
#define cairo_user_to_device_distance _moz_cairo_user_to_device_distance
#define cairo_version _moz_cairo_version
@ -295,10 +308,10 @@
#define cairo_xlib_surface_get_xrender_format _moz_cairo_xlib_surface_get_xrender_format
#define cairo_xlib_surface_set_drawable _moz_cairo_xlib_surface_set_drawable
#define cairo_xlib_surface_set_size _moz_cairo_xlib_surface_set_size
#define pixman_transform_point_3d _moz_pixman_transform_point_3d
#define pixman_region_set_static_pointers _moz_pixman_region_set_static_pointers
#define pixman_region_init _moz_pixman_region_init
#define pixman_region_init_rect _moz_pixman_region_init_rect
#define pixman_region_init_rects _moz_pixman_region_init_rects
#define pixman_region_init_with_extents _moz_pixman_region_init_with_extents
#define pixman_region_fini _moz_pixman_region_fini
#define pixman_region_translate _moz_pixman_region_translate
@ -317,9 +330,34 @@
#define pixman_region_equal _moz_pixman_region_equal
#define pixman_region_selfcheck _moz_pixman_region_selfcheck
#define pixman_region_reset _moz_pixman_region_reset
#define pixman_region_init_rects _moz_pixman_region_init_rects
#define pixman_region32_init _moz_pixman_region32_init
#define pixman_region32_init_rect _moz_pixman_region32_init_rect
#define pixman_region32_init_rects _moz_pixman_region32_init_rects
#define pixman_region32_init_with_extents _moz_pixman_region32_init_with_extents
#define pixman_region32_fini _moz_pixman_region32_fini
#define pixman_region32_translate _moz_pixman_region32_translate
#define pixman_region32_copy _moz_pixman_region32_copy
#define pixman_region32_intersect _moz_pixman_region32_intersect
#define pixman_region32_union _moz_pixman_region32_union
#define pixman_region32_union_rect _moz_pixman_region32_union_rect
#define pixman_region32_subtract _moz_pixman_region32_subtract
#define pixman_region32_inverse _moz_pixman_region32_inverse
#define pixman_region32_contains_point _moz_pixman_region32_contains_point
#define pixman_region32_contains_rectangle _moz_pixman_region32_contains_rectangle
#define pixman_region32_not_empty _moz_pixman_region32_not_empty
#define pixman_region32_extents _moz_pixman_region32_extents
#define pixman_region32_n_rects _moz_pixman_region32_n_rects
#define pixman_region32_rectangles _moz_pixman_region32_rectangles
#define pixman_region32_equal _moz_pixman_region32_equal
#define pixman_region32_selfcheck _moz_pixman_region32_selfcheck
#define pixman_region32_reset _moz_pixman_region32_reset
#define pixman_blt _moz_pixman_blt
#define pixman_fill _moz_pixman_fill
#define pixman_transform_point_3d _moz_pixman_transform_point_3d
#define pixman_version _moz_pixman_version
#define pixman_version_string _moz_pixman_version_string
#define pixman_format_supported_destination _moz_pixman_format_supported_destination
#define pixman_format_supported_source _moz_pixman_format_supported_source
#define pixman_image_create_solid_fill _moz_pixman_image_create_solid_fill
#define pixman_image_create_linear_gradient _moz_pixman_image_create_linear_gradient
#define pixman_image_create_radial_gradient _moz_pixman_image_create_radial_gradient
@ -328,11 +366,12 @@
#define pixman_image_ref _moz_pixman_image_ref
#define pixman_image_unref _moz_pixman_image_unref
#define pixman_image_set_clip_region _moz_pixman_image_set_clip_region
#define pixman_image_set_clip_region32 _moz_pixman_image_set_clip_region32
#define pixman_image_set_has_client_clip _moz_pixman_image_set_has_client_clip
#define pixman_image_set_transform _moz_pixman_image_set_transform
#define pixman_image_set_repeat _moz_pixman_image_set_repeat
#define pixman_image_set_filter _moz_pixman_image_set_filter
#define pixman_image_set_filter_params _moz_pixman_image_set_filter_params
#define pixman_image_set_source_clipping _moz_pixman_image_set_source_clipping
#define pixman_image_set_alpha_map _moz_pixman_image_set_alpha_map
#define pixman_image_set_component_alpha _moz_pixman_image_set_component_alpha
#define pixman_image_set_accessors _moz_pixman_image_set_accessors
@ -354,5 +393,3 @@
#define pixman_add_traps _moz_pixman_add_traps
#define pixman_add_trapezoids _moz_pixman_add_trapezoids
#define pixman_rasterize_trapezoid _moz_pixman_rasterize_trapezoid
#define pixman_transform_point_3d _moz_pixman_transform_point_3d

Просмотреть файл

@ -89,9 +89,14 @@ struct _cairo_scaled_font {
cairo_matrix_t ctm; /* user space => device space */
cairo_font_options_t options;
cairo_bool_t placeholder; /* protected by fontmap mutex */
cairo_bool_t finished;
/* "live" scaled_font members */
cairo_matrix_t scale; /* font space => device space */
cairo_matrix_t scale_inverse; /* device space => font space */
double max_scale; /* maximum x/y expansion of scale */
cairo_font_extents_t extents; /* user space */
/* The mutex protects modification to all subsequent fields. */

Просмотреть файл

@ -46,6 +46,9 @@ typedef struct _cairo_scaled_font_subsets_glyph {
cairo_bool_t is_scaled;
cairo_bool_t is_composite;
double x_advance;
double y_advance;
cairo_bool_t utf8_is_mapped;
uint32_t unicode;
} cairo_scaled_font_subsets_glyph_t;
/**
@ -175,17 +178,25 @@ _cairo_scaled_font_subsets_destroy (cairo_scaled_font_subsets_t *font_subsets);
* @is_scaled: If true, the mapped glyph is from a bitmap font, and separate font
* subset is created for each font scale used. If false, the outline of the mapped glyph
* is available. One font subset for each font face is created.
* @x_advance: When @is_scaled is true, @x_advance contains the x_advance for the mapped glyph in device space.
* When @is_scaled is false, @x_advance contains the x_advance for the the mapped glyph from an unhinted 1 point font.
* @x_advance, @y_advance: When @is_scaled is true, @x_advance and @y_advance contain
* the x and y advance for the mapped glyph in device space.
* When @is_scaled is false, @x_advance and @y_advance contain the x and y advance for
* the the mapped glyph from an unhinted 1 point font.
* @utf8_is_mapped: If true the utf8 string provided to _cairo_scaled_font_subsets_map_glyph()
* is (or already was) the utf8 string mapped to this glyph. If false the glyph is already
* mapped to a different utf8 string.
* @unicode: the unicode character mapped to this glyph by the font backend.
*
* Return value: %CAIRO_STATUS_SUCCESS if successful, or a non-zero
* value indicating an error. Possible errors include
* CAIRO_STATUS_NO_MEMORY.
* %CAIRO_STATUS_NO_MEMORY.
**/
cairo_private cairo_status_t
_cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t *font_subsets,
cairo_scaled_font_t *scaled_font,
unsigned long scaled_font_glyph_index,
const char * utf8,
int utf8_len,
cairo_scaled_font_subsets_glyph_t *subset_glyph_ret);
typedef cairo_status_t
@ -220,7 +231,7 @@ typedef cairo_status_t
*
* Return value: %CAIRO_STATUS_SUCCESS if successful, or a non-zero
* value indicating an error. Possible errors include
* CAIRO_STATUS_NO_MEMORY.
* %CAIRO_STATUS_NO_MEMORY.
**/
cairo_private cairo_status_t
_cairo_scaled_font_subsets_foreach_scaled (cairo_scaled_font_subsets_t *font_subsets,
@ -255,7 +266,7 @@ _cairo_scaled_font_subsets_foreach_scaled (cairo_scaled_font_subsets_t *fon
*
* Return value: %CAIRO_STATUS_SUCCESS if successful, or a non-zero
* value indicating an error. Possible errors include
* CAIRO_STATUS_NO_MEMORY.
* %CAIRO_STATUS_NO_MEMORY.
**/
cairo_private cairo_status_t
_cairo_scaled_font_subsets_foreach_unscaled (cairo_scaled_font_subsets_t *font_subsets,
@ -270,7 +281,7 @@ _cairo_scaled_font_subsets_foreach_unscaled (cairo_scaled_font_subsets_t
* in @font_subsets. The array as store in font_subsets->glyph_names.
*
* Return value: %CAIRO_STATUS_SUCCESS if successful,
* CAIRO_INT_STATUS_UNSUPPORTED if the font backend does not support
* %CAIRO_INT_STATUS_UNSUPPORTED if the font backend does not support
* mapping the glyph indices to unicode characters. Possible errors
* include %CAIRO_STATUS_NO_MEMORY.
**/
@ -298,7 +309,7 @@ typedef struct _cairo_cff_subset {
* data.
*
* Return value: %CAIRO_STATUS_SUCCESS if successful,
* CAIRO_INT_STATUS_UNSUPPORTED if the font can't be subset as a
* %CAIRO_INT_STATUS_UNSUPPORTED if the font can't be subset as a
* cff file, or an non-zero value indicating an error. Possible
* errors include %CAIRO_STATUS_NO_MEMORY.
**/
@ -329,7 +340,7 @@ _cairo_cff_subset_fini (cairo_cff_subset_t *cff_subset);
* with information about the subset and the cff data.
*
* Return value: %CAIRO_STATUS_SUCCESS if successful,
* CAIRO_INT_STATUS_UNSUPPORTED if the font can't be subset as a
* %CAIRO_INT_STATUS_UNSUPPORTED if the font can't be subset as a
* cff file, or an non-zero value indicating an error. Possible
* errors include %CAIRO_STATUS_NO_MEMORY.
**/
@ -372,7 +383,7 @@ typedef struct _cairo_truetype_subset {
* data.
*
* Return value: %CAIRO_STATUS_SUCCESS if successful,
* CAIRO_INT_STATUS_UNSUPPORTED if the font can't be subset as a
* %CAIRO_INT_STATUS_UNSUPPORTED if the font can't be subset as a
* truetype file, or an non-zero value indicating an error. Possible
* errors include %CAIRO_STATUS_NO_MEMORY.
**/
@ -416,7 +427,7 @@ typedef struct _cairo_type1_subset {
* with information about the subset and the type1 data.
*
* Return value: %CAIRO_STATUS_SUCCESS if successful,
* CAIRO_INT_STATUS_UNSUPPORTED if the font can't be subset as a type1
* %CAIRO_INT_STATUS_UNSUPPORTED if the font can't be subset as a type1
* file, or an non-zero value indicating an error. Possible errors
* include %CAIRO_STATUS_NO_MEMORY.
**/
@ -458,7 +469,7 @@ _cairo_type1_scaled_font_is_type1 (cairo_scaled_font_t *scaled_font);
* part of the font is binary encoded.
*
* Return value: %CAIRO_STATUS_SUCCESS if successful,
* CAIRO_INT_STATUS_UNSUPPORTED if the font can't be subset as a type1
* %CAIRO_INT_STATUS_UNSUPPORTED if the font can't be subset as a type1
* file, or an non-zero value indicating an error. Possible errors
* include %CAIRO_STATUS_NO_MEMORY.
**/
@ -479,7 +490,7 @@ _cairo_type1_fallback_init_binary (cairo_type1_subset_t *type_subset,
* part of the font is hex encoded.
*
* Return value: %CAIRO_STATUS_SUCCESS if successful,
* CAIRO_INT_STATUS_UNSUPPORTED if the font can't be subset as a type1
* %CAIRO_INT_STATUS_UNSUPPORTED if the font can't be subset as a type1
* file, or an non-zero value indicating an error. Possible errors
* include %CAIRO_STATUS_NO_MEMORY.
**/
@ -517,7 +528,7 @@ typedef struct _cairo_type2_charstrings {
* with information about the subset.
*
* Return value: %CAIRO_STATUS_SUCCESS if successful,
* CAIRO_INT_STATUS_UNSUPPORTED if the font can't be subset as a type2
* %CAIRO_INT_STATUS_UNSUPPORTED if the font can't be subset as a type2
* charstrings, or an non-zero value indicating an error. Possible errors
* include %CAIRO_STATUS_NO_MEMORY.
**/
@ -546,11 +557,33 @@ _cairo_type2_charstrings_fini (cairo_type2_charstrings_t *charstrings);
* fontsubset->to_unicode.
*
* Return value: %CAIRO_STATUS_SUCCESS if successful,
* CAIRO_INT_STATUS_UNSUPPORTED if the unicode encoding of
* %CAIRO_INT_STATUS_UNSUPPORTED if the unicode encoding of
* the glyphs is not available. Possible errors include
* CAIRO_STATUS_NO_MEMORY.
* %CAIRO_STATUS_NO_MEMORY.
**/
cairo_private cairo_int_status_t
_cairo_truetype_create_glyph_to_unicode_map (cairo_scaled_font_subset_t *font_subset);
/**
* _cairo_truetype_index_to_ucs4:
* @scaled_font: the #cairo_scaled_font_t
* @index: the glyph index
* @ucs4: return value for the unicode value of the glyph
*
* If possible (depending on the format of the underlying
* #cairo_scaled_font_t and the font backend in use) assign
* the unicode character of the glyph to @ucs4.
*
* If mapping glyph indices to unicode is supported but the unicode
* value of the specified glyph is not available, @ucs4 is set to -1.
*
* Return value: %CAIRO_STATUS_SUCCESS if successful,
* %CAIRO_INT_STATUS_UNSUPPORTED if mapping glyph indices to unicode
* is not supported. Possible errors include %CAIRO_STATUS_NO_MEMORY.
**/
cairo_private cairo_int_status_t
_cairo_truetype_index_to_ucs4 (cairo_scaled_font_t *scaled_font,
unsigned long index,
uint32_t *ucs4);
#endif /* CAIRO_SCALED_FONT_SUBSETS_PRIVATE_H */

Просмотреть файл

@ -43,6 +43,7 @@
#define _BSD_SOURCE /* for snprintf(), strdup() */
#include "cairoint.h"
#include "cairo-scaled-font-subsets-private.h"
#include "cairo-user-font-private.h"
#define MAX_GLYPHS_PER_SIMPLE_FONT 256
#define MAX_GLYPHS_PER_COMPOSITE_FONT 65536
@ -53,18 +54,6 @@ typedef enum {
CAIRO_SUBSETS_COMPOSITE
} cairo_subsets_type_t;
struct _cairo_scaled_font_subsets {
cairo_subsets_type_t type;
int max_glyphs_per_unscaled_subset_used;
cairo_hash_table_t *unscaled_sub_fonts;
int max_glyphs_per_scaled_subset_used;
cairo_hash_table_t *scaled_sub_fonts;
int num_sub_fonts;
};
typedef struct _cairo_sub_font {
cairo_hash_entry_t base;
@ -79,18 +68,42 @@ typedef struct _cairo_sub_font {
int max_glyphs_per_subset;
cairo_hash_table_t *sub_font_glyphs;
struct _cairo_sub_font *next;
} cairo_sub_font_t;
struct _cairo_scaled_font_subsets {
cairo_subsets_type_t type;
int max_glyphs_per_unscaled_subset_used;
cairo_hash_table_t *unscaled_sub_fonts;
cairo_sub_font_t *unscaled_sub_fonts_list;
cairo_sub_font_t *unscaled_sub_fonts_list_end;
int max_glyphs_per_scaled_subset_used;
cairo_hash_table_t *scaled_sub_fonts;
cairo_sub_font_t *scaled_sub_fonts_list;
cairo_sub_font_t *scaled_sub_fonts_list_end;
int num_sub_fonts;
};
typedef struct _cairo_sub_font_glyph {
cairo_hash_entry_t base;
unsigned int subset_id;
unsigned int subset_glyph_index;
double x_advance;
double y_advance;
cairo_bool_t is_mapped;
uint32_t unicode;
char *utf8;
int utf8_len;
} cairo_sub_font_glyph_t;
typedef struct _cairo_sub_font_collection {
unsigned long *glyphs; /* scaled_font_glyph_index */
char **utf8;
unsigned int glyphs_size;
unsigned int max_glyph;
unsigned int num_glyphs;
@ -110,6 +123,8 @@ typedef struct _cairo_string_entry {
static cairo_status_t
_cairo_sub_font_map_glyph (cairo_sub_font_t *sub_font,
unsigned long scaled_font_glyph_index,
const char * utf8,
int utf8_len,
cairo_scaled_font_subsets_glyph_t *subset_glyph);
static void
@ -132,7 +147,8 @@ static cairo_sub_font_glyph_t *
_cairo_sub_font_glyph_create (unsigned long scaled_font_glyph_index,
unsigned int subset_id,
unsigned int subset_glyph_index,
double x_advance)
double x_advance,
double y_advance)
{
cairo_sub_font_glyph_t *sub_font_glyph;
@ -146,6 +162,11 @@ _cairo_sub_font_glyph_create (unsigned long scaled_font_glyph_index,
sub_font_glyph->subset_id = subset_id;
sub_font_glyph->subset_glyph_index = subset_glyph_index;
sub_font_glyph->x_advance = x_advance;
sub_font_glyph->y_advance = y_advance;
sub_font_glyph->is_mapped = FALSE;
sub_font_glyph->unicode = -1;
sub_font_glyph->utf8 = NULL;
sub_font_glyph->utf8_len = 0;
return sub_font_glyph;
}
@ -153,6 +174,9 @@ _cairo_sub_font_glyph_create (unsigned long scaled_font_glyph_index,
static void
_cairo_sub_font_glyph_destroy (cairo_sub_font_glyph_t *sub_font_glyph)
{
if (sub_font_glyph->utf8 != NULL)
free (sub_font_glyph->utf8);
free (sub_font_glyph);
}
@ -184,6 +208,7 @@ _cairo_sub_font_glyph_collect (void *entry, void *closure)
assert (subset_glyph_index < collection->glyphs_size);
collection->glyphs[subset_glyph_index] = scaled_font_glyph_index;
collection->utf8[subset_glyph_index] = sub_font_glyph->utf8;
if (subset_glyph_index > collection->max_glyph)
collection->max_glyph = subset_glyph_index;
@ -252,9 +277,10 @@ _cairo_sub_font_create (cairo_scaled_font_subsets_t *parent,
free (sub_font);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
sub_font->next = NULL;
/* Reserve first glyph in subset for the .notdef glyph */
status = _cairo_sub_font_map_glyph (sub_font, 0, &subset_glyph);
status = _cairo_sub_font_map_glyph (sub_font, 0, NULL, 0, &subset_glyph);
if (status) {
_cairo_hash_table_destroy (sub_font->sub_font_glyphs);
free (sub_font);
@ -286,9 +312,86 @@ _cairo_sub_font_pluck (void *entry, void *closure)
_cairo_sub_font_destroy (sub_font);
}
static cairo_status_t
_cairo_sub_font_glyph_lookup_unicode (cairo_sub_font_glyph_t *sub_font_glyph,
cairo_scaled_font_t *scaled_font,
unsigned long scaled_font_glyph_index)
{
uint32_t unicode;
char buf[8];
int len;
cairo_status_t status;
/* Do a reverse lookup on the glyph index. unicode is -1 if the
* index could not be mapped to a unicode character. */
status = _cairo_truetype_index_to_ucs4 (scaled_font, scaled_font_glyph_index, &unicode);
if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
if (status == CAIRO_INT_STATUS_UNSUPPORTED)
unicode = -1;
if (unicode == (uint32_t)-1 && scaled_font->backend->index_to_ucs4)
status = scaled_font->backend->index_to_ucs4 (scaled_font, scaled_font_glyph_index, &unicode);
sub_font_glyph->unicode = unicode;
sub_font_glyph->utf8 = NULL;
sub_font_glyph->utf8_len = 0;
if (unicode != (uint32_t)-1) {
len = _cairo_ucs4_to_utf8 (unicode, buf);
if (len > 0) {
sub_font_glyph->utf8 = malloc(len + 1);
memcpy (sub_font_glyph->utf8, buf, len);
sub_font_glyph->utf8[len] = 0;
sub_font_glyph->utf8_len = len;
}
}
return CAIRO_STATUS_SUCCESS;
}
static cairo_bool_t
_cairo_sub_font_glyph_map_to_unicode (cairo_sub_font_glyph_t *sub_font_glyph,
const char *utf8,
int utf8_len)
{
int add_zero_byte = 0;
if (utf8 != NULL && utf8_len != 0) {
if (sub_font_glyph->utf8 != NULL) {
if (utf8_len == sub_font_glyph->utf8_len &&
memcmp (utf8, sub_font_glyph->utf8, utf8_len) == 0)
{
/* Requested utf8 mapping matches the existing mapping */
return TRUE;
}
else
{
/* Requested utf8 mapping does not match the existing mapping */
return FALSE;
}
} else {
/* No existing mapping. Use the requested mapping */
if (sub_font_glyph->utf8[utf8_len - 1] != 0)
add_zero_byte = 1;
sub_font_glyph->utf8 = malloc (utf8_len + add_zero_byte);
memcpy (sub_font_glyph->utf8, utf8, utf8_len);
if (add_zero_byte)
sub_font_glyph->utf8[utf8_len] = 0;
sub_font_glyph->utf8_len = utf8_len;
return TRUE;
}
}
/* No mapping was requested. */
return FALSE;
}
static cairo_bool_t
_cairo_sub_font_lookup_glyph (cairo_sub_font_t *sub_font,
unsigned long scaled_font_glyph_index,
const char * utf8,
int utf8_len,
cairo_scaled_font_subsets_glyph_t *subset_glyph)
{
cairo_sub_font_glyph_t key, *sub_font_glyph;
@ -303,8 +406,11 @@ _cairo_sub_font_lookup_glyph (cairo_sub_font_t *sub_font,
subset_glyph->is_scaled = sub_font->is_scaled;
subset_glyph->is_composite = sub_font->is_composite;
subset_glyph->x_advance = sub_font_glyph->x_advance;
subset_glyph->y_advance = sub_font_glyph->y_advance;
subset_glyph->utf8_is_mapped = _cairo_sub_font_glyph_map_to_unicode (sub_font_glyph, utf8, utf8_len);
subset_glyph->unicode = sub_font_glyph->unicode;
return TRUE;
return TRUE;
}
return FALSE;
@ -313,6 +419,8 @@ _cairo_sub_font_lookup_glyph (cairo_sub_font_t *sub_font,
static cairo_status_t
_cairo_sub_font_map_glyph (cairo_sub_font_t *sub_font,
unsigned long scaled_font_glyph_index,
const char * utf8,
int utf8_len,
cairo_scaled_font_subsets_glyph_t *subset_glyph)
{
cairo_sub_font_glyph_t key, *sub_font_glyph;
@ -330,7 +438,7 @@ _cairo_sub_font_map_glyph (cairo_sub_font_t *sub_font,
sub_font->num_glyphs_in_current_subset = 0;
/* Reserve first glyph in subset for the .notdef glyph */
status = _cairo_sub_font_map_glyph (sub_font, 0, &tmp_subset_glyph);
status = _cairo_sub_font_map_glyph (sub_font, 0, NULL, 0, &tmp_subset_glyph);
if (status)
return status;
}
@ -346,10 +454,15 @@ _cairo_sub_font_map_glyph (cairo_sub_font_t *sub_font,
sub_font_glyph = _cairo_sub_font_glyph_create (scaled_font_glyph_index,
sub_font->current_subset,
sub_font->num_glyphs_in_current_subset,
scaled_glyph->metrics.x_advance);
scaled_glyph->metrics.x_advance,
scaled_glyph->metrics.y_advance);
if (sub_font_glyph == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
_cairo_sub_font_glyph_lookup_unicode (sub_font_glyph,
sub_font->scaled_font,
scaled_font_glyph_index);
status = _cairo_hash_table_insert (sub_font->sub_font_glyphs, &sub_font_glyph->base);
if (status) {
_cairo_sub_font_glyph_destroy (sub_font_glyph);
@ -376,6 +489,8 @@ _cairo_sub_font_map_glyph (cairo_sub_font_t *sub_font,
subset_glyph->is_scaled = sub_font->is_scaled;
subset_glyph->is_composite = sub_font->is_composite;
subset_glyph->x_advance = sub_font_glyph->x_advance;
subset_glyph->y_advance = sub_font_glyph->y_advance;
subset_glyph->utf8_is_mapped = FALSE;
return CAIRO_STATUS_SUCCESS;
}
@ -412,6 +527,7 @@ _cairo_sub_font_collect (void *entry, void *closure)
subset.font_id = sub_font->font_id;
subset.subset_id = i;
subset.glyphs = collection->glyphs;
subset.utf8 = collection->utf8;
subset.num_glyphs = collection->num_glyphs;
subset.glyph_names = NULL;
/* No need to check for out of memory here. If to_unicode is NULL, the PDF
@ -461,6 +577,8 @@ _cairo_scaled_font_subsets_create_internal (cairo_subsets_type_t type)
free (subsets);
return NULL;
}
subsets->unscaled_sub_fonts_list = NULL;
subsets->unscaled_sub_fonts_list_end = NULL;
subsets->scaled_sub_fonts = _cairo_hash_table_create (_cairo_sub_fonts_equal);
if (! subsets->scaled_sub_fonts) {
@ -468,6 +586,8 @@ _cairo_scaled_font_subsets_create_internal (cairo_subsets_type_t type)
free (subsets);
return NULL;
}
subsets->scaled_sub_fonts_list = NULL;
subsets->scaled_sub_fonts_list_end = NULL;
return subsets;
}
@ -506,6 +626,8 @@ cairo_status_t
_cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t *subsets,
cairo_scaled_font_t *scaled_font,
unsigned long scaled_font_glyph_index,
const char * utf8,
int utf8_len,
cairo_scaled_font_subsets_glyph_t *subset_glyph)
{
cairo_sub_font_t key, *sub_font;
@ -527,6 +649,7 @@ _cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t *subsets,
{
if (_cairo_sub_font_lookup_glyph (sub_font,
scaled_font_glyph_index,
utf8, utf8_len,
subset_glyph))
return CAIRO_STATUS_SUCCESS;
}
@ -540,6 +663,7 @@ _cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t *subsets,
{
if (_cairo_sub_font_lookup_glyph (sub_font,
scaled_font_glyph_index,
utf8, utf8_len,
subset_glyph))
return CAIRO_STATUS_SUCCESS;
}
@ -564,7 +688,8 @@ _cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t *subsets,
return status;
if (status == CAIRO_STATUS_SUCCESS &&
subsets->type != CAIRO_SUBSETS_SCALED)
subsets->type != CAIRO_SUBSETS_SCALED &&
! _cairo_font_face_is_user (scaled_font->font_face))
{
/* Path available. Add to unscaled subset. */
key.is_scaled = FALSE;
@ -611,11 +736,16 @@ _cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t *subsets,
status = _cairo_hash_table_insert (subsets->unscaled_sub_fonts,
&sub_font->base);
if (status) {
_cairo_sub_font_destroy (sub_font);
return status;
}
if (!subsets->unscaled_sub_fonts_list)
subsets->unscaled_sub_fonts_list = sub_font;
else
subsets->unscaled_sub_fonts_list_end->next = sub_font;
subsets->unscaled_sub_fonts_list_end = sub_font;
subsets->num_sub_fonts++;
}
} else {
@ -650,13 +780,18 @@ _cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t *subsets,
_cairo_sub_font_destroy (sub_font);
return status;
}
if (!subsets->scaled_sub_fonts_list)
subsets->scaled_sub_fonts_list = sub_font;
else
subsets->scaled_sub_fonts_list_end->next = sub_font;
subsets->scaled_sub_fonts_list_end = sub_font;
subsets->num_sub_fonts++;
}
}
return _cairo_sub_font_map_glyph (sub_font,
scaled_font_glyph_index,
utf8, utf8_len,
subset_glyph);
}
@ -667,6 +802,7 @@ _cairo_scaled_font_subsets_foreach_internal (cairo_scaled_font_subsets_t
cairo_bool_t is_scaled)
{
cairo_sub_font_collection_t collection;
cairo_sub_font_t *sub_font;
if (is_scaled)
collection.glyphs_size = font_subsets->max_glyphs_per_scaled_subset_used;
@ -677,20 +813,30 @@ _cairo_scaled_font_subsets_foreach_internal (cairo_scaled_font_subsets_t
return CAIRO_STATUS_SUCCESS;
collection.glyphs = _cairo_malloc_ab (collection.glyphs_size, sizeof(unsigned long));
if (collection.glyphs == NULL)
collection.utf8 = _cairo_malloc_ab (collection.glyphs_size, sizeof(char *));
if (collection.glyphs == NULL || collection.utf8 == NULL) {
if (collection.glyphs != NULL)
free (collection.glyphs);
if (collection.utf8 != NULL)
free (collection.utf8);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
collection.font_subset_callback = font_subset_callback;
collection.font_subset_callback_closure = closure;
collection.status = CAIRO_STATUS_SUCCESS;
if (is_scaled)
_cairo_hash_table_foreach (font_subsets->scaled_sub_fonts,
_cairo_sub_font_collect, &collection);
sub_font = font_subsets->scaled_sub_fonts_list;
else
_cairo_hash_table_foreach (font_subsets->unscaled_sub_fonts,
_cairo_sub_font_collect, &collection);
sub_font = font_subsets->unscaled_sub_fonts_list;
while (sub_font) {
_cairo_sub_font_collect (sub_font, &collection);
sub_font = sub_font->next;
}
free (collection.utf8);
free (collection.glyphs);
return collection.status;
@ -757,29 +903,14 @@ create_string_entry (char *s, cairo_string_entry_t **entry)
cairo_int_status_t
_cairo_scaled_font_subset_create_glyph_names (cairo_scaled_font_subset_t *subset)
{
const cairo_scaled_font_backend_t *backend;
unsigned int i;
cairo_status_t status;
cairo_hash_table_t *names;
cairo_string_entry_t key, *entry;
char buf[30];
if (subset->to_unicode == NULL)
return CAIRO_INT_STATUS_UNSUPPORTED;
status = _cairo_truetype_create_glyph_to_unicode_map (subset);
if (status) {
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
backend = subset->scaled_font->backend;
if (backend->map_glyphs_to_unicode == NULL)
return CAIRO_INT_STATUS_UNSUPPORTED;
status = backend->map_glyphs_to_unicode (subset->scaled_font, subset);
if (status)
return status;
}
char *utf8;
uint16_t *utf16;
int utf16_len;
names = _cairo_hash_table_create (_cairo_string_equal);
if (names == NULL)
@ -808,8 +939,17 @@ _cairo_scaled_font_subset_create_glyph_names (cairo_scaled_font_subset_t *subset
}
for (i = 1; i < subset->num_glyphs; i++) {
if (subset->to_unicode[i] <= 0xffff) {
snprintf (buf, sizeof(buf), "uni%04X", (unsigned int)(subset->to_unicode[i]));
utf8 = subset->utf8[i];
utf16 = NULL;
utf16_len = 0;
if (utf8 && *utf8) {
status = _cairo_utf8_to_utf16 (utf8, -1, &utf16, &utf16_len);
if (status && status != CAIRO_STATUS_INVALID_STRING)
return status; // FIXME
}
if (utf16_len == 1) {
snprintf (buf, sizeof(buf), "uni%04X", (int)(utf16[0]));
_cairo_string_init_key (&key, buf);
if (_cairo_hash_table_lookup (names, &key.base,
(cairo_hash_entry_t **) &entry)) {
@ -818,6 +958,8 @@ _cairo_scaled_font_subset_create_glyph_names (cairo_scaled_font_subset_t *subset
} else {
snprintf (buf, sizeof(buf), "g%d", i);
}
if (utf16)
free (utf16);
subset->glyph_names[i] = strdup (buf);
if (subset->glyph_names[i] == NULL) {

Просмотреть файл

@ -167,6 +167,8 @@ _cairo_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph)
cairo_surface_destroy (&scaled_glyph->surface->base);
if (scaled_glyph->path != NULL)
_cairo_path_fixed_destroy (scaled_glyph->path);
if (scaled_glyph->meta_surface != NULL)
cairo_surface_destroy (scaled_glyph->meta_surface);
}
static void
@ -190,8 +192,11 @@ static const cairo_scaled_font_t _cairo_scaled_font_nil = {
CAIRO_SUBPIXEL_ORDER_DEFAULT,
CAIRO_HINT_STYLE_DEFAULT,
CAIRO_HINT_METRICS_DEFAULT} ,
FALSE, /* placeholder */
TRUE, /* finished */
{ 1., 0., 0., 1., 0, 0}, /* scale */
{ 1., 0., 0., 1., 0, 0}, /* scale_inverse */
1., /* max_scale */
{ 0., 0., 0., 0., 0. }, /* extents */
CAIRO_MUTEX_NIL_INITIALIZER,/* mutex */
NULL, /* glyphs */
@ -203,10 +208,10 @@ static const cairo_scaled_font_t _cairo_scaled_font_nil = {
/**
* _cairo_scaled_font_set_error:
* @scaled_font: a scaled_font
* @status: a status value indicating an error, (eg. not
* CAIRO_STATUS_SUCCESS)
* @status: a status value indicating an error
*
* Atomically sets scaled_font->status to @status and calls _cairo_error;
* Does nothing if status is %CAIRO_STATUS_SUCCESS.
*
* All assignments of an error status to scaled_font->status should happen
* through _cairo_scaled_font_set_error(). Note that due to the nature of
@ -343,7 +348,6 @@ _cairo_scaled_font_map_unlock (void)
void
_cairo_scaled_font_map_destroy (void)
{
int i;
cairo_scaled_font_map_t *font_map;
cairo_scaled_font_t *scaled_font;
@ -354,15 +358,23 @@ _cairo_scaled_font_map_destroy (void)
goto CLEANUP_MUTEX_LOCK;
}
for (i = 0; i < font_map->num_holdovers; i++) {
scaled_font = font_map->holdovers[i];
/* We should only get here through the reset_static_data path
* and there had better not be any active references at that
* point. */
/* remove scaled_fonts starting from the end so that font_map->holdovers
* is always in a consistent state when we release the mutex. */
while (font_map->num_holdovers) {
scaled_font = font_map->holdovers[font_map->num_holdovers-1];
assert (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&scaled_font->ref_count));
_cairo_hash_table_remove (font_map->hash_table,
&scaled_font->hash_entry);
font_map->num_holdovers--;
/* release the lock to avoid the possibility of a recursive
* deadlock when the scaled font destroy closure gets called */
CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
_cairo_scaled_font_fini (scaled_font);
CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
free (scaled_font);
}
@ -375,6 +387,113 @@ _cairo_scaled_font_map_destroy (void)
CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
}
/* If a scaled font wants to unlock the font map while still being
* created (needed for user-fonts), we need to take extra care not
* ending up with multiple identical scaled fonts being created.
*
* What we do is, we create a fake identical scaled font, and mark
* it as placeholder, lock its mutex, and insert that in the fontmap
* hash table. This makes other code trying to create an identical
* scaled font to just wait and retry.
*
* The reason we have to create a fake scaled font instead of just using
* scaled_font is for lifecycle management: we need to (or rather,
* other code needs to) reference the scaked_font in the hash.
* We can't do that on the input scaled_font as it may be freed by
* font backend upon error.
*/
void
_cairo_scaled_font_register_placeholder_and_unlock_font_map (cairo_scaled_font_t *scaled_font)
{
cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_scaled_font_t *placeholder_scaled_font;
placeholder_scaled_font = malloc (sizeof (cairo_scaled_font_t));
if (!placeholder_scaled_font) {
status = CAIRO_STATUS_NO_MEMORY;
goto FREE;
}
/* full initialization is wasteful, but who cares... */
status = _cairo_scaled_font_init (placeholder_scaled_font,
scaled_font->font_face,
&scaled_font->font_matrix,
&scaled_font->ctm,
&scaled_font->options,
NULL);
if (status)
goto FINI;
placeholder_scaled_font->placeholder = TRUE;
CAIRO_MUTEX_LOCK (placeholder_scaled_font->mutex);
status = _cairo_hash_table_insert (cairo_scaled_font_map->hash_table,
&placeholder_scaled_font->hash_entry);
if (status)
goto UNLOCK_KEY;
goto UNLOCK;
UNLOCK_KEY:
CAIRO_MUTEX_UNLOCK (placeholder_scaled_font->mutex);
FINI:
_cairo_scaled_font_fini (placeholder_scaled_font);
FREE:
free (placeholder_scaled_font);
status = _cairo_scaled_font_set_error (scaled_font, status);
UNLOCK:
CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
}
void
_cairo_scaled_font_unregister_placeholder_and_lock_font_map (cairo_scaled_font_t *scaled_font)
{
cairo_scaled_font_t *placeholder_scaled_font;
cairo_bool_t found;
CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
found = _cairo_hash_table_lookup (cairo_scaled_font_map->hash_table,
&scaled_font->hash_entry,
(cairo_hash_entry_t**) &placeholder_scaled_font);
assert (found);
assert (placeholder_scaled_font->placeholder);
_cairo_hash_table_remove (cairo_scaled_font_map->hash_table,
&scaled_font->hash_entry);
CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
cairo_scaled_font_destroy (placeholder_scaled_font);
CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
}
static void
_cairo_scaled_font_placeholder_wait_for_creation_to_finish (cairo_scaled_font_t *scaled_font)
{
/* reference the place holder so it doesn't go away */
cairo_scaled_font_reference (scaled_font);
/* now unlock the fontmap mutex so creation has a chance to finish */
CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
/* wait on placeholder mutex until we are awaken */
CAIRO_MUTEX_LOCK (scaled_font->mutex);
/* ok, creation done. just clean up and back out */
CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
cairo_scaled_font_destroy (scaled_font);
}
/* Fowler / Noll / Vo (FNV) Hash (http://www.isthe.com/chongo/tech/comp/fnv/)
*
* Not necessarily better than a lot of other hashes, but should be OK, and
@ -407,6 +526,7 @@ _cairo_scaled_font_init_key (cairo_scaled_font_t *scaled_font,
uint32_t hash = FNV1_32_INIT;
scaled_font->status = CAIRO_STATUS_SUCCESS;
scaled_font->placeholder = FALSE;
scaled_font->font_face = font_face;
scaled_font->font_matrix = *font_matrix;
scaled_font->ctm = *ctm;
@ -477,6 +597,8 @@ _cairo_scaled_font_init (cairo_scaled_font_t *scaled_font,
&scaled_font->font_matrix,
&scaled_font->ctm);
scaled_font->max_scale = MAX (fabs (scaled_font->scale.xx) + fabs (scaled_font->scale.xy),
fabs (scaled_font->scale.yx) + fabs (scaled_font->scale.yy));
scaled_font->scale_inverse = scaled_font->scale;
status = cairo_matrix_invert (&scaled_font->scale_inverse);
if (status) {
@ -485,9 +607,9 @@ _cairo_scaled_font_init (cairo_scaled_font_t *scaled_font,
* producing an error.
*
* FIXME: If the scale is rank 1, we still go into error mode. But then
* again, that's what we doo everywhere in cairo.
* again, that's what we do everywhere in cairo.
*
* Also, the check for == 0. below may bee too harsh...
* Also, the check for == 0. below may be too harsh...
*/
if (scaled_font->scale.xx == 0. && scaled_font->scale.xy == 0. &&
scaled_font->scale.yx == 0. && scaled_font->scale.yy == 0.)
@ -499,6 +621,8 @@ _cairo_scaled_font_init (cairo_scaled_font_t *scaled_font,
return status;
}
scaled_font->finished = FALSE;
scaled_font->glyphs = _cairo_cache_create (_cairo_scaled_glyph_keys_equal,
_cairo_scaled_glyph_destroy,
MAX_GLYPHS_CACHED_PER_FONT);
@ -551,7 +675,7 @@ _cairo_scaled_font_set_metrics (cairo_scaled_font_t *scaled_font,
status = _cairo_matrix_compute_scale_factors (&scaled_font->font_matrix,
&font_scale_x, &font_scale_y,
/* XXX */ 1);
1);
if (status)
return status;
@ -572,6 +696,8 @@ _cairo_scaled_font_set_metrics (cairo_scaled_font_t *scaled_font,
void
_cairo_scaled_font_fini (cairo_scaled_font_t *scaled_font)
{
scaled_font->finished = TRUE;
if (scaled_font->font_face != NULL)
cairo_font_face_destroy (scaled_font->font_face);
@ -584,7 +710,8 @@ _cairo_scaled_font_fini (cairo_scaled_font_t *scaled_font)
scaled_font->surface_backend->scaled_font_fini != NULL)
scaled_font->surface_backend->scaled_font_fini (scaled_font);
scaled_font->backend->fini (scaled_font);
if (scaled_font->backend != NULL && scaled_font->backend->fini != NULL)
scaled_font->backend->fini (scaled_font);
_cairo_user_data_array_fini (&scaled_font->user_data);
}
@ -637,9 +764,20 @@ cairo_scaled_font_create (cairo_font_face_t *font_face,
_cairo_scaled_font_init_key (&key, font_face,
font_matrix, ctm, options);
while (_cairo_hash_table_lookup (font_map->hash_table, &key.hash_entry,
(cairo_hash_entry_t**) &scaled_font))
{
if (!scaled_font->placeholder)
break;
/* If the scaled font is being created (happens for user-font),
* just wait until it's done, then retry */
_cairo_scaled_font_placeholder_wait_for_creation_to_finish (scaled_font);
}
/* Return existing scaled_font if it exists in the hash table. */
if (_cairo_hash_table_lookup (font_map->hash_table, &key.hash_entry,
(cairo_hash_entry_t**) &scaled_font))
if (scaled_font)
{
/* If the original reference count is 0, then this font must have
* been found in font_map->holdovers, (which means this caching is
@ -793,26 +931,29 @@ slim_hidden_def (cairo_scaled_font_reference);
void
cairo_scaled_font_destroy (cairo_scaled_font_t *scaled_font)
{
cairo_scaled_font_map_t *font_map;
cairo_scaled_font_t *lru = NULL;
cairo_scaled_font_map_t *font_map;
if (scaled_font == NULL ||
CAIRO_REFERENCE_COUNT_IS_INVALID (&scaled_font->ref_count))
return;
assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&scaled_font->ref_count));
font_map = _cairo_scaled_font_map_lock ();
assert (font_map != NULL);
assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&scaled_font->ref_count));
if (_cairo_reference_count_dec_and_test (&scaled_font->ref_count)) {
if (scaled_font->hash_entry.hash != ZOMBIE) {
if (!scaled_font->placeholder && scaled_font->hash_entry.hash != ZOMBIE) {
/* Rather than immediately destroying this object, we put it into
* the font_map->holdovers array in case it will get used again
* soon (and is why we must hold the lock over the atomic op on
* the reference count). To make room for it, we do actually
* destroy the least-recently-used holdover.
*/
if (font_map->num_holdovers == CAIRO_SCALED_FONT_MAX_HOLDOVERS)
{
lru = font_map->holdovers[0];
@ -830,8 +971,10 @@ cairo_scaled_font_destroy (cairo_scaled_font_t *scaled_font)
font_map->num_holdovers++;
} else
lru = scaled_font;
}
_cairo_scaled_font_map_unlock ();
CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
/* If we pulled an item from the holdovers array, (while the font
* map lock was held, of course), then there is no way that anyone
@ -1033,6 +1176,21 @@ cairo_scaled_font_glyph_extents (cairo_scaled_font_t *scaled_font,
return;
}
if (num_glyphs == 0)
return;
if (num_glyphs < 0) {
_cairo_error_throw (CAIRO_STATUS_NEGATIVE_COUNT);
/* XXX Can't propagate error */
return;
}
if (glyphs == NULL) {
_cairo_error_throw (CAIRO_STATUS_NULL_POINTER);
/* XXX Can't propagate error */
return;
}
CAIRO_MUTEX_LOCK (scaled_font->mutex);
_cairo_scaled_font_freeze_cache (scaled_font);
@ -1119,20 +1277,26 @@ _cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font,
cairo_status_t status;
cairo_scaled_glyph_t *scaled_glyph;
*num_glyphs = 0;
*glyphs = NULL;
status = scaled_font->status;
if (status)
return status;
if (utf8[0] == '\0') {
*num_glyphs = 0;
*glyphs = NULL;
if (utf8[0] == '\0')
return CAIRO_STATUS_SUCCESS;
}
CAIRO_MUTEX_LOCK (scaled_font->mutex);
_cairo_scaled_font_freeze_cache (scaled_font);
if (scaled_font->backend->text_to_glyphs) {
/* validate input so backend does not have to */
status = _cairo_utf8_to_ucs4 (utf8, -1, NULL, NULL);
if (status)
goto DONE;
status = scaled_font->backend->text_to_glyphs (scaled_font,
x, y, utf8,
glyphs, num_glyphs);
@ -1141,7 +1305,7 @@ _cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font,
goto DONE;
}
status = _cairo_utf8_to_ucs4 ((unsigned char*)utf8, -1, &ucs4, num_glyphs);
status = _cairo_utf8_to_ucs4 (utf8, -1, &ucs4, num_glyphs);
if (status)
goto DONE;
@ -1212,7 +1376,7 @@ _cairo_scaled_font_glyph_device_extents (cairo_scaled_font_t *scaled_font,
if (status)
return _cairo_scaled_font_set_error (scaled_font, status);
/* glyph images are snapped to pixel locations */
/* XXX glyph images are snapped to pixel locations */
x = _cairo_lround (glyphs[i].x);
y = _cairo_lround (glyphs[i].y);
@ -1271,13 +1435,18 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font,
return CAIRO_STATUS_SUCCESS;
if (scaled_font->backend->show_glyphs != NULL) {
int remaining_glyphs = num_glyphs;
status = scaled_font->backend->show_glyphs (scaled_font,
op, pattern,
surface,
source_x, source_y,
dest_x, dest_y,
width, height,
glyphs, num_glyphs);
glyphs, num_glyphs, &remaining_glyphs);
glyphs += num_glyphs - remaining_glyphs;
num_glyphs = remaining_glyphs;
if (remaining_glyphs == 0)
status = CAIRO_STATUS_SUCCESS;
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return _cairo_scaled_font_set_error (scaled_font, status);
}
@ -1641,7 +1810,7 @@ _cairo_scaled_font_glyph_path (cairo_scaled_font_t *scaled_font,
}
/**
* cairo_scaled_glyph_set_metrics:
* _cairo_scaled_glyph_set_metrics:
* @scaled_glyph: a #cairo_scaled_glyph_t
* @scaled_font: a #cairo_scaled_font_t
* @fs_metrics: a #cairo_text_extents_t in font space
@ -1649,7 +1818,7 @@ _cairo_scaled_font_glyph_path (cairo_scaled_font_t *scaled_font,
* _cairo_scaled_glyph_set_metrics() stores user space metrics
* for the specified glyph given font space metrics. It is
* called by the font backend when initializing a glyph with
* CAIRO_SCALED_GLYPH_INFO_METRICS.
* %CAIRO_SCALED_GLYPH_INFO_METRICS.
**/
void
_cairo_scaled_glyph_set_metrics (cairo_scaled_glyph_t *scaled_glyph,
@ -1744,6 +1913,16 @@ _cairo_scaled_glyph_set_path (cairo_scaled_glyph_t *scaled_glyph,
scaled_glyph->path = path;
}
void
_cairo_scaled_glyph_set_meta_surface (cairo_scaled_glyph_t *scaled_glyph,
cairo_scaled_font_t *scaled_font,
cairo_surface_t *meta_surface)
{
if (scaled_glyph->meta_surface != NULL)
cairo_surface_destroy (meta_surface);
scaled_glyph->meta_surface = meta_surface;
}
/**
* _cairo_scaled_glyph_lookup:
* @scaled_font: a #cairo_scaled_font_t
@ -1763,7 +1942,7 @@ _cairo_scaled_glyph_set_path (cairo_scaled_glyph_t *scaled_glyph,
*
* If the desired info is not available, (for example, when trying to
* get INFO_PATH with a bitmapped font), this function will return
* CAIRO_INT_STATUS_UNSUPPORTED.
* %CAIRO_INT_STATUS_UNSUPPORTED.
*
* Note: This function must be called with scaled_font->mutex held.
**/
@ -1799,10 +1978,11 @@ _cairo_scaled_glyph_lookup (cairo_scaled_font_t *scaled_font,
}
_cairo_scaled_glyph_set_index(scaled_glyph, index);
scaled_glyph->cache_entry.size = 1; /* XXX */
scaled_glyph->cache_entry.size = 1; /* We currently don't differentiate on glyph size at all */
scaled_glyph->scaled_font = scaled_font;
scaled_glyph->surface = NULL;
scaled_glyph->path = NULL;
scaled_glyph->meta_surface = NULL;
scaled_glyph->surface_private = NULL;
/* ask backend to initialize metrics and shape fields */
@ -1834,11 +2014,38 @@ _cairo_scaled_glyph_lookup (cairo_scaled_font_t *scaled_font,
scaled_glyph->path == NULL))
need_info |= CAIRO_SCALED_GLYPH_INFO_PATH;
if (((info & CAIRO_SCALED_GLYPH_INFO_META_SURFACE) != 0 &&
scaled_glyph->path == NULL))
need_info |= CAIRO_SCALED_GLYPH_INFO_META_SURFACE;
if (need_info) {
status = (*scaled_font->backend->
scaled_glyph_init) (scaled_font, scaled_glyph, need_info);
if (status)
goto CLEANUP;
/* Don't trust the scaled_glyph_init() return value, the font
* backend may not even know about some of the info. For example,
* no backend other than the user-fonts knows about meta-surface
* glyph info. */
if ((info & CAIRO_SCALED_GLYPH_INFO_SURFACE) != 0 &&
scaled_glyph->surface == NULL) {
status = CAIRO_INT_STATUS_UNSUPPORTED;
goto CLEANUP;
}
if ((info & CAIRO_SCALED_GLYPH_INFO_PATH) != 0 &&
scaled_glyph->path == NULL) {
status = CAIRO_INT_STATUS_UNSUPPORTED;
goto CLEANUP;
}
if ((info & CAIRO_SCALED_GLYPH_INFO_META_SURFACE) != 0 &&
scaled_glyph->meta_surface == NULL) {
status = CAIRO_INT_STATUS_UNSUPPORTED;
goto CLEANUP;
}
}
CLEANUP:
@ -1854,6 +2061,13 @@ _cairo_scaled_glyph_lookup (cairo_scaled_font_t *scaled_font,
return status;
}
double
_cairo_scaled_font_get_max_scale (cairo_scaled_font_t *scaled_font)
{
return scaled_font->max_scale;
}
/**
* cairo_scaled_font_get_font_face:
* @scaled_font: a #cairo_scaled_font_t
@ -1920,6 +2134,30 @@ cairo_scaled_font_get_ctm (cairo_scaled_font_t *scaled_font,
}
slim_hidden_def (cairo_scaled_font_get_ctm);
/**
* cairo_scaled_font_get_scale_matrix:
* @scaled_font: a #cairo_scaled_font_t
* @scale_matrix: return value for the matrix
*
* Stores the scale matrix of @scaled_font into @matrix.
* The scale matrix is product of the font matrix and the ctm
* associated with the scaled font, and hence is the matrix mapping from
* font space to device space.
*
* Since: 1.8
**/
void
cairo_scaled_font_get_scale_matrix (cairo_scaled_font_t *scaled_font,
cairo_matrix_t *scale_matrix)
{
if (scaled_font->status) {
cairo_matrix_init_identity (scale_matrix);
return;
}
*scale_matrix = scaled_font->scale;
}
/**
* cairo_scaled_font_get_font_options:
* @scaled_font: a #cairo_scaled_font_t

Просмотреть файл

@ -358,7 +358,7 @@ _clip_and_composite (cairo_clip_t *clip,
cairo_surface_t *dst,
const cairo_rectangle_int_t *extents)
{
cairo_pattern_union_t solid_pattern;
cairo_solid_pattern_t solid_pattern;
cairo_status_t status;
if (_cairo_rectangle_empty (extents))
@ -366,7 +366,7 @@ _clip_and_composite (cairo_clip_t *clip,
return CAIRO_STATUS_SUCCESS;
if (op == CAIRO_OPERATOR_CLEAR) {
_cairo_pattern_init_solid (&solid_pattern.solid, CAIRO_COLOR_WHITE,
_cairo_pattern_init_solid (&solid_pattern, CAIRO_COLOR_WHITE,
CAIRO_CONTENT_COLOR);
src = &solid_pattern.base;
op = CAIRO_OPERATOR_DEST_OUT;
@ -415,14 +415,14 @@ _composite_trap_region (cairo_clip_t *clip,
cairo_rectangle_int_t *extents)
{
cairo_status_t status;
cairo_pattern_union_t solid_pattern;
cairo_pattern_union_t mask;
cairo_solid_pattern_t solid_pattern;
cairo_surface_pattern_t mask;
int num_rects = _cairo_region_num_boxes (trap_region);
unsigned int clip_serial;
cairo_surface_t *clip_surface = clip ? clip->surface : NULL;
if (clip_surface && op == CAIRO_OPERATOR_CLEAR) {
_cairo_pattern_init_solid (&solid_pattern.solid, CAIRO_COLOR_WHITE,
_cairo_pattern_init_solid (&solid_pattern, CAIRO_COLOR_WHITE,
CAIRO_CONTENT_COLOR);
src = &solid_pattern.base;
op = CAIRO_OPERATOR_DEST_OUT;
@ -444,7 +444,7 @@ _composite_trap_region (cairo_clip_t *clip,
}
if (clip_surface)
_cairo_pattern_init_for_surface (&mask.surface, clip_surface);
_cairo_pattern_init_for_surface (&mask, clip_surface);
status = _cairo_surface_composite (op,
src,
@ -487,13 +487,13 @@ _composite_traps_draw_func (void *closure,
const cairo_rectangle_int_t *extents)
{
cairo_composite_traps_info_t *info = closure;
cairo_pattern_union_t pattern;
cairo_solid_pattern_t pattern;
cairo_status_t status;
if (dst_x != 0 || dst_y != 0)
_cairo_traps_translate (info->traps, - dst_x, - dst_y);
_cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE,
_cairo_pattern_init_solid (&pattern, CAIRO_COLOR_WHITE,
CAIRO_CONTENT_COLOR);
if (!src)
src = &pattern.base;
@ -929,7 +929,7 @@ _cairo_surface_old_show_glyphs_draw_func (void *closure
const cairo_rectangle_int_t *extents)
{
cairo_show_glyphs_info_t *glyph_info = closure;
cairo_pattern_union_t pattern;
cairo_solid_pattern_t pattern;
cairo_status_t status;
/* Modifying the glyph array is fine because we know that this function
@ -946,7 +946,7 @@ _cairo_surface_old_show_glyphs_draw_func (void *closure
}
}
_cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE,
_cairo_pattern_init_solid (&pattern, CAIRO_COLOR_WHITE,
CAIRO_CONTENT_COLOR);
if (!src)
src = &pattern.base;
@ -1032,7 +1032,7 @@ _cairo_surface_fallback_snapshot (cairo_surface_t *surface)
{
cairo_surface_t *snapshot;
cairo_status_t status;
cairo_pattern_union_t pattern;
cairo_surface_pattern_t pattern;
cairo_image_surface_t *image;
void *image_extra;
@ -1050,7 +1050,7 @@ _cairo_surface_fallback_snapshot (cairo_surface_t *surface)
return snapshot;
}
_cairo_pattern_init_for_surface (&pattern.surface, &image->base);
_cairo_pattern_init_for_surface (&pattern, &image->base);
status = _cairo_surface_composite (CAIRO_OPERATOR_SOURCE,
&pattern.base,

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше