зеркало из https://github.com/mozilla/pjs.git
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:
Коммит
1a37b01f3c
|
@ -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, ®ion->rgn))
|
||||
if (! pixman_image_set_clip_region32 (surface->pixman_image, ®ion->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 (®ion->rgn);
|
||||
pixman_region32_init (®ion->rgn);
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_region_init_rect (cairo_region_t *region,
|
||||
cairo_rectangle_int_t *rect)
|
||||
{
|
||||
pixman_region_init_rect (®ion->rgn,
|
||||
pixman_region32_init_rect (®ion->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 (®ion->rgn, pboxes, count))
|
||||
if (!pixman_region32_init_rects (®ion->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 (®ion->rgn);
|
||||
pixman_region32_fini (®ion->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 (®ion->rgn);
|
||||
return pixman_region32_n_rects (®ion->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 (®ion->rgn, &nboxes);
|
||||
pboxes = pixman_region32_rectangles (®ion->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 (®ion->rgn);
|
||||
pixman_box32_t *pextents = pixman_region32_extents (®ion->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 (®ion->rgn);
|
||||
return (cairo_bool_t) pixman_region32_not_empty (®ion->rgn);
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_region_translate (cairo_region_t *region,
|
||||
int x, int y)
|
||||
{
|
||||
pixman_region_translate (®ion->rgn, x, y);
|
||||
pixman_region32_translate (®ion->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 (®ion->rgn, &pbox);
|
||||
return pixman_region32_contains_rectangle (®ion->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,
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче