diff --git a/browser/components/nsBrowserGlue.js b/browser/components/nsBrowserGlue.js index bdee2a60991..bac3e91de04 100644 --- a/browser/components/nsBrowserGlue.js +++ b/browser/components/nsBrowserGlue.js @@ -376,8 +376,13 @@ BrowserGlue.prototype = { // Browser startup complete. All initial windows have opened. _onBrowserStartup: function BG__onBrowserStartup() { // Show about:rights notification, if needed. - if (this._shouldShowRights()) + if (this._shouldShowRights()) { this._showRightsNotification(); + } else { + // Only show telemetry notification when about:rights notification is not shown. + this._showTelemetryNotification(); + } + // Show update notification, if needed. if (Services.prefs.prefHasUserValue("app.update.postupdate")) @@ -735,6 +740,72 @@ BrowserGlue.prototype = { } }, + _showTelemetryNotification: function BG__showTelemetryNotification() { + const PREF_TELEMETRY_PROMPTED = "toolkit.telemetry.prompted"; + const PREF_TELEMETRY_ENABLED = "toolkit.telemetry.enabled"; + const PREF_TELEMETRY_INFOURL = "toolkit.telemetry.infoURL"; + const PREF_TELEMETRY_SERVER_OWNER = "toolkit.telemetry.server_owner"; + + try { + // If the user hasn't already been prompted, ask if they want to + // send telemetry data. + if (Services.prefs.getBoolPref(PREF_TELEMETRY_ENABLED) || + Services.prefs.getBoolPref(PREF_TELEMETRY_PROMPTED)) + return; + } catch(e) {} + + // Stick the notification onto the selected tab of the active browser window. + var win = this.getMostRecentBrowserWindow(); + var browser = win.gBrowser; // for closure in notification bar callback + var notifyBox = browser.getNotificationBox(); + + var browserBundle = Services.strings.createBundle("chrome://browser/locale/browser.properties"); + var brandBundle = Services.strings.createBundle("chrome://branding/locale/brand.properties"); + + var productName = brandBundle.GetStringFromName("brandFullName"); + var serverOwner = Services.prefs.getCharPref(PREF_TELEMETRY_SERVER_OWNER); + var telemetryText = browserBundle.formatStringFromName("telemetryText", [productName, serverOwner], 2); + + var buttons = [ + { + label: browserBundle.GetStringFromName("telemetryYesButtonLabel"), + accessKey: browserBundle.GetStringFromName("telemetryYesButtonAccessKey"), + popup: null, + callback: function(aNotificationBar, aButton) { + Services.prefs.setBoolPref(PREF_TELEMETRY_ENABLED, true); + } + }, + { + label: browserBundle.GetStringFromName("telemetryNoButtonLabel"), + accessKey: browserBundle.GetStringFromName("telemetryNoButtonAccessKey"), + popup: null, + callback: function(aNotificationBar, aButton) {} + } + ]; + + // Set pref to indicate we've shown the notification. + Services.prefs.setBoolPref(PREF_TELEMETRY_PROMPTED, true); + + var notification = notifyBox.appendNotification(telemetryText, "telemetry", null, notifyBox.PRIORITY_INFO_LOW, buttons); + notification.persistence = 3; // arbitrary number, just so bar sticks around for a bit + + let XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; + let link = notification.ownerDocument.createElementNS(XULNS, "label"); + link.className = "text-link telemetry-text-link"; + link.setAttribute("value", browserBundle.GetStringFromName("telemetryLinkLabel")); + link.addEventListener('click', function() { + // Open the learn more url in a new tab + browser.selectedTab = browser.addTab(Services.prefs.getCharPref(PREF_TELEMETRY_INFOURL)); + // Remove the notification on which the user clicked + notification.parentNode.removeNotification(notification, true); + // Add a new notification to that tab, with no "Learn more" link + var notifyBox = browser.getNotificationBox(); + notifyBox.appendNotification(telemetryText, "telemetry", null, notifyBox.PRIORITY_INFO_LOW, buttons); + }, false); + let description = notification.ownerDocument.getAnonymousElementByAttribute(notification, "anonid", "messageText"); + description.appendChild(link); + }, + _showPluginUpdatePage: function BG__showPluginUpdatePage() { Services.prefs.setBoolPref(PREF_PLUGINS_NOTIFYUSER, false); diff --git a/browser/components/preferences/advanced.xul b/browser/components/preferences/advanced.xul index 98a9c47270f..92537f1ea7f 100644 --- a/browser/components/preferences/advanced.xul +++ b/browser/components/preferences/advanced.xul @@ -82,6 +82,10 @@ type="bool"/> #endif + + @@ -193,11 +197,11 @@ preference="layout.spellcheckDefault"/> -#ifdef HAVE_SHELL_SERVICE +#ifdef HAVE_SHELL_SERVICE #endif - #endif + + diff --git a/browser/components/sessionstore/src/nsSessionStore.js b/browser/components/sessionstore/src/nsSessionStore.js index bb78d1e9ff4..e0348a4d66a 100644 --- a/browser/components/sessionstore/src/nsSessionStore.js +++ b/browser/components/sessionstore/src/nsSessionStore.js @@ -2933,8 +2933,7 @@ SessionStoreService.prototype = { // force session history to update its internal index and call reload // instead of gotoIndex. See bug 597315. browser.webNavigation.sessionHistory.getEntryAtIndex(activeIndex, true); - browser.webNavigation.sessionHistory. - QueryInterface(Ci.nsISHistory).reloadCurrentEntry(); + browser.webNavigation.sessionHistory.reloadCurrentEntry(); } catch (ex) { // ignore page load errors diff --git a/browser/locales/en-US/chrome/browser/browser.properties b/browser/locales/en-US/chrome/browser/browser.properties index fddc48202a9..da966fb0587 100644 --- a/browser/locales/en-US/chrome/browser/browser.properties +++ b/browser/locales/en-US/chrome/browser/browser.properties @@ -325,3 +325,13 @@ syncPromoNotification.bookmarks.description=You can access your bookmarks on all # The final space separates this text from the Learn More link. syncPromoNotification.passwords.description=You can access your passwords on all your devices with %S.\u0020 syncPromoNotification.learnMoreLinkText=Learn More + +# Telemetry prompt +# LOCALIZATION NOTE (telemetryText): %1$S will be replaced by brandFullName, +# and %2$S by the value of the toolkit.telemetry.server_owner preference. +telemetryText = Would you like to help improve %1$S by automatically reporting memory usage, performance, and responsiveness to %2$S? +telemetryLinkLabel = Learn More +telemetryYesButtonLabel = Yes +telemetryYesButtonAccessKey = Y +telemetryNoButtonLabel = No +telemetryNoButtonAccessKey = N diff --git a/browser/locales/en-US/chrome/browser/preferences/advanced.dtd b/browser/locales/en-US/chrome/browser/preferences/advanced.dtd index 042f5b4fe7e..cf3a70c71c8 100644 --- a/browser/locales/en-US/chrome/browser/preferences/advanced.dtd +++ b/browser/locales/en-US/chrome/browser/preferences/advanced.dtd @@ -29,6 +29,8 @@ + + diff --git a/browser/themes/pinstripe/browser/browser.css b/browser/themes/pinstripe/browser/browser.css index 9c71e660b7f..f72b92f74c8 100644 --- a/browser/themes/pinstripe/browser/browser.css +++ b/browser/themes/pinstripe/browser/browser.css @@ -2167,6 +2167,10 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker { -moz-margin-start: 0; /* override default label margin to match description margin */ } +.telemetry-text-link { + color: #fff; +} + #addons-notification-icon { list-style-image: url(chrome://mozapps/skin/extensions/extensionGeneric-16.png); } diff --git a/content/base/public/nsINode.h b/content/base/public/nsINode.h index b24f389afaa..a327bb10c57 100644 --- a/content/base/public/nsINode.h +++ b/content/base/public/nsINode.h @@ -979,6 +979,8 @@ public: return NS_ERROR_NOT_IMPLEMENTED; } + nsresult Normalize(); + /** * Get the base URI for any relative URIs within this piece of * content. Generally, this is the document's base URI, but certain diff --git a/content/base/src/nsContentUtils.cpp b/content/base/src/nsContentUtils.cpp index 063901708d9..46a5d54c7cd 100644 --- a/content/base/src/nsContentUtils.cpp +++ b/content/base/src/nsContentUtils.cpp @@ -5362,10 +5362,14 @@ public: mFlags = WANT_ALL_TRACES; } - NS_IMETHOD_(void) DescribeNode(CCNodeType type, - nsrefcnt refcount, - size_t objsz, - const char* objname) + NS_IMETHOD_(void) DescribeRefCountedNode(nsrefcnt refCount, + size_t objSz, + const char *objName) + { + } + NS_IMETHOD_(void) DescribeGCedNode(PRBool isMarked, + size_t objSz, + const char *objName) { } NS_IMETHOD_(void) NoteXPCOMRoot(nsISupports *root) diff --git a/content/base/src/nsDocument.cpp b/content/base/src/nsDocument.cpp index a7de03c22d5..badcc75d821 100644 --- a/content/base/src/nsDocument.cpp +++ b/content/base/src/nsDocument.cpp @@ -1808,11 +1808,10 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsDocument) else { PR_snprintf(name, sizeof(name), "nsDocument %s", uri.get()); } - cb.DescribeNode(RefCounted, tmp->mRefCnt.get(), sizeof(nsDocument), name); + cb.DescribeRefCountedNode(tmp->mRefCnt.get(), sizeof(nsDocument), name); } else { - cb.DescribeNode(RefCounted, tmp->mRefCnt.get(), sizeof(nsDocument), - "nsDocument"); + NS_IMPL_CYCLE_COLLECTION_DESCRIBE(nsDocument, tmp->mRefCnt.get()) } // Always need to traverse script objects, so do that before we check @@ -5774,12 +5773,7 @@ nsDocument::CloneNode(PRBool aDeep, nsIDOMNode** aReturn) NS_IMETHODIMP nsDocument::Normalize() { - for (PRUint32 i = 0; i < mChildren.ChildCount(); ++i) { - nsCOMPtr node(do_QueryInterface(mChildren.ChildAt(i))); - node->Normalize(); - } - - return NS_OK; + return nsIDocument::Normalize(); } NS_IMETHODIMP diff --git a/content/base/src/nsFrameMessageManager.cpp b/content/base/src/nsFrameMessageManager.cpp index def27a981bb..b7ba0bb00db 100644 --- a/content/base/src/nsFrameMessageManager.cpp +++ b/content/base/src/nsFrameMessageManager.cpp @@ -369,7 +369,7 @@ nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget, jsval targetv; nsContentUtils::WrapNative(ctx, JS_GetGlobalForObject(ctx, object), - aTarget, &targetv); + aTarget, &targetv, nsnull, PR_TRUE); // To keep compatibility with e10s message manager, // define empty objects array. @@ -382,6 +382,11 @@ nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget, } } + js::AutoValueRooter objectsv(ctx); + objectsv.set(OBJECT_TO_JSVAL(aObjectsArray)); + if (!JS_WrapValue(ctx, objectsv.jsval_addr())) + return NS_ERROR_UNEXPECTED; + jsval json = JSVAL_NULL; if (!aJSON.IsEmpty()) { if (!JS_ParseJSON(ctx, (jschar*)nsString(aJSON).get(), @@ -400,8 +405,7 @@ nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget, JS_DefineProperty(ctx, param, "sync", BOOLEAN_TO_JSVAL(aSync), NULL, NULL, JSPROP_ENUMERATE); JS_DefineProperty(ctx, param, "json", json, NULL, NULL, JSPROP_ENUMERATE); - JS_DefineProperty(ctx, param, "objects", OBJECT_TO_JSVAL(aObjectsArray), - NULL, NULL, JSPROP_ENUMERATE); + JS_DefineProperty(ctx, param, "objects", objectsv.jsval_value(), NULL, NULL, JSPROP_ENUMERATE); jsval thisValue = JSVAL_VOID; @@ -421,7 +425,7 @@ nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget, } nsContentUtils::WrapNative(ctx, JS_GetGlobalForObject(ctx, object), - defaultThisValue, &thisValue); + defaultThisValue, &thisValue, nsnull, PR_TRUE); } else { // If the listener is a JS object which has receiveMessage function: NS_ENSURE_STATE(JS_GetProperty(ctx, object, "receiveMessage", diff --git a/content/base/src/nsGenericDOMDataNode.cpp b/content/base/src/nsGenericDOMDataNode.cpp index a35782277cb..bf3f9624dc7 100644 --- a/content/base/src/nsGenericDOMDataNode.cpp +++ b/content/base/src/nsGenericDOMDataNode.cpp @@ -172,12 +172,6 @@ nsGenericDOMDataNode::GetPrefix(nsAString& aPrefix) return NS_OK; } -nsresult -nsGenericDOMDataNode::Normalize() -{ - return NS_OK; -} - nsresult nsGenericDOMDataNode::IsSupported(const nsAString& aFeature, const nsAString& aVersion, diff --git a/content/base/src/nsGenericDOMDataNode.h b/content/base/src/nsGenericDOMDataNode.h index 4d92cf2bd14..d341123431d 100644 --- a/content/base/src/nsGenericDOMDataNode.h +++ b/content/base/src/nsGenericDOMDataNode.h @@ -143,7 +143,6 @@ public: return NS_OK; } nsresult GetPrefix(nsAString& aPrefix); - nsresult Normalize(); nsresult IsSupported(const nsAString& aFeature, const nsAString& aVersion, PRBool* aReturn); diff --git a/content/base/src/nsGenericElement.cpp b/content/base/src/nsGenericElement.cpp index 11289342e71..016d1f66eb3 100644 --- a/content/base/src/nsGenericElement.cpp +++ b/content/base/src/nsGenericElement.cpp @@ -541,6 +541,96 @@ nsINode::RemoveChild(nsIDOMNode* aOldChild, nsIDOMNode** aReturn) return rv; } +nsresult +nsINode::Normalize() +{ + // First collect list of nodes to be removed + nsAutoTArray, 50> nodes; + + PRBool canMerge = PR_FALSE; + for (nsIContent* node = this->GetFirstChild(); + node; + node = node->GetNextNode(this)) { + if (node->NodeType() != nsIDOMNode::TEXT_NODE) { + canMerge = PR_FALSE; + continue; + } + + if (canMerge || node->TextLength() == 0) { + // No need to touch canMerge. That way we can merge across empty + // textnodes if and only if the node before is a textnode + nodes.AppendElement(node); + } + else { + canMerge = PR_TRUE; + } + + // If there's no following sibling, then we need to ensure that we don't + // collect following siblings of our (grand)parent as to-be-removed + canMerge = canMerge && !!node->GetNextSibling(); + } + + if (nodes.IsEmpty()) { + return NS_OK; + } + + // We're relying on mozAutoSubtreeModified to keep the doc alive here. + nsIDocument* doc = GetOwnerDoc(); + + // Batch possible DOMSubtreeModified events. + mozAutoSubtreeModified subtree(doc, nsnull); + + // Fire all DOMNodeRemoved events. Optimize the common case of there being + // no listeners + PRBool hasRemoveListeners = nsContentUtils:: + HasMutationListeners(doc, NS_EVENT_BITS_MUTATION_NODEREMOVED); + if (hasRemoveListeners) { + for (PRUint32 i = 0; i < nodes.Length(); ++i) { + nsContentUtils::MaybeFireNodeRemoved(nodes[i], nodes[i]->GetNodeParent(), + doc); + } + } + + mozAutoDocUpdate batch(doc, UPDATE_CONTENT_MODEL, PR_TRUE); + + // Merge and remove all nodes + nsAutoString tmpStr; + for (PRUint32 i = 0; i < nodes.Length(); ++i) { + nsIContent* node = nodes[i]; + // Merge with previous node unless empty + const nsTextFragment* text = node->GetText(); + if (text->GetLength()) { + nsIContent* target = node->GetPreviousSibling(); + NS_ASSERTION((target && target->NodeType() == nsIDOMNode::TEXT_NODE) || + hasRemoveListeners, + "Should always have a previous text sibling unless " + "mutation events messed us up"); + if (!hasRemoveListeners || + (target && target->NodeType() == nsIDOMNode::TEXT_NODE)) { + if (text->Is2b()) { + target->AppendText(text->Get2b(), text->GetLength(), PR_TRUE); + } + else { + tmpStr.Truncate(); + text->AppendTo(tmpStr); + target->AppendText(tmpStr.get(), tmpStr.Length(), PR_TRUE); + } + } + } + + // Remove node + nsINode* parent = node->GetNodeParent(); + NS_ASSERTION(parent || hasRemoveListeners, + "Should always have a parent unless " + "mutation events messed us up"); + if (parent) { + parent->RemoveChildAt(parent->IndexOf(node), PR_TRUE); + } + } + + return NS_OK; +} + nsresult nsINode::GetDOMBaseURI(nsAString &aURI) const { @@ -2619,103 +2709,6 @@ nsGenericElement::HasAttributeNS(const nsAString& aNamespaceURI, return NS_OK; } -nsresult -nsGenericElement::JoinTextNodes(nsIContent* aFirst, - nsIContent* aSecond) -{ - nsresult rv = NS_OK; - nsCOMPtr firstText(do_QueryInterface(aFirst, &rv)); - - if (NS_SUCCEEDED(rv)) { - nsCOMPtr secondText(do_QueryInterface(aSecond, &rv)); - - if (NS_SUCCEEDED(rv)) { - nsAutoString str; - - rv = secondText->GetData(str); - if (NS_SUCCEEDED(rv)) { - rv = firstText->AppendData(str); - } - } - } - - return rv; -} - -nsresult -nsGenericElement::Normalize() -{ - // We're relying on mozAutoSubtreeModified to keep the doc alive here. - nsIDocument* doc = GetOwnerDoc(); - - // Batch possible DOMSubtreeModified events. - mozAutoSubtreeModified subtree(doc, nsnull); - - bool hasRemoveListeners = nsContentUtils:: - HasMutationListeners(doc, NS_EVENT_BITS_MUTATION_NODEREMOVED); - - nsresult result = NS_OK; - PRUint32 index, count = GetChildCount(); - - for (index = 0; (index < count) && (NS_OK == result); index++) { - nsIContent *child = GetChildAt(index); - - switch (child->NodeType()) { - case nsIDOMNode::TEXT_NODE: - - // ensure that if the text node is empty, it is removed - if (0 == child->TextLength()) { - if (hasRemoveListeners) { - nsContentUtils::MaybeFireNodeRemoved(child, this, doc); - } - result = RemoveChildAt(index, PR_TRUE); - if (NS_FAILED(result)) { - return result; - } - - count--; - index--; - break; - } - - if (index+1 < count) { - // Get the sibling. If it's also a text node, then - // remove it from the tree and join the two text - // nodes. - nsCOMPtr sibling = GetChildAt(index + 1); - - if (sibling->NodeType() == nsIDOMNode::TEXT_NODE) { - if (hasRemoveListeners) { - nsContentUtils::MaybeFireNodeRemoved(sibling, this, doc); - } - result = RemoveChildAt(index+1, PR_TRUE); - if (NS_FAILED(result)) { - return result; - } - - result = JoinTextNodes(child, sibling); - if (NS_FAILED(result)) { - return result; - } - count--; - index--; - } - } - break; - - case nsIDOMNode::ELEMENT_NODE: - nsCOMPtr element = do_QueryInterface(child); - - if (element) { - result = element->Normalize(); - } - break; - } - } - - return result; -} - static nsXBLBinding* GetFirstBindingWithContent(nsBindingManager* aBmgr, nsIContent* aBoundElem) { @@ -4182,12 +4175,11 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsGenericElement) else { PR_snprintf(name, sizeof(name), "nsGenericElement %s", localName.get()); } - cb.DescribeNode(RefCounted, tmp->mRefCnt.get(), sizeof(nsGenericElement), - name); + cb.DescribeRefCountedNode(tmp->mRefCnt.get(), sizeof(nsGenericElement), + name); } else { - cb.DescribeNode(RefCounted, tmp->mRefCnt.get(), sizeof(nsGenericElement), - "nsGenericElement"); + NS_IMPL_CYCLE_COLLECTION_DESCRIBE(nsGenericElement, tmp->mRefCnt.get()) } // Always need to traverse script objects, so do that before we check diff --git a/content/base/src/nsGenericElement.h b/content/base/src/nsGenericElement.h index 48494a530f3..fb3d2f144d1 100644 --- a/content/base/src/nsGenericElement.h +++ b/content/base/src/nsGenericElement.h @@ -400,7 +400,6 @@ public: NS_IMETHOD GetAttributes(nsIDOMNamedNodeMap** aAttributes); NS_IMETHOD GetNamespaceURI(nsAString& aNamespaceURI); NS_IMETHOD GetPrefix(nsAString& aPrefix); - NS_IMETHOD Normalize(); NS_IMETHOD IsSupported(const nsAString& aFeature, const nsAString& aVersion, PRBool* aReturn); NS_IMETHOD HasAttributes(PRBool* aHasAttributes); @@ -479,14 +478,6 @@ public: */ nsresult LeaveLink(nsPresContext* aPresContext); - /** - * Take two text nodes and append the second to the first. - * @param aFirst the node which will contain first + second [INOUT] - * @param aSecond the node which will be appended - */ - nsresult JoinTextNodes(nsIContent* aFirst, - nsIContent* aSecond); - /** * Check whether a spec feature/version is supported. * @param aObject the object, which should support the feature, diff --git a/content/base/src/nsNodeInfo.cpp b/content/base/src/nsNodeInfo.cpp index e9e82ad4b3a..4a05d20f558 100644 --- a/content/base/src/nsNodeInfo.cpp +++ b/content/base/src/nsNodeInfo.cpp @@ -198,11 +198,10 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsNodeInfo) PR_snprintf(name, sizeof(name), "nsNodeInfo %s", localName.get()); } - cb.DescribeNode(RefCounted, tmp->mRefCnt.get(), sizeof(nsNodeInfo), name); + cb.DescribeRefCountedNode(tmp->mRefCnt.get(), sizeof(nsNodeInfo), name); } else { - cb.DescribeNode(RefCounted, tmp->mRefCnt.get(), sizeof(nsNodeInfo), - "nsNodeInfo"); + NS_IMPL_CYCLE_COLLECTION_DESCRIBE(nsNodeInfo, tmp->mRefCnt.get()) } NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_MEMBER(mOwnerManager, diff --git a/content/canvas/public/nsICanvasRenderingContextInternal.h b/content/canvas/public/nsICanvasRenderingContextInternal.h index b8831bc68ff..dd9823ded8a 100644 --- a/content/canvas/public/nsICanvasRenderingContextInternal.h +++ b/content/canvas/public/nsICanvasRenderingContextInternal.h @@ -42,6 +42,7 @@ #include "nsIInputStream.h" #include "nsIDocShell.h" #include "gfxPattern.h" +#include "mozilla/RefPtr.h" #define NS_ICANVASRENDERINGCONTEXTINTERNAL_IID \ { 0xffb42d3c, 0x8281, 0x44c8, \ @@ -61,6 +62,9 @@ class LayerManager; namespace ipc { class Shmem; } +namespace gfx { +class SourceSurface; +} } class nsICanvasRenderingContextInternal : public nsISupports { @@ -96,6 +100,11 @@ public: // If this canvas context can be represented with a simple Thebes surface, // return the surface. Otherwise returns an error. NS_IMETHOD GetThebesSurface(gfxASurface **surface) = 0; + + // This gets an Azure SourceSurface for the canvas, this will be a snapshot + // of the canvas at the time it was called. This will return null for a + // non-azure canvas. + virtual mozilla::TemporaryRef GetSurfaceSnapshot() = 0; // If this context is opaque, the backing store of the canvas should // be created as opaque; all compositing operators should assume the diff --git a/content/canvas/src/Makefile.in b/content/canvas/src/Makefile.in index f98c7f4699d..c2738b68912 100644 --- a/content/canvas/src/Makefile.in +++ b/content/canvas/src/Makefile.in @@ -55,6 +55,7 @@ CPPSRCS = \ CanvasImageCache.cpp \ CanvasUtils.cpp \ nsCanvasRenderingContext2D.cpp \ + nsCanvasRenderingContext2DAzure.cpp \ DocumentRendererParent.cpp \ DocumentRendererChild.cpp \ $(NULL) diff --git a/content/canvas/src/WebGLContext.h b/content/canvas/src/WebGLContext.h index 84db7299fcc..949bd8bb959 100644 --- a/content/canvas/src/WebGLContext.h +++ b/content/canvas/src/WebGLContext.h @@ -342,6 +342,9 @@ public: const PRUnichar* aEncoderOptions, nsIInputStream **aStream); NS_IMETHOD GetThebesSurface(gfxASurface **surface); + mozilla::TemporaryRef GetSurfaceSnapshot() + { return nsnull; } + NS_IMETHOD SetIsOpaque(PRBool b) { return NS_OK; }; NS_IMETHOD SetContextOptions(nsIPropertyBag *aOptions); diff --git a/content/canvas/src/nsCanvasRenderingContext2D.cpp b/content/canvas/src/nsCanvasRenderingContext2D.cpp index 97abaa73c44..b57aea6d378 100644 --- a/content/canvas/src/nsCanvasRenderingContext2D.cpp +++ b/content/canvas/src/nsCanvasRenderingContext2D.cpp @@ -373,6 +373,9 @@ public: const PRUnichar* aEncoderOptions, nsIInputStream **aStream); NS_IMETHOD GetThebesSurface(gfxASurface **surface); + mozilla::TemporaryRef GetSurfaceSnapshot() + { return nsnull; } + NS_IMETHOD SetIsOpaque(PRBool isOpaque); NS_IMETHOD Reset(); already_AddRefed GetCanvasLayer(nsDisplayListBuilder* aBuilder, @@ -813,7 +816,7 @@ PRUint8 (*nsCanvasRenderingContext2D::sUnpremultiplyTable)[256] = nsnull; PRUint8 (*nsCanvasRenderingContext2D::sPremultiplyTable)[256] = nsnull; nsresult -NS_NewCanvasRenderingContext2D(nsIDOMCanvasRenderingContext2D** aResult) +NS_NewCanvasRenderingContext2DThebes(nsIDOMCanvasRenderingContext2D** aResult) { nsRefPtr ctx = new nsCanvasRenderingContext2D(); if (!ctx) diff --git a/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp b/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp new file mode 100644 index 00000000000..39a0bdae45b --- /dev/null +++ b/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp @@ -0,0 +1,4352 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.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/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Corporation code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Bas Schouten + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "base/basictypes.h" + +#include "nsIDOMXULElement.h" + +#include "prmem.h" +#include "prenv.h" + +#include "nsIServiceManager.h" +#include "nsMathUtils.h" + +#include "nsContentUtils.h" + +#include "nsIDOMDocument.h" +#include "nsIDocument.h" +#include "nsIDOMCanvasRenderingContext2D.h" +#include "nsICanvasRenderingContextInternal.h" +#include "nsHTMLCanvasElement.h" +#include "nsSVGEffects.h" +#include "nsPresContext.h" +#include "nsIPresShell.h" +#include "nsIVariant.h" + +#include "nsIInterfaceRequestorUtils.h" +#include "nsIFrame.h" +#include "nsDOMError.h" +#include "nsIScriptError.h" + +#include "nsCSSParser.h" +#include "mozilla/css/StyleRule.h" +#include "mozilla/css/Declaration.h" +#include "nsComputedDOMStyle.h" +#include "nsStyleSet.h" + +#include "nsPrintfCString.h" + +#include "nsReadableUtils.h" + +#include "nsColor.h" +#include "nsGfxCIID.h" +#include "nsIScriptSecurityManager.h" +#include "nsIDocShell.h" +#include "nsIDOMWindow.h" +#include "nsPIDOMWindow.h" +#include "nsIDocShell.h" +#include "nsIDocShellTreeItem.h" +#include "nsIDocShellTreeNode.h" +#include "nsIXPConnect.h" +#include "jsapi.h" +#include "nsDisplayList.h" + +#include "nsTArray.h" + +#include "imgIEncoder.h" + +#include "gfxContext.h" +#include "gfxASurface.h" +#include "gfxImageSurface.h" +#include "gfxPlatform.h" +#include "gfxFont.h" +#include "gfxTextRunCache.h" +#include "gfxBlur.h" +#include "gfxUtils.h" + +#include "nsFrameManager.h" +#include "nsFrameLoader.h" +#include "nsBidiPresUtils.h" +#include "Layers.h" +#include "CanvasUtils.h" +#include "nsIMemoryReporter.h" +#include "nsStyleUtil.h" +#include "CanvasImageCache.h" + +#include +#include "mozilla/dom/ContentParent.h" +#include "mozilla/ipc/PDocumentRendererParent.h" +#include "mozilla/dom/PBrowserParent.h" +#include "mozilla/ipc/DocumentRendererParent.h" + +#include "mozilla/gfx/2D.h" + +#ifdef XP_WIN +#include "gfxWindowsPlatform.h" +#endif + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +// windows.h (included by chromium code) defines this, in its infinite wisdom +#undef DrawText + +using namespace mozilla; +using namespace mozilla::layers; +using namespace mozilla::dom; +using namespace mozilla::gfx; +using namespace mozilla::ipc; +using namespace mozilla::css; + +namespace mgfx = mozilla::gfx; + +static float kDefaultFontSize = 10.0; +static NS_NAMED_LITERAL_STRING(kDefaultFontName, "sans-serif"); +static NS_NAMED_LITERAL_STRING(kDefaultFontStyle, "10px sans-serif"); + +/* Float validation stuff */ +#define VALIDATE(_f) if (!NS_finite(_f)) return PR_FALSE + +static PRBool FloatValidate (double f1) { + VALIDATE(f1); + return PR_TRUE; +} + +static PRBool FloatValidate (double f1, double f2) { + VALIDATE(f1); VALIDATE(f2); + return PR_TRUE; +} + +static PRBool FloatValidate (double f1, double f2, double f3) { + VALIDATE(f1); VALIDATE(f2); VALIDATE(f3); + return PR_TRUE; +} + +static PRBool FloatValidate (double f1, double f2, double f3, double f4) { + VALIDATE(f1); VALIDATE(f2); VALIDATE(f3); VALIDATE(f4); + return PR_TRUE; +} + +static PRBool FloatValidate (double f1, double f2, double f3, double f4, double f5) { + VALIDATE(f1); VALIDATE(f2); VALIDATE(f3); VALIDATE(f4); VALIDATE(f5); + return PR_TRUE; +} + +static PRBool FloatValidate (double f1, double f2, double f3, double f4, double f5, double f6) { + VALIDATE(f1); VALIDATE(f2); VALIDATE(f3); VALIDATE(f4); VALIDATE(f5); VALIDATE(f6); + return PR_TRUE; +} + +#undef VALIDATE + +/* Memory reporter stuff */ +static nsIMemoryReporter *gCanvasAzureMemoryReporter = nsnull; +static PRInt64 gCanvasAzureMemoryUsed = 0; + +static PRInt64 GetCanvasAzureMemoryUsed(void *) { + return gCanvasAzureMemoryUsed; +} + +// This is MR_OTHER because it's not always clear where in memory the pixels of +// a canvas are stored. Furthermore, this memory will be tracked by the +// underlying surface implementations. See bug 655638 for details. +NS_MEMORY_REPORTER_IMPLEMENT(CanvasAzureMemory, + "canvas-2d-pixel-bytes", + MR_OTHER, + "Memory used by 2D canvases. Each canvas requires (width * height * 4) " + "bytes.", + GetCanvasAzureMemoryUsed, + nsnull) + +/** + ** nsCanvasGradientAzure + **/ +#define NS_CANVASGRADIENTAZURE_PRIVATE_IID \ + {0x28425a6a, 0x90e0, 0x4d42, {0x9c, 0x75, 0xff, 0x60, 0x09, 0xb3, 0x10, 0xa8}} +class nsCanvasGradientAzure : public nsIDOMCanvasGradient +{ +public: + NS_DECLARE_STATIC_IID_ACCESSOR(NS_CANVASGRADIENTAZURE_PRIVATE_IID) + + enum Type + { + LINEAR = 0, + RADIAL + }; + + Type GetType() + { + return mType; + } + + + GradientStops *GetGradientStopsForTarget(DrawTarget *aRT) + { + if (mStops && mStops->GetBackendType() == aRT->GetType()) { + return mStops; + } + + mStops = aRT->CreateGradientStops(mRawStops.Elements(), mRawStops.Length()); + + return mStops; + } + + NS_DECL_ISUPPORTS + +protected: + nsCanvasGradientAzure(Type aType) : mType(aType) + {} + + nsTArray mRawStops; + RefPtr mStops; + Type mType; +}; + +class nsCanvasRadialGradientAzure : public nsCanvasGradientAzure +{ +public: + nsCanvasRadialGradientAzure(const Point &aBeginOrigin, Float aBeginRadius, + const Point &aEndOrigin, Float aEndRadius) + : nsCanvasGradientAzure(RADIAL) + , mCenter(aEndOrigin) + , mRadius(aEndRadius) + { + mOffsetStart = aBeginRadius / mRadius; + + mOffsetRatio = 1 - mOffsetStart; + mOrigin = ((mCenter * aBeginRadius) - (aBeginOrigin * mRadius)) / + (aBeginRadius - mRadius); + } + + + /* nsIDOMCanvasGradient */ + NS_IMETHOD AddColorStop (float offset, + const nsAString& colorstr) + { + if (!FloatValidate(offset) || offset < 0.0 || offset > 1.0) { + return NS_ERROR_DOM_INDEX_SIZE_ERR; + } + + nscolor color; + nsCSSParser parser; + nsresult rv = parser.ParseColorString(nsString(colorstr), + nsnull, 0, &color); + if (NS_FAILED(rv)) { + return NS_ERROR_DOM_SYNTAX_ERR; + } + + mStops = nsnull; + + GradientStop newStop; + + newStop.offset = offset * mOffsetRatio + mOffsetStart; + newStop.color = Color::FromABGR(color); + + mRawStops.AppendElement(newStop); + + return NS_OK; + } + + // XXX - Temporary gradient code, this will be fixed soon as per bug 666097 + Point mCenter; + Float mRadius; + Point mOrigin; + + Float mOffsetStart; + Float mOffsetRatio; +}; + +class nsCanvasLinearGradientAzure : public nsCanvasGradientAzure +{ +public: + nsCanvasLinearGradientAzure(const Point &aBegin, const Point &aEnd) + : nsCanvasGradientAzure(LINEAR) + , mBegin(aBegin) + , mEnd(aEnd) + { + } + + /* nsIDOMCanvasGradient */ + NS_IMETHOD AddColorStop (float offset, + const nsAString& colorstr) + { + if (!FloatValidate(offset) || offset < 0.0 || offset > 1.0) { + return NS_ERROR_DOM_INDEX_SIZE_ERR; + } + + nscolor color; + nsCSSParser parser; + nsresult rv = parser.ParseColorString(nsString(colorstr), + nsnull, 0, &color); + if (NS_FAILED(rv)) { + return NS_ERROR_DOM_SYNTAX_ERR; + } + + mStops = nsnull; + + GradientStop newStop; + + newStop.offset = offset; + newStop.color = Color::FromABGR(color); + + mRawStops.AppendElement(newStop); + + return NS_OK; + } + +protected: + friend class nsCanvasRenderingContext2DAzure; + + // Beginning of linear gradient. + Point mBegin; + // End of linear gradient. + Point mEnd; +}; + +NS_DEFINE_STATIC_IID_ACCESSOR(nsCanvasGradientAzure, NS_CANVASGRADIENTAZURE_PRIVATE_IID) + +NS_IMPL_ADDREF(nsCanvasGradientAzure) +NS_IMPL_RELEASE(nsCanvasGradientAzure) + +// XXX +// DOMCI_DATA(CanvasGradient, nsCanvasGradientAzure) + +NS_INTERFACE_MAP_BEGIN(nsCanvasGradientAzure) + NS_INTERFACE_MAP_ENTRY(nsCanvasGradientAzure) + NS_INTERFACE_MAP_ENTRY(nsIDOMCanvasGradient) + NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(CanvasGradient) + NS_INTERFACE_MAP_ENTRY(nsISupports) +NS_INTERFACE_MAP_END + +/** + ** nsCanvasPatternAzure + **/ +#define NS_CANVASPATTERNAZURE_PRIVATE_IID \ + {0xc9bacc25, 0x28da, 0x421e, {0x9a, 0x4b, 0xbb, 0xd6, 0x93, 0x05, 0x12, 0xbc}} +class nsCanvasPatternAzure : public nsIDOMCanvasPattern +{ +public: + NS_DECLARE_STATIC_IID_ACCESSOR(NS_CANVASPATTERNAZURE_PRIVATE_IID) + + enum RepeatMode + { + REPEAT, + REPEATX, + REPEATY, + NOREPEAT + }; + + nsCanvasPatternAzure(SourceSurface* aSurface, + RepeatMode aRepeat, + nsIPrincipal* principalForSecurityCheck, + PRBool forceWriteOnly) + : mSurface(aSurface) + , mRepeat(aRepeat) + , mPrincipal(principalForSecurityCheck) + , mForceWriteOnly(forceWriteOnly) + { + } + + NS_DECL_ISUPPORTS + + RefPtr mSurface; + RepeatMode mRepeat; + nsCOMPtr mPrincipal; + PRPackedBool mForceWriteOnly; +}; + +NS_DEFINE_STATIC_IID_ACCESSOR(nsCanvasPatternAzure, NS_CANVASPATTERNAZURE_PRIVATE_IID) + +NS_IMPL_ADDREF(nsCanvasPatternAzure) +NS_IMPL_RELEASE(nsCanvasPatternAzure) + +// XXX +// DOMCI_DATA(CanvasPattern, nsCanvasPatternAzure) + +NS_INTERFACE_MAP_BEGIN(nsCanvasPatternAzure) + NS_INTERFACE_MAP_ENTRY(nsCanvasPatternAzure) + NS_INTERFACE_MAP_ENTRY(nsIDOMCanvasPattern) + NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(CanvasPattern) + NS_INTERFACE_MAP_ENTRY(nsISupports) +NS_INTERFACE_MAP_END + +/** + ** nsTextMetricsAzure + **/ +#define NS_TEXTMETRICSAZURE_PRIVATE_IID \ + {0x9793f9e7, 0x9dc1, 0x4e9c, {0x81, 0xc8, 0xfc, 0xa7, 0x14, 0xf4, 0x30, 0x79}} +class nsTextMetricsAzure : public nsIDOMTextMetrics +{ +public: + nsTextMetricsAzure(float w) : width(w) { } + + virtual ~nsTextMetricsAzure() { } + + NS_DECLARE_STATIC_IID_ACCESSOR(NS_TEXTMETRICSAZURE_PRIVATE_IID) + + NS_IMETHOD GetWidth(float* w) { + *w = width; + return NS_OK; + } + + NS_DECL_ISUPPORTS + +private: + float width; +}; + +NS_DEFINE_STATIC_IID_ACCESSOR(nsTextMetricsAzure, NS_TEXTMETRICSAZURE_PRIVATE_IID) + +NS_IMPL_ADDREF(nsTextMetricsAzure) +NS_IMPL_RELEASE(nsTextMetricsAzure) + +// XXX +// DOMCI_DATA(TextMetrics, nsTextMetricsAzure) + +NS_INTERFACE_MAP_BEGIN(nsTextMetricsAzure) + NS_INTERFACE_MAP_ENTRY(nsTextMetricsAzure) + NS_INTERFACE_MAP_ENTRY(nsIDOMTextMetrics) + NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(TextMetrics) + NS_INTERFACE_MAP_ENTRY(nsISupports) +NS_INTERFACE_MAP_END + +struct nsCanvasBidiProcessorAzure; + +// Cap sigma to avoid overly large temp surfaces. +static const Float SIGMA_MAX = 100; + +/** + ** nsCanvasRenderingContext2DAzure + **/ +class nsCanvasRenderingContext2DAzure : + public nsIDOMCanvasRenderingContext2D, + public nsICanvasRenderingContextInternal +{ +public: + nsCanvasRenderingContext2DAzure(); + virtual ~nsCanvasRenderingContext2DAzure(); + + nsresult Redraw(); + + // nsICanvasRenderingContextInternal + NS_IMETHOD SetCanvasElement(nsHTMLCanvasElement* aParentCanvas); + NS_IMETHOD SetDimensions(PRInt32 width, PRInt32 height); + NS_IMETHOD InitializeWithSurface(nsIDocShell *shell, gfxASurface *surface, PRInt32 width, PRInt32 height) + { return NS_ERROR_NOT_IMPLEMENTED; } + + NS_IMETHOD Render(gfxContext *ctx, gfxPattern::GraphicsFilter aFilter); + NS_IMETHOD GetInputStream(const char* aMimeType, + const PRUnichar* aEncoderOptions, + nsIInputStream **aStream); + NS_IMETHOD GetThebesSurface(gfxASurface **surface); + + TemporaryRef GetSurfaceSnapshot() + { return mTarget ? mTarget->Snapshot() : nsnull; } + + NS_IMETHOD SetIsOpaque(PRBool isOpaque); + NS_IMETHOD Reset(); + already_AddRefed GetCanvasLayer(nsDisplayListBuilder* aBuilder, + CanvasLayer *aOldLayer, + LayerManager *aManager); + void MarkContextClean(); + NS_IMETHOD SetIsIPC(PRBool isIPC); + // this rect is in canvas device space + void Redraw(const mgfx::Rect &r); + NS_IMETHOD Redraw(const gfxRect &r) { Redraw(ToRect(r)); return NS_OK; } + + // this rect is in mTarget's current user space + nsresult RedrawUser(const gfxRect &r); + + // nsISupports interface + CC + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + + NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsCanvasRenderingContext2DAzure, nsIDOMCanvasRenderingContext2D) + + // nsIDOMCanvasRenderingContext2D interface + NS_DECL_NSIDOMCANVASRENDERINGCONTEXT2D + + enum Style { + STYLE_STROKE = 0, + STYLE_FILL, + STYLE_MAX + }; + +protected: + nsresult InitializeWithTarget(DrawTarget *surface, PRInt32 width, PRInt32 height); + + /** + * The number of living nsCanvasRenderingContexts. When this goes down to + * 0, we free the premultiply and unpremultiply tables, if they exist. + */ + static PRUint32 sNumLivingContexts; + + /** + * Lookup table used to speed up GetImageData(). + */ + static PRUint8 (*sUnpremultiplyTable)[256]; + + /** + * Lookup table used to speed up PutImageData(). + */ + static PRUint8 (*sPremultiplyTable)[256]; + + // Some helpers. Doesn't modify a color on failure. + nsresult SetStyleFromStringOrInterface(const nsAString& aStr, nsISupports *aInterface, Style aWhichStyle); + nsresult GetStyleAsStringOrInterface(nsAString& aStr, nsISupports **aInterface, PRInt32 *aType, Style aWhichStyle); + + void StyleColorToString(const nscolor& aColor, nsAString& aStr); + + /** + * Creates the unpremultiply lookup table, if it doesn't exist. + */ + void EnsureUnpremultiplyTable(); + + /** + * Creates the premultiply lookup table, if it doesn't exist. + */ + void EnsurePremultiplyTable(); + + /* This function ensures there is a writable pathbuilder available, this + * pathbuilder may be working in user space or in device space or + * device space. + */ + void EnsureWritablePath(); + + // Ensures a path in UserSpace is available. + void EnsureUserSpacePath(); + + void TransformWillUpdate(); + + // Report the fillRule has changed. + void FillRuleChanged(); + + /** + * Returns the surface format this canvas should be allocated using. Takes + * into account mOpaque, platform requirements, etc. + */ + SurfaceFormat GetSurfaceFormat() const; + + nsHTMLCanvasElement *HTMLCanvasElement() { + return static_cast(mCanvasElement.get()); + } + + // Member vars + PRInt32 mWidth, mHeight; + + // This is true when the canvas is valid, false otherwise, this occurs when + // for some reason initialization of the drawtarget fails. If the canvas + // is invalid certain behavior is expected. + PRPackedBool mValid; + // This is true when the canvas is valid, but of zero size, this requires + // specific behavior on some operations. + PRPackedBool mZero; + + PRPackedBool mOpaque; + + // This is true when the next time our layer is retrieved we need to + // recreate it (i.e. our backing surface changed) + PRPackedBool mResetLayer; + // This is needed for drawing in drawAsyncXULElement + PRPackedBool mIPC; + + // the canvas element we're a context of + nsCOMPtr mCanvasElement; + + // If mCanvasElement is not provided, then a docshell is + nsCOMPtr mDocShell; + + // our drawing surfaces, contexts, and layers + RefPtr mTarget; + + /** + * Flag to avoid duplicate calls to InvalidateFrame. Set to true whenever + * Redraw is called, reset to false when Render is called. + */ + PRPackedBool mIsEntireFrameInvalid; + /** + * When this is set, the first call to Redraw(gfxRect) should set + * mIsEntireFrameInvalid since we expect it will be followed by + * many more Redraw calls. + */ + PRPackedBool mPredictManyRedrawCalls; + + /** + * We also have a device space pathbuilder. The reason for this is as + * follows, when a path is being built, but the transform changes, we + * can no longer keep a single path in userspace, considering there's + * several 'user spaces' now. We therefore transform the current path + * into device space, and add all operations to this path in device + * space. + * + * When then finally executing a render, the Azure drawing API expects + * the path to be in userspace. We could then set an identity transform + * on the DrawTarget and do all drawing in device space. This is + * undesirable because it requires transforming patterns, gradients, + * clips, etc. into device space and it would not work for stroking. + * What we do instead is convert the path back to user space when it is + * drawn, and draw it with the current transform. This makes all drawing + * occur correctly. + * + * There's never both a device space path builder and a user space path + * builder present at the same time. There is also never a path and a + * path builder present at the same time. When writing proceeds on an + * existing path the Path is cleared and a new builder is created. + * + * mPath is always in user-space. + */ + RefPtr mPath; + RefPtr mDSPathBuilder; + RefPtr mPathBuilder; + bool mPathTransformWillUpdate; + Matrix mPathToDS; + + /** + * Number of times we've invalidated before calling redraw + */ + PRUint32 mInvalidateCount; + static const PRUint32 kCanvasMaxInvalidateCount = 100; + + /** + * Returns true if a shadow should be drawn along with a + * drawing operation. + */ + PRBool NeedToDrawShadow() + { + const ContextState& state = CurrentState(); + + // The spec says we should not draw shadows if the operator is OVER. + // If it's over and the alpha value is zero, nothing needs to be drawn. + return state.op == OP_OVER && NS_GET_A(state.shadowColor) != 0; + } + + /** + * Gets the pres shell from either the canvas element or the doc shell + */ + nsIPresShell *GetPresShell() { + nsCOMPtr content = + do_QueryInterface(static_cast(mCanvasElement)); + if (content) { + nsIDocument* ownerDoc = content->GetOwnerDoc(); + return ownerDoc ? ownerDoc->GetShell() : nsnull; + } + if (mDocShell) { + nsCOMPtr shell; + mDocShell->GetPresShell(getter_AddRefs(shell)); + return shell.get(); + } + return nsnull; + } + + // text + enum TextAlign { + TEXT_ALIGN_START, + TEXT_ALIGN_END, + TEXT_ALIGN_LEFT, + TEXT_ALIGN_RIGHT, + TEXT_ALIGN_CENTER + }; + + enum TextBaseline { + TEXT_BASELINE_TOP, + TEXT_BASELINE_HANGING, + TEXT_BASELINE_MIDDLE, + TEXT_BASELINE_ALPHABETIC, + TEXT_BASELINE_IDEOGRAPHIC, + TEXT_BASELINE_BOTTOM + }; + + gfxFontGroup *GetCurrentFontStyle(); + + enum TextDrawOperation { + TEXT_DRAW_OPERATION_FILL, + TEXT_DRAW_OPERATION_STROKE, + TEXT_DRAW_OPERATION_MEASURE + }; + + /* + * Implementation of the fillText, strokeText, and measure functions with + * the operation abstracted to a flag. + */ + nsresult DrawOrMeasureText(const nsAString& text, + float x, + float y, + float maxWidth, + TextDrawOperation op, + float* aWidth); + + // state stack handling + class ContextState { + public: + ContextState() : textAlign(TEXT_ALIGN_START), + textBaseline(TEXT_BASELINE_ALPHABETIC), + lineWidth(1.0f), + miterLimit(10.0f), + globalAlpha(1.0f), + shadowBlur(0.0), + op(OP_OVER), + fillRule(FILL_WINDING), + lineCap(CAP_BUTT), + lineJoin(JOIN_MITER_OR_BEVEL), + imageSmoothingEnabled(PR_TRUE) + { } + + ContextState(const ContextState& other) + : fontGroup(other.fontGroup), + font(other.font), + textAlign(other.textAlign), + textBaseline(other.textBaseline), + shadowColor(other.shadowColor), + transform(other.transform), + shadowOffset(other.shadowOffset), + lineWidth(other.lineWidth), + miterLimit(other.miterLimit), + globalAlpha(other.globalAlpha), + shadowBlur(other.shadowBlur), + op(other.op), + fillRule(FILL_WINDING), + lineCap(other.lineCap), + lineJoin(other.lineJoin), + imageSmoothingEnabled(other.imageSmoothingEnabled) + { + for (int i = 0; i < STYLE_MAX; i++) { + colorStyles[i] = other.colorStyles[i]; + gradientStyles[i] = other.gradientStyles[i]; + patternStyles[i] = other.patternStyles[i]; + } + } + + void SetColorStyle(Style whichStyle, nscolor color) { + colorStyles[whichStyle] = color; + gradientStyles[whichStyle] = nsnull; + patternStyles[whichStyle] = nsnull; + } + + void SetPatternStyle(Style whichStyle, nsCanvasPatternAzure* pat) { + gradientStyles[whichStyle] = nsnull; + patternStyles[whichStyle] = pat; + } + + void SetGradientStyle(Style whichStyle, nsCanvasGradientAzure* grad) { + gradientStyles[whichStyle] = grad; + patternStyles[whichStyle] = nsnull; + } + + /** + * returns true iff the given style is a solid color. + */ + PRBool StyleIsColor(Style whichStyle) const + { + return !(patternStyles[whichStyle] || + gradientStyles[whichStyle]); + } + + + std::vector > clipsPushed; + + nsRefPtr fontGroup; + nsRefPtr gradientStyles[STYLE_MAX]; + nsRefPtr patternStyles[STYLE_MAX]; + + nsString font; + TextAlign textAlign; + TextBaseline textBaseline; + + nscolor colorStyles[STYLE_MAX]; + nscolor shadowColor; + + Matrix transform; + Point shadowOffset; + Float lineWidth; + Float miterLimit; + Float globalAlpha; + Float shadowBlur; + + CompositionOp op; + FillRule fillRule; + CapStyle lineCap; + JoinStyle lineJoin; + + PRPackedBool imageSmoothingEnabled; + }; + + class GeneralPattern + { + public: + GeneralPattern() : mPattern(nsnull) {} + ~GeneralPattern() + { + if (mPattern) { + mPattern->~Pattern(); + } + } + + Pattern& ForStyle(nsCanvasRenderingContext2DAzure *aCtx, + Style aStyle, + DrawTarget *aRT) + { + // This should only be called once or the mPattern destructor will + // not be executed. + NS_ASSERTION(!mPattern, "ForStyle() should only be called once on GeneralPattern!"); + + const nsCanvasRenderingContext2DAzure::ContextState &state = aCtx->CurrentState(); + + if (state.StyleIsColor(aStyle)) { + mPattern = new (mColorPattern.addr()) ColorPattern(Color::FromABGR(state.colorStyles[aStyle])); + } else if (state.gradientStyles[aStyle] && + state.gradientStyles[aStyle]->GetType() == nsCanvasGradientAzure::LINEAR) { + nsCanvasLinearGradientAzure *gradient = + static_cast(state.gradientStyles[aStyle].get()); + + mPattern = new (mLinearGradientPattern.addr()) + LinearGradientPattern(gradient->mBegin, gradient->mEnd, + gradient->GetGradientStopsForTarget(aRT)); + } else if (state.gradientStyles[aStyle] && + state.gradientStyles[aStyle]->GetType() == nsCanvasGradientAzure::RADIAL) { + nsCanvasRadialGradientAzure *gradient = + static_cast(state.gradientStyles[aStyle].get()); + + mPattern = new (mRadialGradientPattern.addr()) + RadialGradientPattern(gradient->mCenter, gradient->mOrigin, gradient->mRadius, + gradient->GetGradientStopsForTarget(aRT)); + } else if (state.patternStyles[aStyle]) { + if (aCtx->mCanvasElement) { + CanvasUtils::DoDrawImageSecurityCheck(aCtx->HTMLCanvasElement(), + state.patternStyles[aStyle]->mPrincipal, + state.patternStyles[aStyle]->mForceWriteOnly); + } + + ExtendMode mode; + if (state.patternStyles[aStyle]->mRepeat == nsCanvasPatternAzure::NOREPEAT) { + mode = EXTEND_CLAMP; + } else { + mode = EXTEND_WRAP; + } + mPattern = new (mSurfacePattern.addr()) + SurfacePattern(state.patternStyles[aStyle]->mSurface, mode); + } + + return *mPattern; + } + + union { + AlignedStorage2 mColorPattern; + AlignedStorage2 mLinearGradientPattern; + AlignedStorage2 mRadialGradientPattern; + AlignedStorage2 mSurfacePattern; + }; + Pattern *mPattern; + }; + + /* This is an RAII based class that can be used as a drawtarget for + * operations that need a shadow drawn. It will automatically provide a + * temporary target when needed, and if so blend it back with a shadow. + */ + class AdjustedTarget + { + public: + AdjustedTarget(nsCanvasRenderingContext2DAzure *ctx, + const mgfx::Rect *aBounds = nsnull) + : mCtx(nsnull) + { + if (!ctx->NeedToDrawShadow()) { + mTarget = ctx->mTarget; + return; + } + mCtx = ctx; + + const ContextState &state = mCtx->CurrentState(); + + mSigma = state.shadowBlur / 2.0f; + + if (mSigma > SIGMA_MAX) { + mSigma = SIGMA_MAX; + } + + Matrix transform = mCtx->mTarget->GetTransform(); + if (!aBounds) { + mTempSize = IntSize(ctx->mWidth, ctx->mHeight); + + // We need to enlarge an possibly offset our temporary surface + // so that things outside of the canvas may cast shadows. + if (state.shadowOffset.x > 0) { + mTempSize.width += state.shadowOffset.x; + mSurfOffset.x = -state.shadowOffset.x; + transform._31 += state.shadowOffset.x; + } else { + mTempSize.width -= state.shadowOffset.x; + } + if (state.shadowOffset.y > 0) { + mTempSize.height += state.shadowOffset.y; + mSurfOffset.y = -state.shadowOffset.y; + transform._32 += state.shadowOffset.y; + } else { + mTempSize.height -= state.shadowOffset.y; + } + + if (mSigma > 0) { + float blurRadius = mSigma * 3; + mSurfOffset.x -= blurRadius; + mSurfOffset.y -= blurRadius; + mTempSize.width += blurRadius; + mTempSize.height += blurRadius; + transform._31 += blurRadius; + transform._32 += blurRadius; + } + } // XXX - Implement aBounds path! See bug 666452. + + mTarget = + mCtx->mTarget->CreateSimilarDrawTarget(mTempSize, + FORMAT_B8G8R8A8); + + mTarget->SetTransform(transform); + + if (!mTarget) { + // XXX - Deal with the situation where our temp size is too big to + // fit in a texture. + mTarget = ctx->mTarget; + mCtx = nsnull; + } + } + + ~AdjustedTarget() + { + if (!mCtx) { + return; + } + + RefPtr snapshot = mTarget->Snapshot(); + + mCtx->mTarget->DrawSurfaceWithShadow(snapshot, mSurfOffset, + Color::FromABGR(mCtx->CurrentState().shadowColor), + mCtx->CurrentState().shadowOffset, mSigma); + } + + DrawTarget* operator->() + { + return mTarget; + } + + private: + RefPtr mTarget; + nsCanvasRenderingContext2DAzure *mCtx; + Float mSigma; + IntSize mTempSize; + Point mSurfOffset; + }; + + nsAutoTArray mStyleStack; + + inline ContextState& CurrentState() { + return mStyleStack[mStyleStack.Length() - 1]; + } + + // other helpers + void GetAppUnitsValues(PRUint32 *perDevPixel, PRUint32 *perCSSPixel) { + // If we don't have a canvas element, we just return something generic. + PRUint32 devPixel = 60; + PRUint32 cssPixel = 60; + + nsIPresShell *ps = GetPresShell(); + nsPresContext *pc; + + if (!ps) goto FINISH; + pc = ps->GetPresContext(); + if (!pc) goto FINISH; + devPixel = pc->AppUnitsPerDevPixel(); + cssPixel = pc->AppUnitsPerCSSPixel(); + + FINISH: + if (perDevPixel) + *perDevPixel = devPixel; + if (perCSSPixel) + *perCSSPixel = cssPixel; + } + + friend struct nsCanvasBidiProcessorAzure; +}; + +NS_IMPL_CYCLE_COLLECTING_ADDREF(nsCanvasRenderingContext2DAzure) +NS_IMPL_CYCLE_COLLECTING_RELEASE(nsCanvasRenderingContext2DAzure) + +NS_IMPL_CYCLE_COLLECTION_CLASS(nsCanvasRenderingContext2DAzure) +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsCanvasRenderingContext2DAzure) + NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mCanvasElement) +NS_IMPL_CYCLE_COLLECTION_UNLINK_END +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsCanvasRenderingContext2DAzure) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mCanvasElement) +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END + +// XXX +// DOMCI_DATA(CanvasRenderingContext2D, nsCanvasRenderingContext2DAzure) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsCanvasRenderingContext2DAzure) + NS_INTERFACE_MAP_ENTRY(nsIDOMCanvasRenderingContext2D) + NS_INTERFACE_MAP_ENTRY(nsICanvasRenderingContextInternal) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMCanvasRenderingContext2D) + NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(CanvasRenderingContext2D) +NS_INTERFACE_MAP_END + +/** + ** CanvasRenderingContext2D impl + **/ + + +// Initialize our static variables. +PRUint32 nsCanvasRenderingContext2DAzure::sNumLivingContexts = 0; +PRUint8 (*nsCanvasRenderingContext2DAzure::sUnpremultiplyTable)[256] = nsnull; +PRUint8 (*nsCanvasRenderingContext2DAzure::sPremultiplyTable)[256] = nsnull; + +nsresult +NS_NewCanvasRenderingContext2DAzure(nsIDOMCanvasRenderingContext2D** aResult) +{ +#ifndef XP_WIN + return NS_ERROR_NOT_AVAILABLE; +#else + + if (gfxWindowsPlatform::GetPlatform()->GetRenderMode() != + gfxWindowsPlatform::RENDER_DIRECT2D || + !gfxWindowsPlatform::GetPlatform()->DWriteEnabled()) { + return NS_ERROR_NOT_AVAILABLE; + } + + nsRefPtr ctx = new nsCanvasRenderingContext2DAzure(); + if (!ctx) + return NS_ERROR_OUT_OF_MEMORY; + + *aResult = ctx.forget().get(); + return NS_OK; +#endif +} + +nsCanvasRenderingContext2DAzure::nsCanvasRenderingContext2DAzure() + : mValid(PR_FALSE), mZero(PR_FALSE), mOpaque(PR_FALSE), mResetLayer(PR_TRUE) + , mIPC(PR_FALSE) + , mCanvasElement(nsnull) + , mIsEntireFrameInvalid(PR_FALSE) + , mPredictManyRedrawCalls(PR_FALSE), mPathTransformWillUpdate(false) + , mInvalidateCount(0) +{ + sNumLivingContexts++; +} + +nsCanvasRenderingContext2DAzure::~nsCanvasRenderingContext2DAzure() +{ + Reset(); + sNumLivingContexts--; + if (!sNumLivingContexts) { + delete[] sUnpremultiplyTable; + delete[] sPremultiplyTable; + sUnpremultiplyTable = nsnull; + sPremultiplyTable = nsnull; + } +} + +nsresult +nsCanvasRenderingContext2DAzure::Reset() +{ + if (mCanvasElement) { + HTMLCanvasElement()->InvalidateCanvas(); + } + + // only do this for non-docshell created contexts, + // since those are the ones that we created a surface for + if (mValid && !mDocShell) { + gCanvasAzureMemoryUsed -= mWidth * mHeight * 4; + } + + mTarget = nsnull; + mValid = PR_FALSE; + mIsEntireFrameInvalid = PR_FALSE; + mPredictManyRedrawCalls = PR_FALSE; + return NS_OK; +} + +nsresult +nsCanvasRenderingContext2DAzure::SetStyleFromStringOrInterface(const nsAString& aStr, + nsISupports *aInterface, + Style aWhichStyle) +{ + nsresult rv; + nscolor color; + + if (!aStr.IsVoid()) { + nsIDocument* document = mCanvasElement ? + HTMLCanvasElement()->GetOwnerDoc() : nsnull; + + // Pass the CSS Loader object to the parser, to allow parser error + // reports to include the outer window ID. + nsCSSParser parser(document ? document->CSSLoader() : nsnull); + rv = parser.ParseColorString(aStr, nsnull, 0, &color); + if (NS_FAILED(rv)) { + // Error reporting happens inside the CSS parser + return NS_OK; + } + + CurrentState().SetColorStyle(aWhichStyle, color); + return NS_OK; + } + + if (aInterface) { + nsCOMPtr grad(do_QueryInterface(aInterface)); + if (grad) { + CurrentState().SetGradientStyle(aWhichStyle, grad); + return NS_OK; + } + + nsCOMPtr pattern(do_QueryInterface(aInterface)); + if (pattern) { + CurrentState().SetPatternStyle(aWhichStyle, pattern); + return NS_OK; + } + } + + nsContentUtils::ReportToConsole( + nsContentUtils::eDOM_PROPERTIES, + "UnexpectedCanvasVariantStyle", + nsnull, 0, + nsnull, + EmptyString(), 0, 0, + nsIScriptError::warningFlag, + "Canvas", + mCanvasElement ? HTMLCanvasElement()->GetOwnerDoc() : nsnull); + + return NS_OK; +} + +nsresult +nsCanvasRenderingContext2DAzure::GetStyleAsStringOrInterface(nsAString& aStr, + nsISupports **aInterface, + PRInt32 *aType, + Style aWhichStyle) +{ + const ContextState &state = CurrentState(); + + if (state.patternStyles[aWhichStyle]) { + aStr.SetIsVoid(PR_TRUE); + NS_ADDREF(*aInterface = state.patternStyles[aWhichStyle]); + *aType = CMG_STYLE_PATTERN; + } else if (state.gradientStyles[aWhichStyle]) { + aStr.SetIsVoid(PR_TRUE); + NS_ADDREF(*aInterface = state.gradientStyles[aWhichStyle]); + *aType = CMG_STYLE_GRADIENT; + } else { + StyleColorToString(state.colorStyles[aWhichStyle], aStr); + *aInterface = nsnull; + *aType = CMG_STYLE_STRING; + } + + return NS_OK; +} + +void +nsCanvasRenderingContext2DAzure::StyleColorToString(const nscolor& aColor, nsAString& aStr) +{ + // We can't reuse the normal CSS color stringification code, + // because the spec calls for a different algorithm for canvas. + if (NS_GET_A(aColor) == 255) { + CopyUTF8toUTF16(nsPrintfCString(100, "#%02x%02x%02x", + NS_GET_R(aColor), + NS_GET_G(aColor), + NS_GET_B(aColor)), + aStr); + } else { + CopyUTF8toUTF16(nsPrintfCString(100, "rgba(%d, %d, %d, ", + NS_GET_R(aColor), + NS_GET_G(aColor), + NS_GET_B(aColor)), + aStr); + aStr.AppendFloat(nsStyleUtil::ColorComponentToFloat(NS_GET_A(aColor))); + aStr.Append(')'); + } +} + +nsresult +nsCanvasRenderingContext2DAzure::Redraw() +{ + if (mIsEntireFrameInvalid) { + return NS_OK; + } + + mIsEntireFrameInvalid = PR_TRUE; + + if (!mCanvasElement) { + NS_ASSERTION(mDocShell, "Redraw with no canvas element or docshell!"); + return NS_OK; + } + + nsSVGEffects::InvalidateDirectRenderingObservers(HTMLCanvasElement()); + + HTMLCanvasElement()->InvalidateCanvasContent(nsnull); + + return NS_OK; +} + +void +nsCanvasRenderingContext2DAzure::Redraw(const mgfx::Rect &r) +{ + ++mInvalidateCount; + + if (mIsEntireFrameInvalid) { + return; + } + + if (mPredictManyRedrawCalls || + mInvalidateCount > kCanvasMaxInvalidateCount) { + Redraw(); + return; + } + + if (!mCanvasElement) { + NS_ASSERTION(mDocShell, "Redraw with no canvas element or docshell!"); + return; + } + + nsSVGEffects::InvalidateDirectRenderingObservers(HTMLCanvasElement()); + + gfxRect tmpR = GFXRect(r); + HTMLCanvasElement()->InvalidateCanvasContent(&tmpR); + + return; +} + +nsresult +nsCanvasRenderingContext2DAzure::RedrawUser(const gfxRect& r) +{ + if (mIsEntireFrameInvalid) { + ++mInvalidateCount; + return NS_OK; + } + + mgfx::Rect newr = + mTarget->GetTransform().TransformBounds(ToRect(r)); + Redraw(newr); + + return NS_OK; +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::SetDimensions(PRInt32 width, PRInt32 height) +{ + RefPtr target; + + // Zero sized surfaces cause issues, so just go with 1x1. + if (height == 0 || width == 0) { + mZero = PR_TRUE; + height = 1; + width = 1; + } + + // Check that the dimensions are sane + IntSize size(width, height); + if (size.width <= 0xFFFF && size.height <= 0xFFFF && + size.width >= 0 && size.height >= 0) { + SurfaceFormat format = GetSurfaceFormat(); + nsCOMPtr content = + do_QueryInterface(static_cast(mCanvasElement)); + nsIDocument* ownerDoc = nsnull; + if (content) { + ownerDoc = content->GetOwnerDoc(); + } + + nsRefPtr layerManager = nsnull; + + if (ownerDoc) { + layerManager = + nsContentUtils::PersistentLayerManagerForDocument(ownerDoc); + } + + if (layerManager) { + target = layerManager->CreateDrawTarget(size, format); + } else { + target = Factory::CreateDrawTarget(BACKEND_DIRECT2D, size, format); + } + } + + if (target) { + if (gCanvasAzureMemoryReporter == nsnull) { + gCanvasAzureMemoryReporter = new NS_MEMORY_REPORTER_NAME(CanvasAzureMemory); + NS_RegisterMemoryReporter(gCanvasAzureMemoryReporter); + } + + gCanvasAzureMemoryUsed += width * height * 4; + JS_updateMallocCounter(nsContentUtils::GetCurrentJSContext(), width * height * 4); + } + + return InitializeWithTarget(target, width, height); +} + +nsresult +nsCanvasRenderingContext2DAzure::InitializeWithTarget(DrawTarget *target, PRInt32 width, PRInt32 height) +{ + Reset(); + + NS_ASSERTION(mCanvasElement, "Must have a canvas element!"); + mDocShell = nsnull; + + mWidth = width; + mHeight = height; + + mTarget = target; + + mResetLayer = PR_TRUE; + + /* Create dummy surfaces here - target can be null when a canvas was created + * that is too large to support. + */ + if (!target) + { + mTarget = Factory::CreateDrawTarget(BACKEND_DIRECT2D, IntSize(1, 1), FORMAT_B8G8R8A8); + } else { + mValid = PR_TRUE; + } + + // set up the initial canvas defaults + mStyleStack.Clear(); + mPathBuilder = nsnull; + mPath = nsnull; + mDSPathBuilder = nsnull; + + ContextState *state = mStyleStack.AppendElement(); + state->globalAlpha = 1.0; + + state->colorStyles[STYLE_FILL] = NS_RGB(0,0,0); + state->colorStyles[STYLE_STROKE] = NS_RGB(0,0,0); + state->shadowColor = NS_RGBA(0,0,0,0); + + mTarget->ClearRect(mgfx::Rect(Point(0, 0), Size(mWidth, mHeight))); + + // always force a redraw, because if the surface dimensions were reset + // then the surface became cleared, and we need to redraw everything. + Redraw(); + + return mValid ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::SetIsOpaque(PRBool isOpaque) +{ + if (isOpaque == mOpaque) + return NS_OK; + + mOpaque = isOpaque; + + if (mValid) { + /* If we've already been created, let SetDimensions take care of + * recreating our surface + */ + return SetDimensions(mWidth, mHeight); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::SetIsIPC(PRBool isIPC) +{ + if (isIPC == mIPC) + return NS_OK; + + mIPC = isIPC; + + if (mValid) { + /* If we've already been created, let SetDimensions take care of + * recreating our surface + */ + return SetDimensions(mWidth, mHeight); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::Render(gfxContext *ctx, gfxPattern::GraphicsFilter aFilter) +{ + nsresult rv = NS_OK; + + if (!mValid || !mTarget) { + return NS_ERROR_FAILURE; + } + + nsRefPtr surface; + + if (NS_FAILED(GetThebesSurface(getter_AddRefs(surface)))) { + return NS_ERROR_FAILURE; + } + + nsRefPtr pat = new gfxPattern(surface); + + pat->SetFilter(aFilter); + pat->SetExtend(gfxPattern::EXTEND_PAD); + + gfxContext::GraphicsOperator op = ctx->CurrentOperator(); + if (mOpaque) + ctx->SetOperator(gfxContext::OPERATOR_SOURCE); + + // XXX I don't want to use PixelSnapped here, but layout doesn't guarantee + // pixel alignment for this stuff! + ctx->NewPath(); + ctx->PixelSnappedRectangleAndSetPattern(gfxRect(0, 0, mWidth, mHeight), pat); + ctx->Fill(); + + if (mOpaque) + ctx->SetOperator(op); + + return rv; +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::GetInputStream(const char *aMimeType, + const PRUnichar *aEncoderOptions, + nsIInputStream **aStream) +{ + if (!mValid || !mTarget) { + return NS_ERROR_FAILURE; + } + + nsRefPtr surface; + + if (NS_FAILED(GetThebesSurface(getter_AddRefs(surface)))) { + return NS_ERROR_FAILURE; + } + + nsresult rv; + const char encoderPrefix[] = "@mozilla.org/image/encoder;2?type="; + nsAutoArrayPtr conid(new (std::nothrow) char[strlen(encoderPrefix) + strlen(aMimeType) + 1]); + + if (!conid) { + return NS_ERROR_OUT_OF_MEMORY; + } + + strcpy(conid, encoderPrefix); + strcat(conid, aMimeType); + + nsCOMPtr encoder = do_CreateInstance(conid); + if (!encoder) { + return NS_ERROR_FAILURE; + } + + nsAutoArrayPtr imageBuffer(new (std::nothrow) PRUint8[mWidth * mHeight * 4]); + if (!imageBuffer) { + return NS_ERROR_OUT_OF_MEMORY; + } + + nsRefPtr imgsurf = + new gfxImageSurface(imageBuffer.get(), + gfxIntSize(mWidth, mHeight), + mWidth * 4, + gfxASurface::ImageFormatARGB32); + + if (!imgsurf || imgsurf->CairoStatus()) { + return NS_ERROR_FAILURE; + } + + nsRefPtr ctx = new gfxContext(imgsurf); + + if (!ctx || ctx->HasError()) { + return NS_ERROR_FAILURE; + } + + ctx->SetOperator(gfxContext::OPERATOR_SOURCE); + ctx->SetSource(surface, gfxPoint(0, 0)); + ctx->Paint(); + + rv = encoder->InitFromData(imageBuffer.get(), + mWidth * mHeight * 4, mWidth, mHeight, mWidth * 4, + imgIEncoder::INPUT_FORMAT_HOSTARGB, + nsDependentString(aEncoderOptions)); + NS_ENSURE_SUCCESS(rv, rv); + + return CallQueryInterface(encoder, aStream); +} + +SurfaceFormat +nsCanvasRenderingContext2DAzure::GetSurfaceFormat() const +{ + return mOpaque ? FORMAT_B8G8R8X8 : FORMAT_B8G8R8A8; +} + +// +// nsCanvasRenderingContext2DAzure impl +// + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::SetCanvasElement(nsHTMLCanvasElement* aCanvasElement) +{ + mCanvasElement = aCanvasElement; + + return NS_OK; +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::GetCanvas(nsIDOMHTMLCanvasElement **canvas) +{ + NS_IF_ADDREF(*canvas = mCanvasElement); + + return NS_OK; +} + +// +// state +// + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::Save() +{ + mStyleStack[mStyleStack.Length() - 1].transform = mTarget->GetTransform(); + mStyleStack.SetCapacity(mStyleStack.Length() + 1); + mStyleStack.AppendElement(CurrentState()); + return NS_OK; +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::Restore() +{ + if (mStyleStack.Length() - 1 == 0) + return NS_OK; + + for (PRUint32 i = 0; i < CurrentState().clipsPushed.size(); i++) { + mTarget->PopClip(); + } + + mStyleStack.RemoveElementAt(mStyleStack.Length() - 1); + + TransformWillUpdate(); + + mTarget->SetTransform(CurrentState().transform); + + return NS_OK; +} + +// +// transformations +// + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::Scale(float x, float y) +{ + if (!FloatValidate(x,y)) + return NS_OK; + + TransformWillUpdate(); + + Matrix newMatrix = mTarget->GetTransform(); + mTarget->SetTransform(newMatrix.Scale(x, y)); + return NS_OK; +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::Rotate(float angle) +{ + if (!FloatValidate(angle)) + return NS_OK; + + TransformWillUpdate(); + + Matrix rotation = Matrix::Rotation(angle); + mTarget->SetTransform(rotation * mTarget->GetTransform()); + return NS_OK; +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::Translate(float x, float y) +{ + if (!FloatValidate(x,y)) { + return NS_OK; + } + + TransformWillUpdate(); + + Matrix newMatrix = mTarget->GetTransform(); + mTarget->SetTransform(newMatrix.Translate(x, y)); + return NS_OK; +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::Transform(float m11, float m12, float m21, float m22, float dx, float dy) +{ + if (!FloatValidate(m11,m12,m21,m22,dx,dy)) { + return NS_OK; + } + + TransformWillUpdate(); + + Matrix matrix(m11, m12, m21, m22, dx, dy); + mTarget->SetTransform(matrix * mTarget->GetTransform()); + return NS_OK; +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::SetTransform(float m11, float m12, float m21, float m22, float dx, float dy) +{ + if (!FloatValidate(m11,m12,m21,m22,dx,dy)) { + return NS_OK; + } + + TransformWillUpdate(); + + Matrix matrix(m11, m12, m21, m22, dx, dy); + mTarget->SetTransform(matrix); + + return NS_OK; +} + +// +// colors +// + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::SetGlobalAlpha(float aGlobalAlpha) +{ + if (!FloatValidate(aGlobalAlpha) || aGlobalAlpha < 0.0 || aGlobalAlpha > 1.0) { + return NS_OK; + } + + CurrentState().globalAlpha = aGlobalAlpha; + + return NS_OK; +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::GetGlobalAlpha(float *aGlobalAlpha) +{ + *aGlobalAlpha = CurrentState().globalAlpha; + return NS_OK; +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::SetStrokeStyle(nsIVariant *aValue) +{ + if (!aValue) + return NS_ERROR_FAILURE; + + nsString str; + + nsresult rv; + PRUint16 vtype; + rv = aValue->GetDataType(&vtype); + NS_ENSURE_SUCCESS(rv, rv); + + if (vtype == nsIDataType::VTYPE_INTERFACE || + vtype == nsIDataType::VTYPE_INTERFACE_IS) + { + nsIID *iid; + nsCOMPtr sup; + rv = aValue->GetAsInterface(&iid, getter_AddRefs(sup)); + NS_ENSURE_SUCCESS(rv, rv); + if (iid) { + NS_Free(iid); + } + + str.SetIsVoid(PR_TRUE); + return SetStrokeStyle_multi(str, sup); + } + + rv = aValue->GetAsAString(str); + NS_ENSURE_SUCCESS(rv, rv); + + return SetStrokeStyle_multi(str, nsnull); +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::GetStrokeStyle(nsIVariant **aResult) +{ + nsCOMPtr wv = do_CreateInstance(NS_VARIANT_CONTRACTID); + + nsCOMPtr sup; + nsString str; + PRInt32 t; + nsresult rv = GetStrokeStyle_multi(str, getter_AddRefs(sup), &t); + NS_ENSURE_SUCCESS(rv, rv); + + if (t == CMG_STYLE_STRING) { + rv = wv->SetAsAString(str); + } else if (t == CMG_STYLE_PATTERN) { + rv = wv->SetAsInterface(NS_GET_IID(nsIDOMCanvasPattern), + sup); + } else if (t == CMG_STYLE_GRADIENT) { + rv = wv->SetAsInterface(NS_GET_IID(nsIDOMCanvasGradient), + sup); + } else { + NS_ERROR("Unknown type from GetStroke/FillStyle_multi!"); + return NS_ERROR_FAILURE; + } + NS_ENSURE_SUCCESS(rv, rv); + + NS_IF_ADDREF(*aResult = wv.get()); + return NS_OK; +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::SetFillStyle(nsIVariant *aValue) +{ + if (!aValue) { + return NS_ERROR_FAILURE; + } + + nsString str; + nsresult rv; + PRUint16 vtype; + rv = aValue->GetDataType(&vtype); + NS_ENSURE_SUCCESS(rv, rv); + + if (vtype == nsIDataType::VTYPE_INTERFACE || + vtype == nsIDataType::VTYPE_INTERFACE_IS) + { + nsIID *iid; + nsCOMPtr sup; + rv = aValue->GetAsInterface(&iid, getter_AddRefs(sup)); + NS_ENSURE_SUCCESS(rv, rv); + + str.SetIsVoid(PR_TRUE); + return SetFillStyle_multi(str, sup); + } + + rv = aValue->GetAsAString(str); + NS_ENSURE_SUCCESS(rv, rv); + + return SetFillStyle_multi(str, nsnull); +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::GetFillStyle(nsIVariant **aResult) +{ + nsCOMPtr wv = do_CreateInstance(NS_VARIANT_CONTRACTID); + + nsCOMPtr sup; + nsString str; + PRInt32 t; + nsresult rv = GetFillStyle_multi(str, getter_AddRefs(sup), &t); + NS_ENSURE_SUCCESS(rv, rv); + + if (t == CMG_STYLE_STRING) { + rv = wv->SetAsAString(str); + } else if (t == CMG_STYLE_PATTERN) { + rv = wv->SetAsInterface(NS_GET_IID(nsIDOMCanvasPattern), + sup); + } else if (t == CMG_STYLE_GRADIENT) { + rv = wv->SetAsInterface(NS_GET_IID(nsIDOMCanvasGradient), + sup); + } else { + NS_ERROR("Unknown type from GetStroke/FillStyle_multi!"); + return NS_ERROR_FAILURE; + } + NS_ENSURE_SUCCESS(rv, rv); + + NS_IF_ADDREF(*aResult = wv.get()); + return NS_OK; +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::SetMozFillRule(const nsAString& aString) +{ + FillRule rule; + + if (aString.EqualsLiteral("evenodd")) + rule = FILL_EVEN_ODD; + else if (aString.EqualsLiteral("nonzero")) + rule = FILL_WINDING; + else + return NS_OK; + + CurrentState().fillRule = rule; + return NS_OK; +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::GetMozFillRule(nsAString& aString) +{ + switch (CurrentState().fillRule) { + case FILL_WINDING: + aString.AssignLiteral("nonzero"); break; + case FILL_EVEN_ODD: + aString.AssignLiteral("evenodd"); break; + default: + return NS_ERROR_FAILURE; + } + + return NS_OK; +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::SetStrokeStyle_multi(const nsAString& aStr, nsISupports *aInterface) +{ + return SetStyleFromStringOrInterface(aStr, aInterface, STYLE_STROKE); +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::GetStrokeStyle_multi(nsAString& aStr, nsISupports **aInterface, PRInt32 *aType) +{ + return GetStyleAsStringOrInterface(aStr, aInterface, aType, STYLE_STROKE); +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::SetFillStyle_multi(const nsAString& aStr, nsISupports *aInterface) +{ + return SetStyleFromStringOrInterface(aStr, aInterface, STYLE_FILL); +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::GetFillStyle_multi(nsAString& aStr, nsISupports **aInterface, PRInt32 *aType) +{ + return GetStyleAsStringOrInterface(aStr, aInterface, aType, STYLE_FILL); +} + +// +// gradients and patterns +// +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::CreateLinearGradient(float x0, float y0, float x1, float y1, + nsIDOMCanvasGradient **_retval) +{ + if (!FloatValidate(x0,y0,x1,y1)) { + return NS_ERROR_DOM_NOT_SUPPORTED_ERR; + } + + nsRefPtr grad = + new nsCanvasLinearGradientAzure(Point(x0, y0), Point(x1, y1)); + + *_retval = grad.forget().get(); + return NS_OK; +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::CreateRadialGradient(float x0, float y0, float r0, + float x1, float y1, float r1, + nsIDOMCanvasGradient **_retval) +{ + if (!FloatValidate(x0,y0,r0,x1,y1,r1)) { + return NS_ERROR_DOM_NOT_SUPPORTED_ERR; + } + + if (r0 < 0.0 || r1 < 0.0) { + return NS_ERROR_DOM_INDEX_SIZE_ERR; + } + + nsRefPtr grad = + new nsCanvasRadialGradientAzure(Point(x0, y0), r0, Point(x1, y1), r1); + + *_retval = grad.forget().get(); + return NS_OK; +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::CreatePattern(nsIDOMHTMLElement *image, + const nsAString& repeat, + nsIDOMCanvasPattern **_retval) +{ + if (!image) { + return NS_ERROR_DOM_TYPE_MISMATCH_ERR; + } + + nsCanvasPatternAzure::RepeatMode repeatMode = + nsCanvasPatternAzure::NOREPEAT; + + if (repeat.IsEmpty() || repeat.EqualsLiteral("repeat")) { + repeatMode = nsCanvasPatternAzure::REPEAT; + } else if (repeat.EqualsLiteral("repeat-x")) { + repeatMode = nsCanvasPatternAzure::REPEATX; + } else if (repeat.EqualsLiteral("repeat-y")) { + repeatMode = nsCanvasPatternAzure::REPEATY; + } else if (repeat.EqualsLiteral("no-repeat")) { + repeatMode = nsCanvasPatternAzure::NOREPEAT; + } else { + return NS_ERROR_DOM_SYNTAX_ERR; + } + + nsCOMPtr content = do_QueryInterface(image); + nsHTMLCanvasElement* canvas = nsHTMLCanvasElement::FromContent(content); + + if (canvas) { + nsIntSize size = canvas->GetSize(); + if (size.width == 0 || size.height == 0) { + return NS_ERROR_DOM_INVALID_STATE_ERR; + } + } + + // Special case for Canvas, which could be an Azure canvas! + nsCOMPtr node = do_QueryInterface(image); + if (canvas && node) { + if (canvas->CountContexts() == 1) { + nsICanvasRenderingContextInternal *srcCanvas = canvas->GetContextAtIndex(0); + + // This might not be an Azure canvas! + if (srcCanvas) { + RefPtr srcSurf = srcCanvas->GetSurfaceSnapshot(); + + nsRefPtr pat = + new nsCanvasPatternAzure(srcSurf, repeatMode, node->NodePrincipal(), canvas->IsWriteOnly()); + + *_retval = pat.forget().get(); + return NS_OK; + } + } + } + + // The canvas spec says that createPattern should use the first frame + // of animated images + nsLayoutUtils::SurfaceFromElementResult res = + nsLayoutUtils::SurfaceFromElement(image, nsLayoutUtils::SFE_WANT_FIRST_FRAME | + nsLayoutUtils::SFE_WANT_NEW_SURFACE); + + if (!res.mSurface) { + return NS_ERROR_NOT_AVAILABLE; + } + + // Ignore nsnull cairo surfaces! See bug 666312. + if (!res.mSurface->CairoSurface()) { + return NS_OK; + } + + RefPtr srcSurf = + gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(mTarget, res.mSurface); + + nsRefPtr pat = + new nsCanvasPatternAzure(srcSurf, repeatMode, res.mPrincipal, res.mIsWriteOnly); + + *_retval = pat.forget().get(); + return NS_OK; +} + +// +// shadows +// +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::SetShadowOffsetX(float x) +{ + if (!FloatValidate(x)) { + return NS_OK; + } + + CurrentState().shadowOffset.x = x; + return NS_OK; +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::GetShadowOffsetX(float *x) +{ + *x = static_cast(CurrentState().shadowOffset.x); + return NS_OK; +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::SetShadowOffsetY(float y) +{ + if (!FloatValidate(y)) { + return NS_OK; + } + + CurrentState().shadowOffset.y = y; + return NS_OK; +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::GetShadowOffsetY(float *y) +{ + *y = static_cast(CurrentState().shadowOffset.y); + return NS_OK; +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::SetShadowBlur(float blur) +{ + if (!FloatValidate(blur) || blur < 0.0) { + return NS_OK; + } + + CurrentState().shadowBlur = blur; + return NS_OK; +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::GetShadowBlur(float *blur) +{ + *blur = CurrentState().shadowBlur; + return NS_OK; +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::SetShadowColor(const nsAString& colorstr) +{ + nsIDocument* document = mCanvasElement ? + HTMLCanvasElement()->GetOwnerDoc() : nsnull; + + // Pass the CSS Loader object to the parser, to allow parser error reports + // to include the outer window ID. + nsCSSParser parser(document ? document->CSSLoader() : nsnull); + nscolor color; + nsresult rv = parser.ParseColorString(colorstr, nsnull, 0, &color); + if (NS_FAILED(rv)) { + // Error reporting happens inside the CSS parser + return NS_OK; + } + CurrentState().shadowColor = color; + + return NS_OK; +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::GetShadowColor(nsAString& color) +{ + StyleColorToString(CurrentState().shadowColor, color); + + return NS_OK; +} + +// +// rects +// + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::ClearRect(float x, float y, float w, float h) +{ + if (!FloatValidate(x,y,w,h)) { + return NS_OK; + } + + mTarget->ClearRect(mgfx::Rect(x, y, w, h)); + + return RedrawUser(gfxRect(x, y, w, h)); +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::FillRect(float x, float y, float w, float h) +{ + if (!FloatValidate(x,y,w,h)) { + return NS_OK; + } + + bool doDrawShadow = NeedToDrawShadow(); + + const ContextState &state = CurrentState(); + + if (state.patternStyles[STYLE_FILL]) { + nsCanvasPatternAzure::RepeatMode repeat = + state.patternStyles[STYLE_FILL]->mRepeat; + // In the FillRect case repeat modes are easy to deal with. + bool limitx = repeat == nsCanvasPatternAzure::NOREPEAT || repeat == nsCanvasPatternAzure::REPEATY; + bool limity = repeat == nsCanvasPatternAzure::NOREPEAT || repeat == nsCanvasPatternAzure::REPEATX; + + IntSize patternSize = + state.patternStyles[STYLE_FILL]->mSurface->GetSize(); + + // We always need to execute painting for non-over operators, even if + // we end up with w/h = 0. + if (limitx) { + if (x < 0) { + w += x; + if (w < 0) { + w = 0; + } + + x = 0; + } + if (x + w > patternSize.width) { + w = patternSize.width - x; + if (w < 0) { + w = 0; + } + } + } + if (limity) { + if (y < 0) { + h += y; + if (h < 0) { + h = 0; + } + + y = 0; + } + if (y + h > patternSize.height) { + h = patternSize.height - y; + if (h < 0) { + h = 0; + } + } + } + } + + AdjustedTarget(this)->FillRect(mgfx::Rect(x, y, w, h), + GeneralPattern().ForStyle(this, STYLE_FILL, mTarget), + DrawOptions(state.globalAlpha, state.op)); + + return RedrawUser(gfxRect(x, y, w, h)); +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::StrokeRect(float x, float y, float w, float h) +{ + if (!FloatValidate(x,y,w,h)) { + return NS_OK; + } + + const ContextState &state = CurrentState(); + + if (!w && !h) { + return NS_OK; + } else if (!h) { + CapStyle cap = CAP_BUTT; + if (state.lineJoin == JOIN_ROUND) { + cap = CAP_ROUND; + } + AdjustedTarget(this)-> + StrokeLine(Point(x, y), Point(x + w, y), + GeneralPattern().ForStyle(this, STYLE_STROKE, mTarget), + StrokeOptions(state.lineWidth, state.lineJoin, + cap, state.miterLimit), + DrawOptions(state.globalAlpha, state.op)); + return NS_OK; + } else if (!w) { + CapStyle cap = CAP_BUTT; + if (state.lineJoin == JOIN_ROUND) { + cap = CAP_ROUND; + } + AdjustedTarget(this)-> + StrokeLine(Point(x, y), Point(x, y + h), + GeneralPattern().ForStyle(this, STYLE_STROKE, mTarget), + StrokeOptions(state.lineWidth, state.lineJoin, + cap, state.miterLimit), + DrawOptions(state.globalAlpha, state.op)); + return NS_OK; + } + + AdjustedTarget(this)-> + StrokeRect(mgfx::Rect(x, y, w, h), + GeneralPattern().ForStyle(this, STYLE_STROKE, mTarget), + StrokeOptions(state.lineWidth, state.lineJoin, + state.lineCap, state.miterLimit), + DrawOptions(state.globalAlpha, state.op)); + + return Redraw(); +} + +// +// path bits +// + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::BeginPath() +{ + mPath = nsnull; + mPathBuilder = nsnull; + mDSPathBuilder = nsnull; + mPathTransformWillUpdate = false; + return NS_OK; +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::ClosePath() +{ + EnsureWritablePath(); + + if (mPathBuilder) { + mPathBuilder->Close(); + } else { + mDSPathBuilder->Close(); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::Fill() +{ + EnsureUserSpacePath(); + + if (!mPath) { + return NS_OK; + } + + AdjustedTarget(this)-> + Fill(mPath, GeneralPattern().ForStyle(this, STYLE_FILL, mTarget), + DrawOptions(CurrentState().globalAlpha, CurrentState().op)); + + return Redraw(); +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::Stroke() +{ + EnsureUserSpacePath(); + + if (!mPath) { + return NS_OK; + } + + const ContextState &state = CurrentState(); + + AdjustedTarget(this)-> + Stroke(mPath, GeneralPattern().ForStyle(this, STYLE_STROKE, mTarget), + StrokeOptions(state.lineWidth, state.lineJoin, + state.lineCap, state.miterLimit), + DrawOptions(state.globalAlpha, state.op)); + + return Redraw(); +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::Clip() +{ + EnsureUserSpacePath(); + + if (!mPath) { + return NS_OK; + } + + mTarget->PushClip(mPath); + CurrentState().clipsPushed.push_back(mPath); + + return NS_OK; +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::MoveTo(float x, float y) +{ + if (!FloatValidate(x,y)) + return NS_OK; + + EnsureWritablePath(); + + if (mPathBuilder) { + mPathBuilder->MoveTo(Point(x, y)); + } else { + mDSPathBuilder->MoveTo(mTarget->GetTransform() * Point(x, y)); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::LineTo(float x, float y) +{ + if (!FloatValidate(x,y)) + return NS_OK; + + EnsureWritablePath(); + + if (mPathBuilder) { + mPathBuilder->LineTo(Point(x, y)); + } else { + mDSPathBuilder->LineTo(mTarget->GetTransform() * Point(x, y)); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::QuadraticCurveTo(float cpx, float cpy, float x, float y) +{ + if (!FloatValidate(cpx, cpy, x, y)) { + return NS_OK; + } + + EnsureWritablePath(); + + if (mPathBuilder) { + mPathBuilder->QuadraticBezierTo(Point(cpx, cpy), Point(x, y)); + } else { + Matrix transform = mTarget->GetTransform(); + mDSPathBuilder->QuadraticBezierTo(transform * Point(cpx, cpy), transform * Point(cpx, cpy)); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::BezierCurveTo(float cp1x, float cp1y, + float cp2x, float cp2y, + float x, float y) +{ + if (!FloatValidate(cp1x, cp1y, cp2x, cp2y, x, y)) { + return NS_OK; + } + + EnsureWritablePath(); + + if (mPathBuilder) { + mPathBuilder->BezierTo(Point(cp1x, cp1y), Point(cp2x, cp2y), Point(x, y)); + } else { + Matrix transform = mTarget->GetTransform(); + mDSPathBuilder->BezierTo(transform * Point(cp1x, cp1y), + transform * Point(cp2x, cp2y), + transform * Point(x, y)); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::ArcTo(float x1, float y1, float x2, float y2, float radius) +{ + if (!FloatValidate(x1, y1, x2, y2, radius)) { + return NS_OK; + } + + if (radius < 0) { + return NS_ERROR_DOM_INDEX_SIZE_ERR; + } + + EnsureWritablePath(); + + // Current point in user space! + Point p0; + if (mPathBuilder) { + p0 = mPathBuilder->CurrentPoint(); + } else { + Matrix invTransform = mTarget->GetTransform(); + if (!invTransform.Invert()) { + return NS_OK; + } + + p0 = invTransform * mDSPathBuilder->CurrentPoint(); + } + + Point p1(x1, y1); + Point p2(x2, y2); + + // Execute these calculations in double precision to avoid cumulative + // rounding errors. + double dir, a2, b2, c2, cosx, sinx, d, anx, any, + bnx, bny, x3, y3, x4, y4, cx, cy, angle0, angle1; + bool anticlockwise; + + if (p0 == p1 || p1 == p2 || radius == 0) { + LineTo(p1.x, p1.y); + return NS_OK; + } + + // Check for colinearity + dir = (p2.x - p1.x) * (p0.y - p1.y) + (p2.y - p1.y) * (p1.x - p0.x); + if (dir == 0) { + LineTo(p1.x, p1.y); + return NS_OK; + } + + + // XXX - Math for this code was already available from the non-azure code + // and would be well tested. Perhaps converting to bezier directly might + // be more efficient longer run. + a2 = (p0.x-x1)*(p0.x-x1) + (p0.y-y1)*(p0.y-y1); + b2 = (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2); + c2 = (p0.x-x2)*(p0.x-x2) + (p0.y-y2)*(p0.y-y2); + cosx = (a2+b2-c2)/(2*sqrt(a2*b2)); + + sinx = sqrt(1 - cosx*cosx); + d = radius / ((1 - cosx) / sinx); + + anx = (x1-p0.x) / sqrt(a2); + any = (y1-p0.y) / sqrt(a2); + bnx = (x1-x2) / sqrt(b2); + bny = (y1-y2) / sqrt(b2); + x3 = x1 - anx*d; + y3 = y1 - any*d; + x4 = x1 - bnx*d; + y4 = y1 - bny*d; + anticlockwise = (dir < 0); + cx = x3 + any*radius*(anticlockwise ? 1 : -1); + cy = y3 - anx*radius*(anticlockwise ? 1 : -1); + angle0 = atan2((y3-cy), (x3-cx)); + angle1 = atan2((y4-cy), (x4-cx)); + + + LineTo(x3, y3); + + Arc(cx, cy, radius, angle0, angle1, anticlockwise); + return NS_OK; +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::Arc(float x, float y, + float r, + float startAngle, float endAngle, + PRBool ccw) +{ + if (!FloatValidate(x, y, r, startAngle, endAngle)) { + return NS_OK; + } + + if (r < 0.0) + return NS_ERROR_DOM_INDEX_SIZE_ERR; + + EnsureWritablePath(); + + // We convert to Bezier curve here, since we need to be able to write in + // device space, but a transformed arc is no longer representable by an arc. + + Point startPoint(x + cos(startAngle) * r, y + sin(startAngle) * r); + + if (mPathBuilder) { + mPathBuilder->LineTo(startPoint); + } else { + mDSPathBuilder->LineTo(mTarget->GetTransform() * startPoint); + } + + // Clockwise we always sweep from the smaller to the larger angle, ccw + // it's vice versa. + if (!ccw && (endAngle < startAngle)) { + Float correction = ceil((startAngle - endAngle) / (2.0f * M_PI)); + endAngle += correction * 2.0f * M_PI; + } else if (ccw && (startAngle < endAngle)) { + Float correction = ceil((endAngle - startAngle) / (2.0f * M_PI)); + startAngle += correction * 2.0f * M_PI; + } + + // Sweeping more than 2 * pi is a full circle. + if (!ccw && (endAngle - startAngle > 2 * M_PI)) { + endAngle = startAngle + 2.0f * M_PI; + } else if (ccw && (startAngle - endAngle > 2.0f * M_PI)) { + endAngle = startAngle - 2.0f * M_PI; + } + + // Calculate the total arc we're going to sweep. + Float arcSweepLeft = abs(endAngle - startAngle); + // Calculate the amount of curves needed, 1 per quarter circle. + Float curves = ceil(arcSweepLeft / (M_PI / 2.0f)); + + Float sweepDirection = ccw ? -1.0f : 1.0f; + + Float currentStartAngle = startAngle; + + while (arcSweepLeft > 0) { + // We guarantee here the current point is the start point of the next + // curve segment. + Float currentEndAngle; + + if (arcSweepLeft > M_PI / 2.0f) { + currentEndAngle = currentStartAngle + M_PI / 2.0f * sweepDirection; + } else { + currentEndAngle = currentStartAngle + arcSweepLeft * sweepDirection; + } + + Point currentStartPoint(x + cos(currentStartAngle) * r, + y + sin(currentStartAngle) * r); + Point currentEndPoint(x + cos(currentEndAngle) * r, + y + sin(currentEndAngle) * r); + + // Calculate kappa constant for partial curve. The sign of angle in the + // tangent will actually ensure this is negative for a counter clockwise + // sweep, so changing signs later isn't needed. + Float kappa = (4.0f / 3.0f) * tan((currentEndAngle - currentStartAngle) / 4.0f) * r; + + Point tangentStart(-sin(currentStartAngle), cos(currentStartAngle)); + Point cp1 = currentStartPoint; + cp1 += tangentStart * kappa; + + Point revTangentEnd(sin(currentEndAngle), -cos(currentEndAngle)); + Point cp2 = currentEndPoint; + cp2 += revTangentEnd * kappa; + + if (mPathBuilder) { + mPathBuilder->BezierTo(cp1, cp2, currentEndPoint); + } else { + mDSPathBuilder->BezierTo(mTarget->GetTransform() * cp1, + mTarget->GetTransform() * cp2, + mTarget->GetTransform() * currentEndPoint); + } + + arcSweepLeft -= M_PI / 2.0f; + currentStartAngle = currentEndAngle; + } + + + return NS_OK; +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::Rect(float x, float y, float w, float h) +{ + if (!FloatValidate(x, y, w, h)) { + return NS_OK; + } + + EnsureWritablePath(); + + if (mPathBuilder) { + mPathBuilder->MoveTo(Point(x, y)); + mPathBuilder->LineTo(Point(x + w, y)); + mPathBuilder->LineTo(Point(x + w, y + h)); + mPathBuilder->LineTo(Point(x, y + h)); + mPathBuilder->Close(); + } else { + mDSPathBuilder->MoveTo(mTarget->GetTransform() * Point(x, y)); + mDSPathBuilder->LineTo(mTarget->GetTransform() * Point(x + w, y)); + mDSPathBuilder->LineTo(mTarget->GetTransform() * Point(x + w, y + h)); + mDSPathBuilder->LineTo(mTarget->GetTransform() * Point(x, y + h)); + mDSPathBuilder->Close(); + } + + return NS_OK; +} + +void +nsCanvasRenderingContext2DAzure::EnsureWritablePath() +{ + if (mDSPathBuilder) { + return; + } + + FillRule fillRule = CurrentState().fillRule; + + if (mPathBuilder) { + if (mPathTransformWillUpdate) { + mPath = mPathBuilder->Finish(); + mDSPathBuilder = + mPath->TransformedCopyToBuilder(mPathToDS, fillRule); + mPath = nsnull; + mPathBuilder = nsnull; + } + return; + } + + if (!mPath) { + mPathBuilder = mTarget->CreatePathBuilder(fillRule); + } else if (!mPathTransformWillUpdate) { + mPathBuilder = mPath->CopyToBuilder(fillRule); + } else { + mDSPathBuilder = + mPath->TransformedCopyToBuilder(mPathToDS, fillRule); + } +} + +void +nsCanvasRenderingContext2DAzure::EnsureUserSpacePath() +{ + FillRule fillRule = CurrentState().fillRule; + + if (!mPath && !mPathBuilder && !mDSPathBuilder) { + mPathBuilder = mTarget->CreatePathBuilder(fillRule); + } + + if (mPathBuilder) { + mPath = mPathBuilder->Finish(); + mPathBuilder = nsnull; + } + + if (mPath && mPathTransformWillUpdate) { + mDSPathBuilder = + mPath->TransformedCopyToBuilder(mPathToDS, fillRule); + mPath = nsnull; + mPathTransformWillUpdate = false; + } + + if (mDSPathBuilder) { + RefPtr dsPath; + dsPath = mDSPathBuilder->Finish(); + mDSPathBuilder = nsnull; + + Matrix inverse = mTarget->GetTransform(); + if (!inverse.Invert()) { + return; + } + + mPathBuilder = + dsPath->TransformedCopyToBuilder(inverse, fillRule); + mPath = mPathBuilder->Finish(); + mPathBuilder = nsnull; + } + + if (mPath && mPath->GetFillRule() != fillRule) { + mPathBuilder = mPath->CopyToBuilder(fillRule); + mPath = mPathBuilder->Finish(); + } +} + +void +nsCanvasRenderingContext2DAzure::TransformWillUpdate() +{ + // Store the matrix that would transform the current path to device + // space. + if (mPath || mPathBuilder) { + if (!mPathTransformWillUpdate) { + // If the transform has already been updated, but a device space builder + // has not been created yet mPathToDS contains the right transform to + // transform the current mPath into device space. + // We should leave it alone. + mPathToDS = mTarget->GetTransform(); + } + mPathTransformWillUpdate = true; + } +} + +// +// text +// + +/** + * Helper function for SetFont that creates a style rule for the given font. + * @param aFont The CSS font string + * @param aNode The canvas element + * @param aResult Pointer in which to place the new style rule. + * @remark Assumes all pointer arguments are non-null. + */ +static nsresult +CreateFontStyleRule(const nsAString& aFont, + nsINode* aNode, + StyleRule** aResult) +{ + nsRefPtr rule; + PRBool changed; + + nsIPrincipal* principal = aNode->NodePrincipal(); + nsIDocument* document = aNode->GetOwnerDoc(); + + nsIURI* docURL = document->GetDocumentURI(); + nsIURI* baseURL = document->GetDocBaseURI(); + + // Pass the CSS Loader object to the parser, to allow parser error reports + // to include the outer window ID. + nsCSSParser parser(document->CSSLoader()); + + nsresult rv = parser.ParseStyleAttribute(EmptyString(), docURL, baseURL, + principal, getter_AddRefs(rule)); + if (NS_FAILED(rv)) { + return rv; + } + + rv = parser.ParseProperty(eCSSProperty_font, aFont, docURL, baseURL, + principal, rule->GetDeclaration(), &changed, + PR_FALSE); + if (NS_FAILED(rv)) + return rv; + + rv = parser.ParseProperty(eCSSProperty_line_height, + NS_LITERAL_STRING("normal"), docURL, baseURL, + principal, rule->GetDeclaration(), &changed, + PR_FALSE); + if (NS_FAILED(rv)) { + return rv; + } + + rule->RuleMatched(); + + rule.forget(aResult); + return NS_OK; +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::SetFont(const nsAString& font) +{ + nsresult rv; + + /* + * If font is defined with relative units (e.g. ems) and the parent + * style context changes in between calls, setting the font to the + * same value as previous could result in a different computed value, + * so we cannot have the optimization where we check if the new font + * string is equal to the old one. + */ + + nsCOMPtr content = do_QueryInterface(mCanvasElement); + if (!content && !mDocShell) { + NS_WARNING("Canvas element must be an nsIContent and non-null or a docshell must be provided"); + return NS_ERROR_FAILURE; + } + + nsIPresShell* presShell = GetPresShell(); + if (!presShell) { + return NS_ERROR_FAILURE; + } + nsIDocument* document = presShell->GetDocument(); + + nsCOMArray rules; + + nsRefPtr rule; + rv = CreateFontStyleRule(font, document, getter_AddRefs(rule)); + + if (NS_FAILED(rv)) { + return rv; + } + + css::Declaration *declaration = rule->GetDeclaration(); + // The easiest way to see whether we got a syntax error or whether + // we got 'inherit' or 'initial' is to look at font-size-adjust, + // which the shorthand resets to either 'none' or + // '-moz-system-font'. + // We know the declaration is not !important, so we can use + // GetNormalBlock(). + const nsCSSValue *fsaVal = + declaration->GetNormalBlock()->ValueFor(eCSSProperty_font_size_adjust); + if (!fsaVal || (fsaVal->GetUnit() != eCSSUnit_None && + fsaVal->GetUnit() != eCSSUnit_System_Font)) { + // We got an all-property value or a syntax error. The spec says + // this value must be ignored. + return NS_OK; + } + + rules.AppendObject(rule); + + nsStyleSet* styleSet = presShell->StyleSet(); + + // have to get a parent style context for inherit-like relative + // values (2em, bolder, etc.) + nsRefPtr parentContext; + + if (content && content->IsInDoc()) { + // inherit from the canvas element + parentContext = nsComputedDOMStyle::GetStyleContextForElement( + content->AsElement(), + nsnull, + presShell); + } else { + // otherwise inherit from default (10px sans-serif) + nsRefPtr parentRule; + rv = CreateFontStyleRule(NS_LITERAL_STRING("10px sans-serif"), + document, + getter_AddRefs(parentRule)); + + if (NS_FAILED(rv)) { + return rv; + } + + nsCOMArray parentRules; + parentRules.AppendObject(parentRule); + parentContext = styleSet->ResolveStyleForRules(nsnull, parentRules); + } + + if (!parentContext) { + return NS_ERROR_FAILURE; + } + + nsRefPtr sc = + styleSet->ResolveStyleForRules(parentContext, rules); + if (!sc) { + return NS_ERROR_FAILURE; + } + + const nsStyleFont* fontStyle = sc->GetStyleFont(); + + NS_ASSERTION(fontStyle, "Could not obtain font style"); + + nsIAtom* language = sc->GetStyleVisibility()->mLanguage; + if (!language) { + language = presShell->GetPresContext()->GetLanguageFromCharset(); + } + + // use CSS pixels instead of dev pixels to avoid being affected by page zoom + const PRUint32 aupcp = nsPresContext::AppUnitsPerCSSPixel(); + // un-zoom the font size to avoid being affected by text-only zoom + const nscoord fontSize = nsStyleFont::UnZoomText(parentContext->PresContext(), fontStyle->mFont.size); + + PRBool printerFont = (presShell->GetPresContext()->Type() == nsPresContext::eContext_PrintPreview || + presShell->GetPresContext()->Type() == nsPresContext::eContext_Print); + + gfxFontStyle style(fontStyle->mFont.style, + fontStyle->mFont.weight, + fontStyle->mFont.stretch, + NSAppUnitsToFloatPixels(fontSize, float(aupcp)), + language, + fontStyle->mFont.sizeAdjust, + fontStyle->mFont.systemFont, + printerFont, + fontStyle->mFont.featureSettings, + fontStyle->mFont.languageOverride); + + CurrentState().fontGroup = + gfxPlatform::GetPlatform()->CreateFontGroup(fontStyle->mFont.name, + &style, + presShell->GetPresContext()->GetUserFontSet()); + NS_ASSERTION(CurrentState().fontGroup, "Could not get font group"); + + // The font getter is required to be reserialized based on what we + // parsed (including having line-height removed). (Older drafts of + // the spec required font sizes be converted to pixels, but that no + // longer seems to be required.) + declaration->GetValue(eCSSProperty_font, CurrentState().font); + + return NS_OK; +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::GetFont(nsAString& font) +{ + /* will initilize the value if not set, else does nothing */ + GetCurrentFontStyle(); + + font = CurrentState().font; + return NS_OK; +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::SetTextAlign(const nsAString& ta) +{ + if (ta.EqualsLiteral("start")) + CurrentState().textAlign = TEXT_ALIGN_START; + else if (ta.EqualsLiteral("end")) + CurrentState().textAlign = TEXT_ALIGN_END; + else if (ta.EqualsLiteral("left")) + CurrentState().textAlign = TEXT_ALIGN_LEFT; + else if (ta.EqualsLiteral("right")) + CurrentState().textAlign = TEXT_ALIGN_RIGHT; + else if (ta.EqualsLiteral("center")) + CurrentState().textAlign = TEXT_ALIGN_CENTER; + // spec says to not throw error for invalid arg, but do it anyway + else + return NS_ERROR_INVALID_ARG; + + return NS_OK; +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::GetTextAlign(nsAString& ta) +{ + switch (CurrentState().textAlign) + { + case TEXT_ALIGN_START: + ta.AssignLiteral("start"); + break; + case TEXT_ALIGN_END: + ta.AssignLiteral("end"); + break; + case TEXT_ALIGN_LEFT: + ta.AssignLiteral("left"); + break; + case TEXT_ALIGN_RIGHT: + ta.AssignLiteral("right"); + break; + case TEXT_ALIGN_CENTER: + ta.AssignLiteral("center"); + break; + default: + NS_ERROR("textAlign holds invalid value"); + return NS_ERROR_FAILURE; + } + + return NS_OK; +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::SetTextBaseline(const nsAString& tb) +{ + if (tb.EqualsLiteral("top")) + CurrentState().textBaseline = TEXT_BASELINE_TOP; + else if (tb.EqualsLiteral("hanging")) + CurrentState().textBaseline = TEXT_BASELINE_HANGING; + else if (tb.EqualsLiteral("middle")) + CurrentState().textBaseline = TEXT_BASELINE_MIDDLE; + else if (tb.EqualsLiteral("alphabetic")) + CurrentState().textBaseline = TEXT_BASELINE_ALPHABETIC; + else if (tb.EqualsLiteral("ideographic")) + CurrentState().textBaseline = TEXT_BASELINE_IDEOGRAPHIC; + else if (tb.EqualsLiteral("bottom")) + CurrentState().textBaseline = TEXT_BASELINE_BOTTOM; + // spec says to not throw error for invalid arg, but do it anyway + else + return NS_ERROR_INVALID_ARG; + + return NS_OK; +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::GetTextBaseline(nsAString& tb) +{ + switch (CurrentState().textBaseline) + { + case TEXT_BASELINE_TOP: + tb.AssignLiteral("top"); + break; + case TEXT_BASELINE_HANGING: + tb.AssignLiteral("hanging"); + break; + case TEXT_BASELINE_MIDDLE: + tb.AssignLiteral("middle"); + break; + case TEXT_BASELINE_ALPHABETIC: + tb.AssignLiteral("alphabetic"); + break; + case TEXT_BASELINE_IDEOGRAPHIC: + tb.AssignLiteral("ideographic"); + break; + case TEXT_BASELINE_BOTTOM: + tb.AssignLiteral("bottom"); + break; + default: + NS_ERROR("textBaseline holds invalid value"); + return NS_ERROR_FAILURE; + } + + return NS_OK; +} + +/* + * Helper function that replaces the whitespace characters in a string + * with U+0020 SPACE. The whitespace characters are defined as U+0020 SPACE, + * U+0009 CHARACTER TABULATION (tab), U+000A LINE FEED (LF), U+000B LINE + * TABULATION, U+000C FORM FEED (FF), and U+000D CARRIAGE RETURN (CR). + * @param str The string whose whitespace characters to replace. + */ +static inline void +TextReplaceWhitespaceCharacters(nsAutoString& str) +{ + str.ReplaceChar("\x09\x0A\x0B\x0C\x0D", PRUnichar(' ')); +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::FillText(const nsAString& text, float x, float y, float maxWidth) +{ + return DrawOrMeasureText(text, x, y, maxWidth, TEXT_DRAW_OPERATION_FILL, nsnull); +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::StrokeText(const nsAString& text, float x, float y, float maxWidth) +{ + return DrawOrMeasureText(text, x, y, maxWidth, TEXT_DRAW_OPERATION_STROKE, nsnull); +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::MeasureText(const nsAString& rawText, + nsIDOMTextMetrics** _retval) +{ + float width; + + nsresult rv = DrawOrMeasureText(rawText, 0, 0, 0, TEXT_DRAW_OPERATION_MEASURE, &width); + + if (NS_FAILED(rv)) { + return rv; + } + + nsRefPtr textMetrics = new nsTextMetricsAzure(width); + if (!textMetrics.get()) { + return NS_ERROR_OUT_OF_MEMORY; + } + + *_retval = textMetrics.forget().get(); + + return NS_OK; +} + +/** + * Used for nsBidiPresUtils::ProcessText + */ +struct NS_STACK_CLASS nsCanvasBidiProcessorAzure : public nsBidiPresUtils::BidiProcessor +{ + virtual void SetText(const PRUnichar* text, PRInt32 length, nsBidiDirection direction) + { + mTextRun = gfxTextRunCache::MakeTextRun(text, + length, + mFontgrp, + mThebes, + mAppUnitsPerDevPixel, + direction==NSBIDI_RTL ? gfxTextRunFactory::TEXT_IS_RTL : 0); + } + + virtual nscoord GetWidth() + { + gfxTextRun::Metrics textRunMetrics = mTextRun->MeasureText(0, + mTextRun->GetLength(), + mDoMeasureBoundingBox ? + gfxFont::TIGHT_INK_EXTENTS : + gfxFont::LOOSE_INK_EXTENTS, + mThebes, + nsnull); + + // this only measures the height; the total width is gotten from the + // the return value of ProcessText. + if (mDoMeasureBoundingBox) { + textRunMetrics.mBoundingBox.Scale(1.0 / mAppUnitsPerDevPixel); + mBoundingBox = mBoundingBox.Union(textRunMetrics.mBoundingBox); + } + + return static_cast(textRunMetrics.mAdvanceWidth/gfxFloat(mAppUnitsPerDevPixel)); + } + + virtual void DrawText(nscoord xOffset, nscoord width) + { + gfxPoint point = mPt; + point.x += xOffset * mAppUnitsPerDevPixel; + + // offset is given in terms of left side of string + if (mTextRun->IsRightToLeft()) { + // Bug 581092 - don't use rounded pixel width to advance to + // right-hand end of run, because this will cause different + // glyph positioning for LTR vs RTL drawing of the same + // glyph string on OS X and DWrite where textrun widths may + // involve fractional pixels. + gfxTextRun::Metrics textRunMetrics = + mTextRun->MeasureText(0, + mTextRun->GetLength(), + mDoMeasureBoundingBox ? + gfxFont::TIGHT_INK_EXTENTS : + gfxFont::LOOSE_INK_EXTENTS, + mThebes, + nsnull); + point.x += textRunMetrics.mAdvanceWidth; + // old code was: + // point.x += width * mAppUnitsPerDevPixel; + // TODO: restore this if/when we move to fractional coords + // throughout the text layout process + } + + PRUint32 numRuns; + const gfxTextRun::GlyphRun *runs = mTextRun->GetGlyphRuns(&numRuns); + const PRUint32 appUnitsPerDevUnit = mAppUnitsPerDevPixel; + const double devUnitsPerAppUnit = 1.0/double(appUnitsPerDevUnit); + Point baselineOrigin = + Point(point.x * devUnitsPerAppUnit, point.y * devUnitsPerAppUnit); + + for (int c = 0; c < numRuns; c++) { + gfxFont *font = runs[c].mFont; + PRUint32 endRun = 0; + if (c + 1 < numRuns) { + endRun = runs[c + 1].mCharacterOffset; + } else { + endRun = mTextRun->GetLength(); + } + + const gfxTextRun::CompressedGlyph *glyphs = mTextRun->GetCharacterGlyphs(); + + RefPtr scaledFont = + gfxPlatform::GetPlatform()->GetScaledFontForFont(font); + + GlyphBuffer buffer; + + std::vector glyphBuf; + + float advanceSum = 0; + + for (int i = runs[c].mCharacterOffset; i < endRun; i++) { + Glyph newGlyph; + if (glyphs[i].IsSimpleGlyph()) { + newGlyph.mIndex = glyphs[i].GetSimpleGlyph(); + if (mTextRun->IsRightToLeft()) { + newGlyph.mPosition.x = baselineOrigin.x - advanceSum - + glyphs[i].GetSimpleAdvance() * devUnitsPerAppUnit; + } else { + newGlyph.mPosition.x = baselineOrigin.x + advanceSum; + } + newGlyph.mPosition.y = baselineOrigin.y; + advanceSum += glyphs[i].GetSimpleAdvance() * devUnitsPerAppUnit; + glyphBuf.push_back(newGlyph); + continue; + } + + if (!glyphs[i].GetGlyphCount()) { + continue; + } + + gfxTextRun::DetailedGlyph *detailedGlyphs = + mTextRun->GetDetailedGlyphs(i); + + for (int c = 0; c < glyphs[i].GetGlyphCount(); c++) { + newGlyph.mIndex = detailedGlyphs[c].mGlyphID; + if (mTextRun->IsRightToLeft()) { + newGlyph.mPosition.x = baselineOrigin.x + detailedGlyphs[c].mXOffset * devUnitsPerAppUnit - + advanceSum - detailedGlyphs[c].mAdvance * devUnitsPerAppUnit; + } else { + newGlyph.mPosition.x = baselineOrigin.x + detailedGlyphs[c].mXOffset * devUnitsPerAppUnit + advanceSum; + } + newGlyph.mPosition.y = baselineOrigin.y + detailedGlyphs[c].mYOffset * devUnitsPerAppUnit; + glyphBuf.push_back(newGlyph); + advanceSum += detailedGlyphs[c].mAdvance * devUnitsPerAppUnit; + } + } + + buffer.mGlyphs = &glyphBuf.front(); + buffer.mNumGlyphs = glyphBuf.size(); + + if (mOp == nsCanvasRenderingContext2DAzure::TEXT_DRAW_OPERATION_FILL) { + nsCanvasRenderingContext2DAzure::AdjustedTarget(mCtx)-> + FillGlyphs(scaledFont, buffer, + nsCanvasRenderingContext2DAzure::GeneralPattern(). + ForStyle(mCtx, nsCanvasRenderingContext2DAzure::STYLE_FILL, mCtx->mTarget), + DrawOptions(mState->globalAlpha, mState->op)); + } else if (mOp == nsCanvasRenderingContext2DAzure::TEXT_DRAW_OPERATION_STROKE) { + RefPtr path = scaledFont->GetPathForGlyphs(buffer, mCtx->mTarget); + + Matrix oldTransform = mCtx->mTarget->GetTransform(); + + nsCanvasRenderingContext2DAzure::AdjustedTarget(mCtx)-> + Stroke(path, nsCanvasRenderingContext2DAzure::GeneralPattern(). + ForStyle(mCtx, nsCanvasRenderingContext2DAzure::STYLE_STROKE, mCtx->mTarget), + StrokeOptions(mCtx->CurrentState().lineWidth, mCtx->CurrentState().lineJoin, + mCtx->CurrentState().lineCap, mCtx->CurrentState().miterLimit), + DrawOptions(mState->globalAlpha, mState->op)); + + } + } + } + + // current text run + gfxTextRunCache::AutoTextRun mTextRun; + + // pointer to a screen reference context used to measure text and such + nsRefPtr mThebes; + + // Pointer to the draw target we should fill our text to + nsCanvasRenderingContext2DAzure *mCtx; + + // position of the left side of the string, alphabetic baseline + gfxPoint mPt; + + // current font + gfxFontGroup* mFontgrp; + + // dev pixel conversion factor + PRUint32 mAppUnitsPerDevPixel; + + // operation (fill or stroke) + nsCanvasRenderingContext2DAzure::TextDrawOperation mOp; + + // context state + nsCanvasRenderingContext2DAzure::ContextState *mState; + + // union of bounding boxes of all runs, needed for shadows + gfxRect mBoundingBox; + + // true iff the bounding box should be measured + PRBool mDoMeasureBoundingBox; +}; + +nsresult +nsCanvasRenderingContext2DAzure::DrawOrMeasureText(const nsAString& aRawText, + float aX, + float aY, + float aMaxWidth, + TextDrawOperation aOp, + float* aWidth) +{ + nsresult rv; + + if (!FloatValidate(aX, aY, aMaxWidth)) + return NS_ERROR_DOM_SYNTAX_ERR; + + // spec isn't clear on what should happen if aMaxWidth <= 0, so + // treat it as an invalid argument + // technically, 0 should be an invalid value as well, but 0 is the default + // arg, and there is no way to tell if the default was used + if (aMaxWidth < 0) + return NS_ERROR_INVALID_ARG; + + nsCOMPtr content = do_QueryInterface(mCanvasElement); + if (!content && !mDocShell) { + NS_WARNING("Canvas element must be an nsIContent and non-null or a docshell must be provided"); + return NS_ERROR_FAILURE; + } + + nsIPresShell* presShell = GetPresShell(); + if (!presShell) + return NS_ERROR_FAILURE; + + nsIDocument* document = presShell->GetDocument(); + + nsBidiPresUtils* bidiUtils = presShell->GetPresContext()->GetBidiUtils(); + if (!bidiUtils) { + return NS_ERROR_FAILURE; + } + + // replace all the whitespace characters with U+0020 SPACE + nsAutoString textToDraw(aRawText); + TextReplaceWhitespaceCharacters(textToDraw); + + // for now, default to ltr if not in doc + PRBool isRTL = PR_FALSE; + + if (content && content->IsInDoc()) { + // try to find the closest context + nsRefPtr canvasStyle = + nsComputedDOMStyle::GetStyleContextForElement(content->AsElement(), + nsnull, + presShell); + if (!canvasStyle) { + return NS_ERROR_FAILURE; + } + + isRTL = canvasStyle->GetStyleVisibility()->mDirection == + NS_STYLE_DIRECTION_RTL; + } else { + isRTL = GET_BIDI_OPTION_DIRECTION(document->GetBidiOptions()) == IBMBIDI_TEXTDIRECTION_RTL; + } + + const ContextState &state = CurrentState(); + + // This is only needed to know if we can know the drawing bounding box easily. + PRBool doDrawShadow = aOp == TEXT_DRAW_OPERATION_FILL && NeedToDrawShadow(); + + nsCanvasBidiProcessorAzure processor; + + GetAppUnitsValues(&processor.mAppUnitsPerDevPixel, nsnull); + processor.mPt = gfxPoint(aX, aY); + processor.mThebes = + new gfxContext(gfxPlatform::GetPlatform()->ScreenReferenceSurface()); + Matrix matrix = mTarget->GetTransform(); + processor.mThebes->SetMatrix(gfxMatrix(matrix._11, matrix._12, matrix._21, matrix._22, matrix._31, matrix._32)); + processor.mCtx = this; + processor.mOp = aOp; + processor.mBoundingBox = gfxRect(0, 0, 0, 0); + processor.mDoMeasureBoundingBox = doDrawShadow || !mIsEntireFrameInvalid; + processor.mState = &CurrentState(); + + + processor.mFontgrp = GetCurrentFontStyle(); + NS_ASSERTION(processor.mFontgrp, "font group is null"); + + nscoord totalWidth; + + // calls bidi algo twice since it needs the full text width and the + // bounding boxes before rendering anything + rv = bidiUtils->ProcessText(textToDraw.get(), + textToDraw.Length(), + isRTL ? NSBIDI_RTL : NSBIDI_LTR, + presShell->GetPresContext(), + processor, + nsBidiPresUtils::MODE_MEASURE, + nsnull, + 0, + &totalWidth); + if (NS_FAILED(rv)) { + return rv; + } + + if (aWidth) { + *aWidth = static_cast(totalWidth); + } + + // if only measuring, don't need to do any more work + if (aOp==TEXT_DRAW_OPERATION_MEASURE) { + return NS_OK; + } + + // offset pt.x based on text align + gfxFloat anchorX; + + if (state.textAlign == TEXT_ALIGN_CENTER) { + anchorX = .5; + } else if (state.textAlign == TEXT_ALIGN_LEFT || + (!isRTL && state.textAlign == TEXT_ALIGN_START) || + (isRTL && state.textAlign == TEXT_ALIGN_END)) { + anchorX = 0; + } else { + anchorX = 1; + } + + processor.mPt.x -= anchorX * totalWidth; + + // offset pt.y based on text baseline + NS_ASSERTION(processor.mFontgrp->FontListLength()>0, "font group contains no fonts"); + const gfxFont::Metrics& fontMetrics = processor.mFontgrp->GetFontAt(0)->GetMetrics(); + + gfxFloat anchorY; + + switch (state.textBaseline) + { + case TEXT_BASELINE_HANGING: + // fall through; best we can do with the information available + case TEXT_BASELINE_TOP: + anchorY = fontMetrics.emAscent; + break; + break; + case TEXT_BASELINE_MIDDLE: + anchorY = (fontMetrics.emAscent - fontMetrics.emDescent) * .5f; + break; + case TEXT_BASELINE_IDEOGRAPHIC: + // fall through; best we can do with the information available + case TEXT_BASELINE_ALPHABETIC: + anchorY = 0; + break; + case TEXT_BASELINE_BOTTOM: + anchorY = -fontMetrics.emDescent; + break; + default: + NS_ERROR("mTextBaseline holds invalid value"); + return NS_ERROR_FAILURE; + } + + processor.mPt.y += anchorY; + + // correct bounding box to get it to be the correct size/position + processor.mBoundingBox.width = totalWidth; + processor.mBoundingBox.MoveBy(processor.mPt); + + processor.mPt.x *= processor.mAppUnitsPerDevPixel; + processor.mPt.y *= processor.mAppUnitsPerDevPixel; + + Matrix oldTransform = mTarget->GetTransform(); + // if text is over aMaxWidth, then scale the text horizontally such that its + // width is precisely aMaxWidth + if (aMaxWidth > 0 && totalWidth > aMaxWidth) { + Matrix newTransform = oldTransform; + + // Translate so that the anchor point is at 0,0, then scale and then + // translate back. + newTransform.Translate(aX, 0); + newTransform.Scale(aMaxWidth / totalWidth, 1); + newTransform.Translate(-aX, 0); + /* we do this to avoid an ICE in the android compiler */ + Matrix androidCompilerBug = newTransform; + mTarget->SetTransform(androidCompilerBug); + } + + // save the previous bounding box + gfxRect boundingBox = processor.mBoundingBox; + + // don't ever need to measure the bounding box twice + processor.mDoMeasureBoundingBox = PR_FALSE; + + rv = bidiUtils->ProcessText(textToDraw.get(), + textToDraw.Length(), + isRTL ? NSBIDI_RTL : NSBIDI_LTR, + presShell->GetPresContext(), + processor, + nsBidiPresUtils::MODE_DRAW, + nsnull, + 0, + nsnull); + + + mTarget->SetTransform(oldTransform); + + if (aOp == nsCanvasRenderingContext2DAzure::TEXT_DRAW_OPERATION_FILL && !doDrawShadow) + return RedrawUser(boundingBox); + + return Redraw(); +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::SetMozTextStyle(const nsAString& textStyle) +{ + // font and mozTextStyle are the same value + return SetFont(textStyle); +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::GetMozTextStyle(nsAString& textStyle) +{ + // font and mozTextStyle are the same value + return GetFont(textStyle); +} + +gfxFontGroup *nsCanvasRenderingContext2DAzure::GetCurrentFontStyle() +{ + // use lazy initilization for the font group since it's rather expensive + if (!CurrentState().fontGroup) { + nsresult rv = SetFont(kDefaultFontStyle); + if (NS_FAILED(rv)) { + gfxFontStyle style; + style.size = kDefaultFontSize; + CurrentState().fontGroup = + gfxPlatform::GetPlatform()->CreateFontGroup(kDefaultFontName, + &style, + nsnull); + if (CurrentState().fontGroup) { + CurrentState().font = kDefaultFontStyle; + rv = NS_OK; + } else { + rv = NS_ERROR_OUT_OF_MEMORY; + } + } + + NS_ASSERTION(NS_SUCCEEDED(rv), "Default canvas font is invalid"); + } + + return CurrentState().fontGroup; +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::MozDrawText(const nsAString& textToDraw) +{ + return NS_ERROR_DOM_NOT_SUPPORTED_ERR; +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::MozMeasureText(const nsAString& textToMeasure, float *retVal) +{ + return NS_ERROR_DOM_NOT_SUPPORTED_ERR; +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::MozPathText(const nsAString& textToPath) +{ + return NS_ERROR_DOM_NOT_SUPPORTED_ERR; +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::MozTextAlongPath(const nsAString& textToDraw, PRBool stroke) +{ + return NS_ERROR_DOM_NOT_SUPPORTED_ERR; +} + +// +// line caps/joins +// +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::SetLineWidth(float width) +{ + if (!FloatValidate(width) || width <= 0.0) { + return NS_OK; + } + + CurrentState().lineWidth = width; + return NS_OK; +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::GetLineWidth(float *width) +{ + *width = CurrentState().lineWidth; + return NS_OK; +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::SetLineCap(const nsAString& capstyle) +{ + CapStyle cap; + + if (capstyle.EqualsLiteral("butt")) { + cap = CAP_BUTT; + } else if (capstyle.EqualsLiteral("round")) { + cap = CAP_ROUND; + } else if (capstyle.EqualsLiteral("square")) { + cap = CAP_SQUARE; + } else { + // XXX ERRMSG we need to report an error to developers here! (bug 329026) + return NS_OK; + } + + CurrentState().lineCap = cap; + + return NS_OK; +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::GetLineCap(nsAString& capstyle) +{ + switch (CurrentState().lineCap) { + case CAP_BUTT: + capstyle.AssignLiteral("butt"); + break; + case CAP_ROUND: + capstyle.AssignLiteral("round"); + break; + case CAP_SQUARE: + capstyle.AssignLiteral("square"); + break; + default: + return NS_ERROR_FAILURE; + } + + return NS_OK; +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::SetLineJoin(const nsAString& joinstyle) +{ + JoinStyle j; + + if (joinstyle.EqualsLiteral("round")) { + j = JOIN_ROUND; + } else if (joinstyle.EqualsLiteral("bevel")) { + j = JOIN_BEVEL; + } else if (joinstyle.EqualsLiteral("miter")) { + j = JOIN_MITER_OR_BEVEL; + } else { + // XXX ERRMSG we need to report an error to developers here! (bug 329026) + return NS_OK; + } + + CurrentState().lineJoin = j; + + return NS_OK; +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::GetLineJoin(nsAString& joinstyle) +{ + switch (CurrentState().lineJoin) { + case JOIN_ROUND: + joinstyle.AssignLiteral("round"); + break; + case JOIN_BEVEL: + joinstyle.AssignLiteral("bevel"); + break; + case JOIN_MITER_OR_BEVEL: + joinstyle.AssignLiteral("miter"); + break; + default: + return NS_ERROR_FAILURE; + } + + return NS_OK; +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::SetMiterLimit(float miter) +{ + if (!FloatValidate(miter) || miter <= 0.0) + return NS_OK; + + CurrentState().miterLimit = miter; + + return NS_OK; +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::GetMiterLimit(float *miter) +{ + *miter = CurrentState().miterLimit; + return NS_OK; +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::IsPointInPath(float x, float y, PRBool *retVal) +{ + if (!FloatValidate(x,y)) { + *retVal = PR_FALSE; + return NS_OK; + } + + EnsureUserSpacePath(); + + *retVal = PR_FALSE; + + if (mPath) { + *retVal = mPath->ContainsPoint(Point(x, y), mTarget->GetTransform()); + } + + return NS_OK; +} + +// +// image +// + +// drawImage(in HTMLImageElement image, in float dx, in float dy); +// -- render image from 0,0 at dx,dy top-left coords +// drawImage(in HTMLImageElement image, in float dx, in float dy, in float sw, in float sh); +// -- render image from 0,0 at dx,dy top-left coords clipping it to sw,sh +// drawImage(in HTMLImageElement image, in float sx, in float sy, in float sw, in float sh, in float dx, in float dy, in float dw, in float dh); +// -- render the region defined by (sx,sy,sw,wh) in image-local space into the region (dx,dy,dw,dh) on the canvas + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::DrawImage(nsIDOMElement *imgElt, float a1, + float a2, float a3, float a4, float a5, + float a6, float a7, float a8, + PRUint8 optional_argc) +{ + if (!imgElt) { + return NS_ERROR_DOM_TYPE_MISMATCH_ERR; + } + + if (optional_argc == 0) { + if (!FloatValidate(a1, a2)) { + return NS_OK; + } + } else if (optional_argc == 2) { + if (!FloatValidate(a1, a2, a3, a4)) { + return NS_OK; + } + } else if (optional_argc == 6) { + if (!FloatValidate(a1, a2, a3, a4, a5, a6) || !FloatValidate(a7, a8)) { + return NS_OK; + } + } + + double sx,sy,sw,sh; + double dx,dy,dw,dh; + + nsCOMPtr content = do_QueryInterface(imgElt); + nsHTMLCanvasElement* canvas = nsHTMLCanvasElement::FromContent(content); + if (canvas) { + nsIntSize size = canvas->GetSize(); + if (size.width == 0 || size.height == 0) { + return NS_ERROR_DOM_INVALID_STATE_ERR; + } + } + + RefPtr srcSurf; + + gfxIntSize imgSize; + nsRefPtr imgsurf = + CanvasImageCache::Lookup(imgElt, HTMLCanvasElement(), &imgSize); + + if (imgsurf) { + srcSurf = gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(mTarget, imgsurf); + } + + // We know an Azure canvas always has an HTMLCanvasElement! + if (canvas == HTMLCanvasElement()) { + // Self-copy. + srcSurf = mTarget->Snapshot(); + imgSize = gfxIntSize(mWidth, mHeight); + } + + if (!srcSurf) { + // The canvas spec says that drawImage should draw the first frame + // of animated images + PRUint32 sfeFlags = nsLayoutUtils::SFE_WANT_FIRST_FRAME; + nsLayoutUtils::SurfaceFromElementResult res = + nsLayoutUtils::SurfaceFromElement(imgElt, sfeFlags); + + if (!res.mSurface) { + // Spec says to silently do nothing if the element is still loading. + return res.mIsStillLoading ? NS_OK : NS_ERROR_NOT_AVAILABLE; + } + + // Ignore nsnull cairo surfaces! See bug 666312. + if (!res.mSurface->CairoSurface()) { + return NS_OK; + } + + imgsurf = res.mSurface.forget(); + imgSize = res.mSize; + + if (mCanvasElement) { + CanvasUtils::DoDrawImageSecurityCheck(HTMLCanvasElement(), + res.mPrincipal, res.mIsWriteOnly); + } + + if (res.mImageRequest) { + CanvasImageCache::NotifyDrawImage(imgElt, HTMLCanvasElement(), + res.mImageRequest, imgsurf, imgSize); + } + + srcSurf = gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(mTarget, imgsurf); + } + + if (optional_argc == 0) { + dx = a1; + dy = a2; + sx = sy = 0.0; + dw = sw = (double) imgSize.width; + dh = sh = (double) imgSize.height; + } else if (optional_argc == 2) { + dx = a1; + dy = a2; + dw = a3; + dh = a4; + sx = sy = 0.0; + sw = (double) imgSize.width; + sh = (double) imgSize.height; + } else if (optional_argc == 6) { + sx = a1; + sy = a2; + sw = a3; + sh = a4; + dx = a5; + dy = a6; + dw = a7; + dh = a8; + } else { + // XXX ERRMSG we need to report an error to developers here! (bug 329026) + return NS_ERROR_INVALID_ARG; + } + + if (sw == 0.0 || sh == 0.0) { + // zero-sized source -- failure !? + return NS_ERROR_DOM_INDEX_SIZE_ERR; + } + + if (dw == 0.0 || dh == 0.0) { + // not really failure, but nothing to do -- + // and noone likes a divide-by-zero + return NS_OK; + } + + // Handle negative sw, sh, dw and dh by flipping the rectangle over in the + // relevant direction. + if (sw < 0.0) { + sx += sw; + sw = -sw; + } + if (sh < 0.0) { + sy += sh; + sh = -sh; + } + if (dw < 0.0) { + dx += dw; + dw = -dw; + } + if (dh < 0.0) { + dy += dh; + dh = -dh; + } + + // Checking source image boundaries. + if (sx < 0 || sx + sw > (double) imgSize.width || + sy < 0 || sy + sh > (double) imgSize.height) { + return NS_ERROR_DOM_INDEX_SIZE_ERR; + } + + Filter filter; + + if (CurrentState().imageSmoothingEnabled) + filter = mgfx::FILTER_LINEAR; + else + filter = mgfx::FILTER_POINT; + + AdjustedTarget(this)-> + DrawSurface(srcSurf, + mgfx::Rect(dx, dy, dw, dh), + mgfx::Rect(sx, sy, sw, sh), + DrawSurfaceOptions(filter), + DrawOptions(CurrentState().globalAlpha, CurrentState().op)); + + return RedrawUser(gfxRect(dx, dy, dw, dh)); +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::SetGlobalCompositeOperation(const nsAString& op) +{ + CompositionOp comp_op; + +#define CANVAS_OP_TO_GFX_OP(cvsop, op2d) \ + if (op.EqualsLiteral(cvsop)) \ + comp_op = OP_##op2d; + + CANVAS_OP_TO_GFX_OP("copy", SOURCE) + else CANVAS_OP_TO_GFX_OP("source-atop", ATOP) + else CANVAS_OP_TO_GFX_OP("source-in", IN) + else CANVAS_OP_TO_GFX_OP("source-out", OUT) + else CANVAS_OP_TO_GFX_OP("source-over", OVER) + else CANVAS_OP_TO_GFX_OP("destination-in", DEST_IN) + else CANVAS_OP_TO_GFX_OP("destination-out", DEST_OUT) + else CANVAS_OP_TO_GFX_OP("destination-over", DEST_OVER) + else CANVAS_OP_TO_GFX_OP("destination-atop", DEST_ATOP) + else CANVAS_OP_TO_GFX_OP("lighter", ADD) + else CANVAS_OP_TO_GFX_OP("xor", XOR) + // XXX ERRMSG we need to report an error to developers here! (bug 329026) + else return NS_OK; + +#undef CANVAS_OP_TO_GFX_OP + CurrentState().op = comp_op; + return NS_OK; +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::GetGlobalCompositeOperation(nsAString& op) +{ + CompositionOp comp_op = CurrentState().op; + +#define CANVAS_OP_TO_GFX_OP(cvsop, op2d) \ + if (comp_op == OP_##op2d) \ + op.AssignLiteral(cvsop); + + CANVAS_OP_TO_GFX_OP("copy", SOURCE) + else CANVAS_OP_TO_GFX_OP("destination-atop", DEST_ATOP) + else CANVAS_OP_TO_GFX_OP("destination-in", DEST_IN) + else CANVAS_OP_TO_GFX_OP("destination-out", DEST_OUT) + else CANVAS_OP_TO_GFX_OP("destination-over", DEST_OVER) + else CANVAS_OP_TO_GFX_OP("lighter", ADD) + else CANVAS_OP_TO_GFX_OP("source-atop", ATOP) + else CANVAS_OP_TO_GFX_OP("source-in", IN) + else CANVAS_OP_TO_GFX_OP("source-out", OUT) + else CANVAS_OP_TO_GFX_OP("source-over", OVER) + else CANVAS_OP_TO_GFX_OP("xor", XOR) + else return NS_ERROR_FAILURE; + +#undef CANVAS_OP_TO_GFX_OP + + return NS_OK; +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::DrawWindow(nsIDOMWindow* aWindow, float aX, float aY, + float aW, float aH, + const nsAString& aBGColor, + PRUint32 flags) +{ + NS_ENSURE_ARG(aWindow != nsnull); + + // protect against too-large surfaces that will cause allocation + // or overflow issues + if (!gfxASurface::CheckSurfaceSize(gfxIntSize(PRInt32(aW), PRInt32(aH)), + 0xffff)) + return NS_ERROR_FAILURE; + + nsRefPtr drawSurf; + GetThebesSurface(getter_AddRefs(drawSurf)); + + nsRefPtr thebes = new gfxContext(drawSurf); + + Matrix matrix = mTarget->GetTransform(); + thebes->SetMatrix(gfxMatrix(matrix._11, matrix._12, matrix._21, + matrix._22, matrix._31, matrix._32)); + + // We can't allow web apps to call this until we fix at least the + // following potential security issues: + // -- rendering cross-domain IFRAMEs and then extracting the results + // -- rendering the user's theme and then extracting the results + // -- rendering native anonymous content (e.g., file input paths; + // scrollbars should be allowed) + if (!nsContentUtils::IsCallerTrustedForRead()) { + // not permitted to use DrawWindow + // XXX ERRMSG we need to report an error to developers here! (bug 329026) + return NS_ERROR_DOM_SECURITY_ERR; + } + + // Flush layout updates + if (!(flags & nsIDOMCanvasRenderingContext2D::DRAWWINDOW_DO_NOT_FLUSH)) + nsContentUtils::FlushLayoutForTree(aWindow); + + nsRefPtr presContext; + nsCOMPtr win = do_QueryInterface(aWindow); + if (win) { + nsIDocShell* docshell = win->GetDocShell(); + if (docshell) { + docshell->GetPresContext(getter_AddRefs(presContext)); + } + } + if (!presContext) + return NS_ERROR_FAILURE; + + nscolor bgColor; + + nsIDocument* elementDoc = mCanvasElement ? + HTMLCanvasElement()->GetOwnerDoc() : nsnull; + + // Pass the CSS Loader object to the parser, to allow parser error reports + // to include the outer window ID. + nsCSSParser parser(elementDoc ? elementDoc->CSSLoader() : nsnull); + nsresult rv = parser.ParseColorString(PromiseFlatString(aBGColor), + nsnull, 0, &bgColor); + NS_ENSURE_SUCCESS(rv, rv); + + nsIPresShell* presShell = presContext->PresShell(); + NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE); + + nsRect r(nsPresContext::CSSPixelsToAppUnits(aX), + nsPresContext::CSSPixelsToAppUnits(aY), + nsPresContext::CSSPixelsToAppUnits(aW), + nsPresContext::CSSPixelsToAppUnits(aH)); + PRUint32 renderDocFlags = (nsIPresShell::RENDER_IGNORE_VIEWPORT_SCROLLING | + nsIPresShell::RENDER_DOCUMENT_RELATIVE); + if (flags & nsIDOMCanvasRenderingContext2D::DRAWWINDOW_DRAW_CARET) { + renderDocFlags |= nsIPresShell::RENDER_CARET; + } + if (flags & nsIDOMCanvasRenderingContext2D::DRAWWINDOW_DRAW_VIEW) { + renderDocFlags &= ~(nsIPresShell::RENDER_IGNORE_VIEWPORT_SCROLLING | + nsIPresShell::RENDER_DOCUMENT_RELATIVE); + } + if (flags & nsIDOMCanvasRenderingContext2D::DRAWWINDOW_USE_WIDGET_LAYERS) { + renderDocFlags |= nsIPresShell::RENDER_USE_WIDGET_LAYERS; + } + if (flags & nsIDOMCanvasRenderingContext2D::DRAWWINDOW_ASYNC_DECODE_IMAGES) { + renderDocFlags |= nsIPresShell::RENDER_ASYNC_DECODE_IMAGES; + } + + rv = presShell->RenderDocument(r, renderDocFlags, bgColor, thebes); + + // note that aX and aY are coordinates in the document that + // we're drawing; aX and aY are drawn to 0,0 in current user + // space. + RedrawUser(gfxRect(0, 0, aW, aH)); + + return NS_OK; +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::AsyncDrawXULElement(nsIDOMXULElement* aElem, float aX, float aY, + float aW, float aH, + const nsAString& aBGColor, + PRUint32 flags) +{ +#if 0 + NS_ENSURE_ARG(aElem != nsnull); + + // We can't allow web apps to call this until we fix at least the + // following potential security issues: + // -- rendering cross-domain IFRAMEs and then extracting the results + // -- rendering the user's theme and then extracting the results + // -- rendering native anonymous content (e.g., file input paths; + // scrollbars should be allowed) + if (!nsContentUtils::IsCallerTrustedForRead()) { + // not permitted to use DrawWindow + // XXX ERRMSG we need to report an error to developers here! (bug 329026) + return NS_ERROR_DOM_SECURITY_ERR; + } + + nsCOMPtr loaderOwner = do_QueryInterface(aElem); + if (!loaderOwner) + return NS_ERROR_FAILURE; + + nsRefPtr frameloader = loaderOwner->GetFrameLoader(); + if (!frameloader) + return NS_ERROR_FAILURE; + + PBrowserParent *child = frameloader->GetRemoteBrowser(); + if (!child) { + nsCOMPtr window = + do_GetInterface(frameloader->GetExistingDocShell()); + if (!window) + return NS_ERROR_FAILURE; + + return DrawWindow(window, aX, aY, aW, aH, aBGColor, flags); + } + + // protect against too-large surfaces that will cause allocation + // or overflow issues + if (!gfxASurface::CheckSurfaceSize(gfxIntSize(aW, aH), 0xffff)) + return NS_ERROR_FAILURE; + + PRBool flush = + (flags & nsIDOMCanvasRenderingContext2D::DRAWWINDOW_DO_NOT_FLUSH) == 0; + + PRUint32 renderDocFlags = nsIPresShell::RENDER_IGNORE_VIEWPORT_SCROLLING; + if (flags & nsIDOMCanvasRenderingContext2D::DRAWWINDOW_DRAW_CARET) { + renderDocFlags |= nsIPresShell::RENDER_CARET; + } + if (flags & nsIDOMCanvasRenderingContext2D::DRAWWINDOW_DRAW_VIEW) { + renderDocFlags &= ~nsIPresShell::RENDER_IGNORE_VIEWPORT_SCROLLING; + } + + nsRect rect(nsPresContext::CSSPixelsToAppUnits(aX), + nsPresContext::CSSPixelsToAppUnits(aY), + nsPresContext::CSSPixelsToAppUnits(aW), + nsPresContext::CSSPixelsToAppUnits(aH)); + if (mIPC) { + PDocumentRendererParent *pdocrender = + child->SendPDocumentRendererConstructor(rect, + mThebes->CurrentMatrix(), + nsString(aBGColor), + renderDocFlags, flush, + nsIntSize(mWidth, mHeight)); + if (!pdocrender) + return NS_ERROR_FAILURE; + + DocumentRendererParent *docrender = + static_cast(pdocrender); + + docrender->SetCanvasContext(this, mThebes); + } +#endif + return NS_OK; +} + +// +// device pixel getting/setting +// + +void +nsCanvasRenderingContext2DAzure::EnsureUnpremultiplyTable() { + if (sUnpremultiplyTable) + return; + + // Infallably alloc the unpremultiply table. + sUnpremultiplyTable = new PRUint8[256][256]; + + // It's important that the array be indexed first by alpha and then by rgb + // value. When we unpremultiply a pixel, we're guaranteed to do three + // lookups with the same alpha; indexing by alpha first makes it likely that + // those three lookups will be close to one another in memory, thus + // increasing the chance of a cache hit. + + // a == 0 case + for (PRUint32 c = 0; c <= 255; c++) { + sUnpremultiplyTable[0][c] = c; + } + + for (int a = 1; a <= 255; a++) { + for (int c = 0; c <= 255; c++) { + sUnpremultiplyTable[a][c] = (PRUint8)((c * 255) / a); + } + } +} + + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::GetImageData() +{ + /* Should never be called -- GetImageData_explicit is the QS entry point */ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::GetImageData_explicit(PRInt32 x, PRInt32 y, PRUint32 w, PRUint32 h, + PRUint8 *aData, PRUint32 aDataLen) +{ + if (!mValid) + return NS_ERROR_FAILURE; + + if (!mCanvasElement && !mDocShell) { + NS_ERROR("No canvas element and no docshell in GetImageData!!!"); + return NS_ERROR_DOM_SECURITY_ERR; + } + + // Check only if we have a canvas element; if we were created with a docshell, + // then it's special internal use. + if (mCanvasElement && + HTMLCanvasElement()->IsWriteOnly() && + !nsContentUtils::IsCallerTrustedForRead()) + { + // XXX ERRMSG we need to report an error to developers here! (bug 329026) + return NS_ERROR_DOM_SECURITY_ERR; + } + + if (w == 0 || h == 0 || aDataLen != w * h * 4) + return NS_ERROR_DOM_SYNTAX_ERR; + + CheckedInt32 rightMost = CheckedInt32(x) + w; + CheckedInt32 bottomMost = CheckedInt32(y) + h; + + if (!rightMost.valid() || !bottomMost.valid()) + return NS_ERROR_DOM_SYNTAX_ERR; + + if (mZero) { + return NS_OK; + } + + IntRect srcRect(0, 0, mWidth, mHeight); + IntRect destRect(x, y, w, h); + + if (!srcRect.Contains(destRect)) { + // Some data is outside the canvas surface, clear the destination. + memset(aData, 0, aDataLen); + } + + bool finishedPainting = false; + + IntRect srcReadRect = srcRect.Intersect(destRect); + IntRect dstWriteRect = srcReadRect; + dstWriteRect.MoveBy(-x, -y); + + PRUint8 *src = aData; + PRUint32 srcStride = w * 4; + + if (!srcReadRect.IsEmpty()) { + RefPtr snapshot = mTarget->Snapshot(); + + RefPtr readback = snapshot->GetDataSurface(); + + srcStride = readback->Stride(); + src = readback->GetData() + srcReadRect.y * srcStride + srcReadRect.x * 4; + } + + // make sure sUnpremultiplyTable has been created + EnsureUnpremultiplyTable(); + + // NOTE! dst is the same as src, and this relies on reading + // from src and advancing that ptr before writing to dst. + PRUint8 *dst = aData + dstWriteRect.y * (w * 4) + dstWriteRect.x * 4; + + for (PRUint32 j = 0; j < dstWriteRect.height; j++) { + for (PRUint32 i = 0; i < dstWriteRect.width; i++) { + // XXX Is there some useful swizzle MMX we can use here? +#ifdef IS_LITTLE_ENDIAN + PRUint8 b = *src++; + PRUint8 g = *src++; + PRUint8 r = *src++; + PRUint8 a = *src++; +#else + PRUint8 a = *src++; + PRUint8 r = *src++; + PRUint8 g = *src++; + PRUint8 b = *src++; +#endif + // Convert to non-premultiplied color + *dst++ = sUnpremultiplyTable[a][r]; + *dst++ = sUnpremultiplyTable[a][g]; + *dst++ = sUnpremultiplyTable[a][b]; + *dst++ = a; + } + src += srcStride - (dstWriteRect.width * 4); + dst += (w * 4) - (dstWriteRect.width * 4); + } + return NS_OK; +} + +void +nsCanvasRenderingContext2DAzure::EnsurePremultiplyTable() { + if (sPremultiplyTable) + return; + + // Infallably alloc the premultiply table. + sPremultiplyTable = new PRUint8[256][256]; + + // Like the unpremultiply table, it's important that we index the premultiply + // table with the alpha value as the first index to ensure good cache + // performance. + + for (int a = 0; a <= 255; a++) { + for (int c = 0; c <= 255; c++) { + sPremultiplyTable[a][c] = (a * c + 254) / 255; + } + } +} + +void +nsCanvasRenderingContext2DAzure::FillRuleChanged() +{ + if (mPath) { + mPathBuilder = mPath->CopyToBuilder(CurrentState().fillRule); + mPath = nsnull; + } +} + +// void putImageData (in ImageData d, in float x, in float y); +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::PutImageData() +{ + /* Should never be called -- PutImageData_explicit is the QS entry point */ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::PutImageData_explicit(PRInt32 x, PRInt32 y, PRUint32 w, PRUint32 h, + unsigned char *aData, PRUint32 aDataLen, + PRBool hasDirtyRect, PRInt32 dirtyX, PRInt32 dirtyY, + PRInt32 dirtyWidth, PRInt32 dirtyHeight) +{ + if (!mValid) { + return NS_ERROR_FAILURE; + } + + if (w == 0 || h == 0) { + return NS_ERROR_DOM_SYNTAX_ERR; + } + + IntRect dirtyRect; + IntRect imageDataRect(0, 0, w, h); + + if (hasDirtyRect) { + // fix up negative dimensions + if (dirtyWidth < 0) { + NS_ENSURE_TRUE(dirtyWidth != INT_MIN, NS_ERROR_DOM_INDEX_SIZE_ERR); + + CheckedInt32 checkedDirtyX = CheckedInt32(dirtyX) + dirtyWidth; + + if (!checkedDirtyX.valid()) + return NS_ERROR_DOM_INDEX_SIZE_ERR; + + dirtyX = checkedDirtyX.value(); + dirtyWidth = -(int32)dirtyWidth; + } + + if (dirtyHeight < 0) { + NS_ENSURE_TRUE(dirtyHeight != INT_MIN, NS_ERROR_DOM_INDEX_SIZE_ERR); + + CheckedInt32 checkedDirtyY = CheckedInt32(dirtyY) + dirtyHeight; + + if (!checkedDirtyY.valid()) + return NS_ERROR_DOM_INDEX_SIZE_ERR; + + dirtyY = checkedDirtyY.value(); + dirtyHeight = -(int32)dirtyHeight; + } + + // bound the dirty rect within the imageData rectangle + dirtyRect = imageDataRect.Intersect(IntRect(dirtyX, dirtyY, dirtyWidth, dirtyHeight)); + + if (dirtyRect.Width() <= 0 || dirtyRect.Height() <= 0) + return NS_OK; + } else { + dirtyRect = imageDataRect; + } + + dirtyRect.MoveBy(IntPoint(x, y)); + dirtyRect = IntRect(0, 0, mWidth, mHeight).Intersect(dirtyRect); + + if (dirtyRect.Width() <= 0 || dirtyRect.Height() <= 0) { + return NS_OK; + } + + PRUint32 len = w * h * 4; + if (aDataLen != len) { + return NS_ERROR_DOM_SYNTAX_ERR; + } + + nsRefPtr imgsurf = new gfxImageSurface(gfxIntSize(w, h), + gfxASurface::ImageFormatARGB32); + if (!imgsurf || imgsurf->CairoStatus()) { + return NS_ERROR_FAILURE; + } + + // ensure premultiply table has been created + EnsurePremultiplyTable(); + + PRUint8 *src = aData; + PRUint8 *dst = imgsurf->Data(); + + for (PRUint32 j = 0; j < h; j++) { + for (PRUint32 i = 0; i < w; i++) { + PRUint8 r = *src++; + PRUint8 g = *src++; + PRUint8 b = *src++; + PRUint8 a = *src++; + + // Convert to premultiplied color (losslessly if the input came from getImageData) +#ifdef IS_LITTLE_ENDIAN + *dst++ = sPremultiplyTable[a][b]; + *dst++ = sPremultiplyTable[a][g]; + *dst++ = sPremultiplyTable[a][r]; + *dst++ = a; +#else + *dst++ = a; + *dst++ = sPremultiplyTable[a][r]; + *dst++ = sPremultiplyTable[a][g]; + *dst++ = sPremultiplyTable[a][b]; +#endif + } + } + + RefPtr sourceSurface = + mTarget->CreateSourceSurfaceFromData(imgsurf->Data(), IntSize(w, h), imgsurf->Stride(), FORMAT_B8G8R8A8); + + + mTarget->CopySurface(sourceSurface, + IntRect(dirtyRect.x - x, dirtyRect.y - y, + dirtyRect.width, dirtyRect.height), + IntPoint(dirtyRect.x, dirtyRect.y)); + + Redraw(mgfx::Rect(dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height)); + + return NS_OK; +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::GetThebesSurface(gfxASurface **surface) +{ + if (!mTarget) { + nsRefPtr tmpSurf = + gfxPlatform::GetPlatform()->CreateOffscreenSurface(gfxIntSize(1, 1), gfxASurface::CONTENT_COLOR_ALPHA); + *surface = tmpSurf.forget().get(); + return NS_OK; + } + + nsRefPtr newSurf = + gfxPlatform::GetPlatform()->GetThebesSurfaceForDrawTarget(mTarget); + + *surface = newSurf.forget().get(); + + return NS_OK; +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::CreateImageData() +{ + /* Should never be called; handled entirely in the quickstub */ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::GetMozImageSmoothingEnabled(PRBool *retVal) +{ + *retVal = CurrentState().imageSmoothingEnabled; + return NS_OK; +} + +NS_IMETHODIMP +nsCanvasRenderingContext2DAzure::SetMozImageSmoothingEnabled(PRBool val) +{ + if (val != CurrentState().imageSmoothingEnabled) { + CurrentState().imageSmoothingEnabled = val; + } + + return NS_OK; +} + +static PRUint8 g2DContextLayerUserData; + +class CanvasRenderingContext2DUserData : public LayerUserData { +public: + CanvasRenderingContext2DUserData(nsHTMLCanvasElement *aContent) + : mContent(aContent) {} + static void DidTransactionCallback(void* aData) + { + static_cast(aData)->mContent->MarkContextClean(); + } + +private: + nsRefPtr mContent; +}; + +already_AddRefed +nsCanvasRenderingContext2DAzure::GetCanvasLayer(nsDisplayListBuilder* aBuilder, + CanvasLayer *aOldLayer, + LayerManager *aManager) +{ + if (!mValid) { + return nsnull; + } + + if (mTarget) { + mTarget->Flush(); + } + + if (!mResetLayer && aOldLayer && + aOldLayer->HasUserData(&g2DContextLayerUserData)) { + NS_ADDREF(aOldLayer); + return aOldLayer; + } + + nsRefPtr canvasLayer = aManager->CreateCanvasLayer(); + if (!canvasLayer) { + NS_WARNING("CreateCanvasLayer returned null!"); + return nsnull; + } + CanvasRenderingContext2DUserData *userData = nsnull; + if (aBuilder->IsPaintingToWindow()) { + // Make the layer tell us whenever a transaction finishes (including + // the current transaction), so we can clear our invalidation state and + // start invalidating again. We need to do this for the layer that is + // being painted to a window (there shouldn't be more than one at a time, + // and if there is, flushing the invalidation state more often than + // necessary is harmless). + + // The layer will be destroyed when we tear down the presentation + // (at the latest), at which time this userData will be destroyed, + // releasing the reference to the element. + // The userData will receive DidTransactionCallbacks, which flush the + // the invalidation state to indicate that the canvas is up to date. + userData = new CanvasRenderingContext2DUserData(HTMLCanvasElement()); + canvasLayer->SetDidTransactionCallback( + CanvasRenderingContext2DUserData::DidTransactionCallback, userData); + } + canvasLayer->SetUserData(&g2DContextLayerUserData, userData); + + CanvasLayer::Data data; + + data.mDrawTarget = mTarget; + data.mSize = nsIntSize(mWidth, mHeight); + + canvasLayer->Initialize(data); + PRUint32 flags = mOpaque ? Layer::CONTENT_OPAQUE : 0; + canvasLayer->SetContentFlags(flags); + canvasLayer->Updated(); + + mResetLayer = PR_FALSE; + + return canvasLayer.forget(); +} + +void +nsCanvasRenderingContext2DAzure::MarkContextClean() +{ + if (mInvalidateCount > 0) { + mPredictManyRedrawCalls = mInvalidateCount > kCanvasMaxInvalidateCount; + } + mIsEntireFrameInvalid = PR_FALSE; + mInvalidateCount = 0; +} + diff --git a/content/canvas/test/test_2d.gradient.radial.cone.top.html b/content/canvas/test/test_2d.gradient.radial.cone.top.html index 424df7fa826..04b2fef218a 100644 --- a/content/canvas/test/test_2d.gradient.radial.cone.top.html +++ b/content/canvas/test/test_2d.gradient.radial.cone.top.html @@ -6,6 +6,18 @@

FAIL (fallback content)

@@ -245,7 +256,7 @@ isPixel(ctx, 50,25, 0,255,0,255, 0); } catch (e) { _thrown_outer = true; } -ok(!_thrown_outer, 'should not throw exception'); +ok(!_thrown_outer, ctx.canvas.id + ' should not throw exception'); } @@ -1018,8 +1029,8 @@ function todo_isPixel(ctx, x,y, r,g,b,a, d) { todo(r-d <= pr && pr <= r+d && g-d <= pg && pg <= g+d && b-d <= pb && pb <= b+d && - a-d <= pa && pa <= a+d, - "pixel "+pos+" is "+pr+","+pg+","+pb+","+pa+"; expected "+colour+" +/- "+d); + a-d <= pa && pa <= a+d, + "pixel "+pos+" of "+ctx.canvas.id+" is "+pr+","+pg+","+pb+","+pa+" (marked todo); expected "+colour+" +/- " + d); } function test_2d_composite_globalAlpha_canvaspattern() { @@ -1467,7 +1478,7 @@ ok(ctx.globalCompositeOperation == 'xor', "ctx.globalCompositeOperation == 'xor' } catch (e) { _thrown_outer = true; } -ok(!_thrown_outer, 'should not throw exception'); +ok(!_thrown_outer, ctx.canvas.id + ' should not throw exception'); } @@ -1573,7 +1584,7 @@ ok(ctx.globalCompositeOperation == 'xor', "ctx.globalCompositeOperation == 'xor' } catch (e) { _thrown_outer = true; } -ok(!_thrown_outer, 'should not throw exception'); +ok(!_thrown_outer, ctx.canvas.id + ' should not throw exception'); } @@ -1600,7 +1611,7 @@ ok(ctx.globalCompositeOperation == 'xor', "ctx.globalCompositeOperation == 'xor' } catch (e) { _thrown_outer = true; } -ok(!_thrown_outer, 'should not throw exception'); +ok(!_thrown_outer, ctx.canvas.id + ' should not throw exception'); } @@ -1646,7 +1657,7 @@ ok(ctx.globalCompositeOperation == 'xor', "ctx.globalCompositeOperation == 'xor' } catch (e) { _thrown_outer = true; } -ok(!_thrown_outer, 'should not throw exception'); +ok(!_thrown_outer, ctx.canvas.id + ' should not throw exception'); } @@ -3141,6 +3152,7 @@ var canvas = document.getElementById('c119'); var ctx = canvas.getContext('2d'); var _thrown_outer = false; + try { ctx.fillStyle = '#0f0'; @@ -3843,7 +3855,7 @@ isPixel(ctx, 50,25, 0,255,0,255, 0); } catch (e) { _thrown_outer = true; } -ok(!_thrown_outer, 'should not throw exception'); +ok(!_thrown_outer, ctx.canvas.id + ' should not throw exception'); } @@ -6072,9 +6084,15 @@ g.addColorStop(0.75, '#0f0'); g.addColorStop(1, '#f00'); ctx.fillStyle = g; ctx.fillRect(0, 0, 100, 50); -ctx.translate(-50, 0); -ctx.fillRect(50, 0, 100, 50); -todo_isPixel(ctx, 25,25, 0,255,0,255, 0); +ctx.translate(-50, 0); +ctx.fillRect(50, 0, 100, 50); + +if (IsAzureEnabled()) { + isPixel(ctx, 25,25, 0,255,0,255, 0); +} else { + todo_isPixel(ctx, 25,25, 0,255,0,255, 0); +} + isPixel(ctx, 50,25, 0,255,0,255, 0); isPixel(ctx, 75,25, 0,255,0,255, 0); @@ -6379,18 +6397,30 @@ var g = ctx.createRadialGradient(210, 25, 100, 230, 25, 100); g.addColorStop(0, '#0f0'); g.addColorStop(1, '#f00'); ctx.fillStyle = g; -ctx.fillRect(0, 0, 100, 50); - -isPixel(ctx, 1,1, 0,255,0,255, 0); -isPixel(ctx, 50,1, 0,255,0,255, 0); -isPixel(ctx, 98,1, 0,255,0,255, 0); -isPixel(ctx, 1,25, 0,255,0,255, 0); -isPixel(ctx, 50,25, 0,255,0,255, 0); -isPixel(ctx, 98,25, 0,255,0,255, 0); -isPixel(ctx, 1,48, 0,255,0,255, 0); -isPixel(ctx, 50,48, 0,255,0,255, 0); -isPixel(ctx, 98,48, 0,255,0,255, 0); - +ctx.fillRect(0, 0, 100, 50); + +if (IsAzureEnabled()) { + // XXX - See Bug 666097. + todo_isPixel(ctx, 1, 1, 0, 255, 0, 255, 0); + todo_isPixel(ctx, 50, 1, 0, 255, 0, 255, 0); + todo_isPixel(ctx, 98, 1, 0, 255, 0, 255, 0); + todo_isPixel(ctx, 1, 25, 0, 255, 0, 255, 0); + todo_isPixel(ctx, 50, 25, 0, 255, 0, 255, 0); + todo_isPixel(ctx, 98, 25, 0, 255, 0, 255, 0); + todo_isPixel(ctx, 1, 48, 0, 255, 0, 255, 0); + todo_isPixel(ctx, 50, 48, 0, 255, 0, 255, 0); + todo_isPixel(ctx, 98, 48, 0, 255, 0, 255, 0); +} else { + isPixel(ctx, 1, 1, 0, 255, 0, 255, 0); + isPixel(ctx, 50, 1, 0, 255, 0, 255, 0); + isPixel(ctx, 98, 1, 0, 255, 0, 255, 0); + isPixel(ctx, 1, 25, 0, 255, 0, 255, 0); + isPixel(ctx, 50, 25, 0, 255, 0, 255, 0); + isPixel(ctx, 98, 25, 0, 255, 0, 255, 0); + isPixel(ctx, 1, 48, 0, 255, 0, 255, 0); + isPixel(ctx, 50, 48, 0, 255, 0, 255, 0); + isPixel(ctx, 98, 48, 0, 255, 0, 255, 0); +} } @@ -6538,18 +6568,31 @@ var g = ctx.createRadialGradient(230, 25, 100, 100, 25, 101); g.addColorStop(0, '#f00'); g.addColorStop(1, '#0f0'); ctx.fillStyle = g; -ctx.fillRect(0, 0, 100, 50); - -isPixel(ctx, 1,1, 0,255,0,255, 0); -isPixel(ctx, 50,1, 0,255,0,255, 0); -isPixel(ctx, 98,1, 0,255,0,255, 0); -isPixel(ctx, 1,25, 0,255,0,255, 0); -isPixel(ctx, 50,25, 0,255,0,255, 0); -isPixel(ctx, 98,25, 0,255,0,255, 0); -isPixel(ctx, 1,48, 0,255,0,255, 0); -isPixel(ctx, 50,48, 0,255,0,255, 0); -isPixel(ctx, 98,48, 0,255,0,255, 0); - +ctx.fillRect(0, 0, 100, 50); + + +if (IsAzureEnabled()) { + // XXX - See Bug 666097. + todo_isPixel(ctx, 1, 1, 0, 255, 0, 255, 0); + todo_isPixel(ctx, 50, 1, 0, 255, 0, 255, 0); + todo_isPixel(ctx, 98, 1, 0, 255, 0, 255, 0); + todo_isPixel(ctx, 1, 25, 0, 255, 0, 255, 0); + todo_isPixel(ctx, 50, 25, 0, 255, 0, 255, 0); + todo_isPixel(ctx, 98, 25, 0, 255, 0, 255, 0); + todo_isPixel(ctx, 1, 48, 0, 255, 0, 255, 0); + todo_isPixel(ctx, 50, 48, 0, 255, 0, 255, 0); + todo_isPixel(ctx, 98, 48, 0, 255, 0, 255, 0); +} else { + isPixel(ctx, 1, 1, 0, 255, 0, 255, 0); + isPixel(ctx, 50, 1, 0, 255, 0, 255, 0); + isPixel(ctx, 98, 1, 0, 255, 0, 255, 0); + isPixel(ctx, 1, 25, 0, 255, 0, 255, 0); + isPixel(ctx, 50, 25, 0, 255, 0, 255, 0); + isPixel(ctx, 98, 25, 0, 255, 0, 255, 0); + isPixel(ctx, 1, 48, 0, 255, 0, 255, 0); + isPixel(ctx, 50, 48, 0, 255, 0, 255, 0); + isPixel(ctx, 98, 48, 0, 255, 0, 255, 0); +} } @@ -7267,10 +7310,16 @@ ctx.fillRect(0, 0, 100, 50); ctx.translate(50, 25); ctx.scale(10, 10); ctx.fillRect(-5, -2.5, 10, 5); -todo_isPixel(ctx, 25,25, 0,255,0,255, 0); -todo_isPixel(ctx, 50,25, 0,255,0,255, 0); -todo_isPixel(ctx, 75,25, 0,255,0,255, 0); +if (IsAzureEnabled()) { + isPixel(ctx, 25,25, 0,255,0,255, 0); + isPixel(ctx, 50,25, 0,255,0,255, 0); + isPixel(ctx, 75,25, 0,255,0,255, 0); +} else { + todo_isPixel(ctx, 25,25, 0,255,0,255, 0); + todo_isPixel(ctx, 50,25, 0,255,0,255, 0); + todo_isPixel(ctx, 75,25, 0,255,0,255, 0); +} } @@ -7420,7 +7469,7 @@ ok(imgdata3.data.length == imgdata4.data.length, "imgdata3.data.length == imgdat } catch (e) { _thrown_outer = true; } -ok(!_thrown_outer, 'should not throw exception'); +ok(!_thrown_outer, ctx.canvas.id + ' should not throw exception'); } @@ -7536,7 +7585,7 @@ ok(isTransparentBlack, "isTransparentBlack"); } catch (e) { _thrown_outer = true; } -ok(!_thrown_outer, 'should not throw exception'); +ok(!_thrown_outer, ctx.canvas.id + ' should not throw exception'); } @@ -7568,7 +7617,7 @@ ok(imgdata.data.thisImplementsCanvasPixelArray, "imgdata.data.thisImplementsCanv } catch (e) { _thrown_outer = true; } -todo(!_thrown_outer, 'should not throw exception'); +todo(!_thrown_outer, ctx.canvas.id + ' should not throw exception'); } @@ -7600,7 +7649,7 @@ todo(imgdata.data.thisImplementsCanvasPixelArray, "imgdata.data.thisImplementsCa } catch (e) { _thrown_outer = true; } -todo(!_thrown_outer, 'should not throw exception'); +todo(!_thrown_outer, ctx.canvas.id + ' should not throw exception'); } @@ -8039,7 +8088,7 @@ ok(imgdata2.data[3] === 0, "imgdata2.data[\""+(3)+"\"] === 0"); } catch (e) { _thrown_outer = true; } -ok(!_thrown_outer, 'should not throw exception'); +ok(!_thrown_outer, ctx.canvas.id + ' should not throw exception'); } @@ -8124,7 +8173,7 @@ ok(imgdata7.data[20*4+3] === 0, "imgdata7.data[20*4+3] === 0"); } catch (e) { _thrown_outer = true; } -ok(!_thrown_outer, 'should not throw exception'); +ok(!_thrown_outer, ctx.canvas.id + ' should not throw exception'); } @@ -8174,7 +8223,7 @@ ok(imgdata.height == 1, "imgdata.height == 1"); } catch (e) { _thrown_outer = true; } -ok(!_thrown_outer, 'should not throw exception'); +ok(!_thrown_outer, ctx.canvas.id + ' should not throw exception'); } @@ -8206,7 +8255,7 @@ ok(imgdata.data.thisImplementsCanvasPixelArray, "imgdata.data.thisImplementsCanv } catch (e) { _thrown_outer = true; } -todo(!_thrown_outer, 'should not throw exception'); +todo(!_thrown_outer, ctx.canvas.id + ' should not throw exception'); } @@ -8699,7 +8748,7 @@ isPixel(ctx, 50,45, 0,255,0,255, 2); } catch (e) { _thrown_outer = true; } -ok(!_thrown_outer, 'should not throw exception'); +ok(!_thrown_outer, ctx.canvas.id + ' should not throw exception'); } @@ -8745,7 +8794,7 @@ isPixel(ctx, 1,45, 0,255,0,255, 2); } catch (e) { _thrown_outer = true; } -ok(!_thrown_outer, 'should not throw exception'); +ok(!_thrown_outer, ctx.canvas.id + ' should not throw exception'); } @@ -8789,7 +8838,7 @@ isPixel(ctx, 50,45, 0,255,0,255, 2); } catch (e) { _thrown_outer = true; } -ok(!_thrown_outer, 'should not throw exception'); +ok(!_thrown_outer, ctx.canvas.id + ' should not throw exception'); } @@ -8833,7 +8882,7 @@ isPixel(ctx, 50,45, 0,255,0,255, 2); } catch (e) { _thrown_outer = true; } -ok(!_thrown_outer, 'should not throw exception'); +ok(!_thrown_outer, ctx.canvas.id + ' should not throw exception'); } @@ -9433,7 +9482,7 @@ ok(ctx.lineCap === 'butt', "ctx.lineCap === 'butt'"); } catch (e) { _thrown_outer = true; } -ok(!_thrown_outer, 'should not throw exception'); +ok(!_thrown_outer, ctx.canvas.id + ' should not throw exception'); } @@ -9807,7 +9856,7 @@ ok(ctx.lineJoin === 'bevel', "ctx.lineJoin === 'bevel'"); } catch (e) { _thrown_outer = true; } -ok(!_thrown_outer, 'should not throw exception'); +ok(!_thrown_outer, ctx.canvas.id + ' should not throw exception'); } @@ -10138,7 +10187,7 @@ ok(ctx.miterLimit === 1.5, "ctx.miterLimit === 1.5"); } catch (e) { _thrown_outer = true; } -ok(!_thrown_outer, 'should not throw exception'); +ok(!_thrown_outer, ctx.canvas.id + ' should not throw exception'); } @@ -10428,7 +10477,7 @@ ok(ctx.lineWidth === 1.5, "ctx.lineWidth === 1.5"); } catch (e) { _thrown_outer = true; } -ok(!_thrown_outer, 'should not throw exception'); +ok(!_thrown_outer, ctx.canvas.id + ' should not throw exception'); } @@ -11100,7 +11149,7 @@ isPixel(ctx, 90,45, 0,255,0,255, 0); } catch (e) { _thrown_outer = true; } -ok(!_thrown_outer, 'should not throw exception'); +ok(!_thrown_outer, ctx.canvas.id + ' should not throw exception'); } @@ -11582,7 +11631,12 @@ ctx.beginPath(); ctx.moveTo(0, 25); ctx.arc(200, 25, 0, 0, Math.PI, true); ctx.stroke(); -todo_isPixel(ctx, 50,25, 0,255,0,255, 0); + +if (IsAzureEnabled()) { + isPixel(ctx, 50,25, 0,255,0,255, 0); +} else { + todo_isPixel(ctx, 50,25, 0,255,0,255, 0); +} } @@ -11880,7 +11934,7 @@ isPixel(ctx, 90,45, 0,255,0,255, 0); } catch (e) { _thrown_outer = true; } -ok(!_thrown_outer, 'should not throw exception'); +ok(!_thrown_outer, ctx.canvas.id + ' should not throw exception'); } @@ -12170,7 +12224,7 @@ isPixel(ctx, 50,25, 0,255,0,255, 0); } catch (e) { _thrown_outer = true; } -ok(!_thrown_outer, 'should not throw exception'); +ok(!_thrown_outer, ctx.canvas.id + ' should not throw exception'); } @@ -12213,7 +12267,7 @@ isPixel(ctx, 50,25, 0,255,0,255, 0); } catch (e) { _thrown_outer = true; } -ok(!_thrown_outer, 'should not throw exception'); +ok(!_thrown_outer, ctx.canvas.id + ' should not throw exception'); } @@ -12393,7 +12447,7 @@ isPixel(ctx, 90,45, 0,255,0,255, 0); } catch (e) { _thrown_outer = true; } -ok(!_thrown_outer, 'should not throw exception'); +ok(!_thrown_outer, ctx.canvas.id + ' should not throw exception'); } @@ -13140,22 +13194,22 @@ ok(ctx.isPointInPath(70, 30) === false, "ctx.isPointInPath(70, 30) === false"); function test_2d_path_isPointInPath_edge() { var canvas = document.getElementById('c404'); -var ctx = canvas.getContext('2d'); - -ctx.rect(0, 0, 20, 20); -ok(ctx.isPointInPath(0, 0) === true, "ctx.isPointInPath(0, 0) === true"); -ok(ctx.isPointInPath(10, 0) === true, "ctx.isPointInPath(10, 0) === true"); -ok(ctx.isPointInPath(20, 0) === true, "ctx.isPointInPath(20, 0) === true"); -ok(ctx.isPointInPath(20, 10) === true, "ctx.isPointInPath(20, 10) === true"); -ok(ctx.isPointInPath(20, 20) === true, "ctx.isPointInPath(20, 20) === true"); -ok(ctx.isPointInPath(10, 20) === true, "ctx.isPointInPath(10, 20) === true"); -ok(ctx.isPointInPath(0, 20) === true, "ctx.isPointInPath(0, 20) === true"); -ok(ctx.isPointInPath(0, 10) === true, "ctx.isPointInPath(0, 10) === true"); -ok(ctx.isPointInPath(10, -0.01) === false, "ctx.isPointInPath(10, -0.01) === false"); -ok(ctx.isPointInPath(10, 20.01) === false, "ctx.isPointInPath(10, 20.01) === false"); -ok(ctx.isPointInPath(-0.01, 10) === false, "ctx.isPointInPath(-0.01, 10) === false"); -ok(ctx.isPointInPath(20.01, 10) === false, "ctx.isPointInPath(20.01, 10) === false"); - +var ctx = canvas.getContext('2d'); + +ctx.rect(0, 0, 20, 20); + +ok(ctx.isPointInPath(0, 0) === true, "ctx.isPointInPath(0, 0) === true"); +ok(ctx.isPointInPath(10, 0) === true, "ctx.isPointInPath(10, 0) === true"); +ok(ctx.isPointInPath(20, 0) === true, "ctx.isPointInPath(20, 0) === true"); +ok(ctx.isPointInPath(20, 10) === true, "ctx.isPointInPath(20, 10) === true"); +ok(ctx.isPointInPath(20, 20) === true, "ctx.isPointInPath(20, 20) === true"); +ok(ctx.isPointInPath(10, 20) === true, "ctx.isPointInPath(10, 20) === true"); +ok(ctx.isPointInPath(0, 20) === true, "ctx.isPointInPath(0, 20) === true"); +ok(ctx.isPointInPath(0, 10) === true, "ctx.isPointInPath(0, 10) === true"); +ok(ctx.isPointInPath(10, -0.01) === false, "ctx.isPointInPath(10, -0.01) === false"); +ok(ctx.isPointInPath(10, 20.01) === false, "ctx.isPointInPath(10, 20.01) === false"); +ok(ctx.isPointInPath(-0.01, 10) === false, "ctx.isPointInPath(-0.01, 10) === false"); +ok(ctx.isPointInPath(20.01, 10) === false, "ctx.isPointInPath(20.01, 10) === false"); } @@ -13205,7 +13259,7 @@ ok(ctx.isPointInPath(NaN, NaN) === false, "ctx.isPointInPath(NaN, NaN) === false } catch (e) { _thrown_outer = true; } -ok(!_thrown_outer, 'should not throw exception'); +ok(!_thrown_outer, ctx.canvas.id + ' should not throw exception'); } @@ -13506,7 +13560,7 @@ isPixel(ctx, 90,45, 0,255,0,255, 0); } catch (e) { _thrown_outer = true; } -ok(!_thrown_outer, 'should not throw exception'); +ok(!_thrown_outer, ctx.canvas.id + ' should not throw exception'); } @@ -13621,7 +13675,7 @@ isPixel(ctx, 50,25, 0,255,0,255, 0); } catch (e) { _thrown_outer = true; } -ok(!_thrown_outer, 'should not throw exception'); +ok(!_thrown_outer, ctx.canvas.id + ' should not throw exception'); } @@ -13727,7 +13781,7 @@ isPixel(ctx, 90,45, 0,255,0,255, 0); } catch (e) { _thrown_outer = true; } -ok(!_thrown_outer, 'should not throw exception'); +ok(!_thrown_outer, ctx.canvas.id + ' should not throw exception'); } @@ -13991,7 +14045,7 @@ isPixel(ctx, 90,45, 0,255,0,255, 0); } catch (e) { _thrown_outer = true; } -ok(!_thrown_outer, 'should not throw exception'); +ok(!_thrown_outer, ctx.canvas.id + ' should not throw exception'); } @@ -14943,30 +14997,41 @@ ok(pattern.thisImplementsCanvasPattern, "pattern.thisImplementsCanvasPattern"); function test_2d_pattern_basic_zerocanvas() { -var canvas = document.getElementById('c463'); -var ctx = canvas.getContext('2d'); +var _thrown_outer = false; -var canvas2 = document.createElement('canvas'); -canvas2.width = 0; -canvas2.height = 0; -ok(canvas2.width === 0, "canvas2.width === 0"); -ok(canvas2.height === 0, "canvas2.height === 0"); -var ctx2 = canvas2.getContext('2d'); -ctx2.fillStyle = '#f00'; -ctx2.fillRect(0, 0, 100, 50); -var pattern = ctx.createPattern(canvas2, 'repeat'); +try { + var canvas = document.getElementById('c463'); + var ctx = canvas.getContext('2d'); -ctx.fillStyle = '#0f0'; -ctx.fillRect(0, 0, 100, 50); -ctx.fillStyle = '#f00'; -ctx.fillStyle = pattern; -ctx.fillRect(0, 0, 100, 50); + var canvas2 = document.createElement('canvas'); + canvas2.width = 0; + canvas2.height = 0; + ok(canvas2.width === 0, "canvas2.width === 0"); + ok(canvas2.height === 0, "canvas2.height === 0"); + var ctx2 = canvas2.getContext('2d'); + ctx2.fillStyle = '#f00'; + ctx2.fillRect(0, 0, 100, 50); + var pattern = ctx.createPattern(canvas2, 'repeat'); -isPixel(ctx, 1,1, 0,255,0,255, 0); -isPixel(ctx, 98,1, 0,255,0,255, 0); -isPixel(ctx, 1,48, 0,255,0,255, 0); -isPixel(ctx, 98,48, 0,255,0,255, 0); + ctx.fillStyle = '#0f0'; + ctx.fillRect(0, 0, 100, 50); + ctx.fillStyle = '#f00'; + ctx.fillStyle = pattern; + ctx.fillRect(0, 0, 100, 50); + isPixel(ctx, 1,1, 0,255,0,255, 0); + isPixel(ctx, 98,1, 0,255,0,255, 0); + isPixel(ctx, 1,48, 0,255,0,255, 0); + isPixel(ctx, 98,48, 0,255,0,255, 0); +} catch(e) { + _thrown_outer = true; +} + +if (IsAzureEnabled()) { + ok(_thrown_outer); +} else { + todo(_thrown_outer, ctx.canvas.is + ' should throw exception INVALID_STATE_ERR'); +} } @@ -15594,11 +15659,17 @@ ctx.fillRect(0, 0, 100, 50); ctx.translate(-128, -78); ctx.fillRect(128, 78, 100, 50); -todo_isPixel(ctx, 1,1, 0,255,0,255, 0); -todo_isPixel(ctx, 98,1, 0,255,0,255, 0); -todo_isPixel(ctx, 1,48, 0,255,0,255, 0); -todo_isPixel(ctx, 98,48, 0,255,0,255, 0); - +if (IsAzureEnabled()) { + isPixel(ctx, 1,1, 0,255,0,255, 0); + isPixel(ctx, 98,1, 0,255,0,255, 0); + isPixel(ctx, 1,48, 0,255,0,255, 0); + isPixel(ctx, 98,48, 0,255,0,255, 0); +} else { + todo_isPixel(ctx, 1,1, 0,255,0,255, 0); + todo_isPixel(ctx, 98,1, 0,255,0,255, 0); + todo_isPixel(ctx, 1,48, 0,255,0,255, 0); + todo_isPixel(ctx, 98,48, 0,255,0,255, 0); +} } @@ -15692,12 +15763,20 @@ ctx.fillRect(0, -16, 100, 50); ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 16); -todo_isPixel(ctx, 1,1, 0,255,0,255, 0); -todo_isPixel(ctx, 98,1, 0,255,0,255, 0); +if (IsAzureEnabled()) { + isPixel(ctx, 1,1, 0,255,0,255, 0); + isPixel(ctx, 98,1, 0,255,0,255, 0); + isPixel(ctx, 1,48, 0,255,0,255, 0); + isPixel(ctx, 98,48, 0,255,0,255, 0); +} else { + todo_isPixel(ctx, 1,1, 0,255,0,255, 0); + todo_isPixel(ctx, 98,1, 0,255,0,255, 0); + todo_isPixel(ctx, 1,48, 0,255,0,255, 0); + todo_isPixel(ctx, 98,48, 0,255,0,255, 0); +} + isPixel(ctx, 1,25, 0,255,0,255, 0); isPixel(ctx, 98,25, 0,255,0,255, 0); -todo_isPixel(ctx, 1,48, 0,255,0,255, 0); -todo_isPixel(ctx, 98,48, 0,255,0,255, 0); } @@ -15730,8 +15809,14 @@ ctx.fillRect(0, 0, 100, 16); isPixel(ctx, 1,1, 0,255,0,255, 0); isPixel(ctx, 98,1, 0,255,0,255, 0); -todo_isPixel(ctx, 1,48, 0,255,0,255, 0); -todo_isPixel(ctx, 98,48, 0,255,0,255, 0); + +if (IsAzureEnabled()) { + isPixel(ctx, 1,48, 0,255,0,255, 0); + isPixel(ctx, 98,48, 0,255,0,255, 0); +} else { + todo_isPixel(ctx, 1,48, 0,255,0,255, 0); + todo_isPixel(ctx, 98,48, 0,255,0,255, 0); +} } @@ -15795,12 +15880,20 @@ ctx.fillRect(-48, 0, 100, 50); ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 16, 50); -todo_isPixel(ctx, 1,1, 0,255,0,255, 0); isPixel(ctx, 50,1, 0,255,0,255, 0); -todo_isPixel(ctx, 98,1, 0,255,0,255, 0); -todo_isPixel(ctx, 1,48, 0,255,0,255, 0); isPixel(ctx, 50,48, 0,255,0,255, 0); -todo_isPixel(ctx, 98,48, 0,255,0,255, 0); + +if (IsAzureEnabled()) { + isPixel(ctx, 1,1, 0,255,0,255, 0); + isPixel(ctx, 98,1, 0,255,0,255, 0); + isPixel(ctx, 1,48, 0,255,0,255, 0); + isPixel(ctx, 98,48, 0,255,0,255, 0); +} else { + todo_isPixel(ctx, 1,1, 0,255,0,255, 0); + todo_isPixel(ctx, 98,1, 0,255,0,255, 0); + todo_isPixel(ctx, 1,48, 0,255,0,255, 0); + todo_isPixel(ctx, 98,48, 0,255,0,255, 0); +} } @@ -15832,10 +15925,15 @@ ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 16, 50); isPixel(ctx, 1,1, 0,255,0,255, 0); -todo_isPixel(ctx, 98,1, 0,255,0,255, 0); isPixel(ctx, 1,48, 0,255,0,255, 0); -todo_isPixel(ctx, 98,48, 0,255,0,255, 0); +if (IsAzureEnabled()) { + isPixel(ctx, 98,1, 0,255,0,255, 0); + isPixel(ctx, 98,48, 0,255,0,255, 0); +} else { + todo_isPixel(ctx, 98,1, 0,255,0,255, 0); + todo_isPixel(ctx, 98,48, 0,255,0,255, 0); +} } @@ -16642,10 +16740,9 @@ ctx.globalCompositeOperation = 'xor'; ctx.shadowColor = '#f00'; ctx.shadowOffsetX = 100; ctx.fillStyle = '#0f0'; -ctx.fillRect(-100, 0, 200, 50); - -isPixel(ctx, 50,25, 0,255,0,255, 2); - +ctx.fillRect(-100, 0, 200, 50); + +isPixel(ctx, 50, 25, 255, 255, 0, 255, 2); } @@ -16669,10 +16766,9 @@ ctx.globalCompositeOperation = 'xor'; ctx.shadowColor = '#f00'; ctx.shadowBlur = 1; ctx.fillStyle = '#0f0'; -ctx.fillRect(-10, -10, 120, 70); - -isPixel(ctx, 50,25, 0,255,0,255, 2); - +ctx.fillRect(-10, -10, 120, 70); + +isPixel(ctx, 50, 25, 255, 255, 0, 255, 2); } @@ -18263,7 +18359,7 @@ isPixel(ctx, 50,25, 0,255,0,255, 0); } catch (e) { _thrown_outer = true; } -ok(!_thrown_outer, 'should not throw exception'); +ok(!_thrown_outer, ctx.canvas.id + ' should not throw exception'); } @@ -18566,7 +18662,7 @@ isPixel(ctx, 50,25, 0,255,0,255, 0); } catch (e) { _thrown_outer = true; } -ok(!_thrown_outer, 'should not throw exception'); +ok(!_thrown_outer, ctx.canvas.id + ' should not throw exception'); } @@ -18825,7 +18921,7 @@ isPixel(ctx, 50,25, 0,255,0,255, 0); } catch (e) { _thrown_outer = true; } -ok(!_thrown_outer, 'should not throw exception'); +ok(!_thrown_outer, ctx.canvas.id + ' should not throw exception'); } @@ -18995,7 +19091,7 @@ isPixel(ctx, 50,25, 0,255,0,255, 0); } catch (e) { _thrown_outer = true; } -ok(!_thrown_outer, 'should not throw exception'); +ok(!_thrown_outer, ctx.canvas.id + ' should not throw exception'); } @@ -19202,7 +19298,7 @@ isPixel(ctx, 50,25, 0,255,0,255, 0); } catch (e) { _thrown_outer = true; } -ok(!_thrown_outer, 'should not throw exception'); +ok(!_thrown_outer, ctx.canvas.id + ' should not throw exception'); } @@ -19316,7 +19412,7 @@ isPixel(ctx, 50,25, 0,255,0,255, 0); } catch (e) { _thrown_outer = true; } -ok(!_thrown_outer, 'should not throw exception'); +ok(!_thrown_outer, ctx.canvas.id + ' should not throw exception'); } @@ -19613,7 +19709,7 @@ ok(canvas.getContext('2D') === null, "canvas.getContext('2D') === null"); } catch (e) { _thrown_outer = true; } -ok(!_thrown_outer, 'should not throw exception'); +ok(!_thrown_outer, ctx.canvas.id + ' should not throw exception'); } @@ -19639,7 +19735,7 @@ ok(canvas.getContext("") === null, "canvas.getContext(\"\") === null"); } catch (e) { _thrown_outer = true; } -ok(!_thrown_outer, 'should not throw exception'); +ok(!_thrown_outer, ctx.canvas.id + ' should not throw exception'); } @@ -19665,7 +19761,7 @@ ok(canvas.getContext('This is not an implemented context in any real browser') = } catch (e) { _thrown_outer = true; } -ok(!_thrown_outer, 'should not throw exception'); +ok(!_thrown_outer, ctx.canvas.id + ' should not throw exception'); } @@ -19691,7 +19787,7 @@ ok(canvas.getContext("2d#") === null, "canvas.getContext(\"2d#\") === null"); } catch (e) { _thrown_outer = true; } -ok(!_thrown_outer, 'should not throw exception'); +ok(!_thrown_outer, ctx.canvas.id + ' should not throw exception'); } @@ -19717,7 +19813,7 @@ ok(canvas.getContext("2d\0") === null, "canvas.getContext(\"2d\\0\") === null"); } catch (e) { _thrown_outer = true; } -ok(!_thrown_outer, 'should not throw exception'); +ok(!_thrown_outer, ctx.canvas.id + ' should not throw exception'); } @@ -19743,7 +19839,7 @@ ok(canvas.getContext("2\uFF44") === null, "canvas.getContext(\"2\\uFF44\") === n } catch (e) { _thrown_outer = true; } -ok(!_thrown_outer, 'should not throw exception'); +ok(!_thrown_outer, ctx.canvas.id + ' should not throw exception'); } @@ -20763,7 +20859,7 @@ ok(/^data:image\/png[;,]/.test(data), "data =~ /^data:image\\/png[;,]/"); } catch (e) { _thrown_outer = true; } -ok(!_thrown_outer, 'should not throw exception'); +ok(!_thrown_outer, ctx.canvas.id + ' should not throw exception'); } @@ -20790,7 +20886,7 @@ ok(/^data:image\/png[;,]/.test(data), "data =~ /^data:image\\/png[;,]/"); } catch (e) { _thrown_outer = true; } -ok(!_thrown_outer, 'should not throw exception'); +ok(!_thrown_outer, ctx.canvas.id + ' should not throw exception'); } @@ -20818,7 +20914,7 @@ ok(/^data:image\/png[;,]/.test(data), "data =~ /^data:image\\/png[;,]/"); } catch (e) { _thrown_outer = true; } -ok(!_thrown_outer, 'should not throw exception'); +ok(!_thrown_outer, ctx.canvas.id + ' should not throw exception'); } @@ -20904,7 +21000,7 @@ ok(/^data:image\/png[;,]/.test(data), "data =~ /^data:image\\/png[;,]/"); } catch (e) { _thrown_outer = true; } -ok(!_thrown_outer, 'should not throw exception'); +ok(!_thrown_outer, ctx.canvas.id + ' should not throw exception'); } @@ -21012,7 +21108,7 @@ ok(/^data:image\/png[;,]/.test(data), "data =~ /^data:image\\/png[;,]/"); } catch (e) { _thrown_outer = true; } -ok(!_thrown_outer, 'should not throw exception'); +ok(!_thrown_outer, ctx.canvas.id + ' should not throw exception'); } @@ -21407,14 +21503,10 @@ function runTests() { //test_2d_path_rect_zero_6(); // This test is bogus according to the spec; see bug 407107 - // These tests are bogus according to the spec: shadows should not be - // drawn if shadowBlur, shadowOffsetX, and shadowOffsetY are all zero, whic - // they are in these tests + // The following tests are disabled due to pending changes in the spec: + // //test_2d_shadow_composite_3(); //test_2d_shadow_composite_4(); - // Shadows should not be drawn if the operator is not source-over (the spec doesn't - // say this yet, but it should be changed). These tests assume shadows will - // be drawn with operators other than source-over: //test_2d_shadow_composite_1(); //test_2d_shadow_composite_2(); try { diff --git a/content/html/content/src/nsHTMLCanvasElement.cpp b/content/html/content/src/nsHTMLCanvasElement.cpp index ed47529dc69..e50a96a182f 100644 --- a/content/html/content/src/nsHTMLCanvasElement.cpp +++ b/content/html/content/src/nsHTMLCanvasElement.cpp @@ -48,6 +48,7 @@ #include "jsapi.h" #include "nsJSUtils.h" #include "nsMathUtils.h" +#include "mozilla/Preferences.h" #include "nsFrameManager.h" #include "nsDisplayList.h" @@ -722,3 +723,23 @@ nsHTMLCanvasElement::RenderContextsExternal(gfxContext *aContext, gfxPattern::Gr return mCurrentContext->Render(aContext, aFilter); } + +nsresult NS_NewCanvasRenderingContext2DThebes(nsIDOMCanvasRenderingContext2D** aResult); +nsresult NS_NewCanvasRenderingContext2DAzure(nsIDOMCanvasRenderingContext2D** aResult); + +nsresult +NS_NewCanvasRenderingContext2D(nsIDOMCanvasRenderingContext2D** aResult) +{ + PRBool azure = PR_FALSE; + nsresult rv = Preferences::GetBool("gfx.canvas.azure.enabled", &azure); + + if (azure) { + nsresult rv = NS_NewCanvasRenderingContext2DAzure(aResult); + // If Azure fails, fall back to a classic canvas. + if (NS_SUCCEEDED(rv)) { + return rv; + } + } + + return NS_NewCanvasRenderingContext2DThebes(aResult); +} diff --git a/content/mathml/content/src/nsMathMLElement.cpp b/content/mathml/content/src/nsMathMLElement.cpp index 30b130391fe..261fa83b22a 100644 --- a/content/mathml/content/src/nsMathMLElement.cpp +++ b/content/mathml/content/src/nsMathMLElement.cpp @@ -62,6 +62,8 @@ NS_INTERFACE_TABLE_HEAD(nsMathMLElement) NS_NODE_OFFSET_AND_INTERFACE_TABLE_BEGIN(nsMathMLElement) NS_INTERFACE_TABLE_ENTRY(nsMathMLElement, nsIDOMNode) NS_INTERFACE_TABLE_ENTRY(nsMathMLElement, nsIDOMElement) + NS_INTERFACE_TABLE_ENTRY(nsMathMLElement, nsILink) + NS_INTERFACE_TABLE_ENTRY(nsMathMLElement, Link) NS_OFFSET_AND_INTERFACE_TABLE_END NS_ELEMENT_INTERFACE_TABLE_TO_MAP_SEGUE NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(MathMLElement) @@ -77,6 +79,8 @@ nsMathMLElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent, { static const char kMathMLStyleSheetURI[] = "resource://gre-resources/mathml.css"; + Link::ResetLinkState(false); + nsresult rv = nsMathMLElementBase::BindToTree(aDocument, aParent, aBindingParent, aCompileEventHandlers); @@ -101,6 +105,16 @@ nsMathMLElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent, return rv; } +void +nsMathMLElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent) +{ + // If this link is ever reinserted into a document, it might + // be under a different xml:base, so forget the cached state now. + Link::ResetLinkState(false); + + nsMathMLElementBase::UnbindFromTree(aDeep, aNullParent); +} + PRBool nsMathMLElement::ParseAttribute(PRInt32 aNamespaceID, nsIAtom* aAttribute, @@ -438,12 +452,27 @@ nsMathMLElement::MapMathMLAttributesInto(const nsMappedAttributes* aAttributes, } } +nsresult +nsMathMLElement::PreHandleEvent(nsEventChainPreVisitor& aVisitor) +{ + nsresult rv = nsGenericElement::PreHandleEvent(aVisitor); + NS_ENSURE_SUCCESS(rv, rv); + + return PreHandleEventForLinks(aVisitor); +} + +nsresult +nsMathMLElement::PostHandleEvent(nsEventChainPostVisitor& aVisitor) +{ + return PostHandleEventForLinks(aVisitor); +} + NS_IMPL_ELEMENT_CLONE(nsMathMLElement) nsEventStates nsMathMLElement::IntrinsicState() const { - return nsMathMLElementBase::IntrinsicState() | + return Link::LinkState() | nsMathMLElementBase::IntrinsicState() | (mIncrementScriptLevel ? NS_EVENT_STATE_INCREMENT_SCRIPT_LEVEL : nsEventStates()); } @@ -465,3 +494,185 @@ nsMathMLElement::SetIncrementScriptLevel(PRBool aIncrementScriptLevel, UpdateState(true); } + +PRBool +nsMathMLElement::IsFocusable(PRInt32 *aTabIndex, PRBool aWithMouse) +{ + nsCOMPtr uri; + if (IsLink(getter_AddRefs(uri))) { + if (aTabIndex) { + *aTabIndex = ((sTabFocusModel & eTabFocus_linksMask) == 0 ? -1 : 0); + } + return PR_TRUE; + } + + if (aTabIndex) { + *aTabIndex = -1; + } + + return PR_FALSE; +} + +PRBool +nsMathMLElement::IsLink(nsIURI** aURI) const +{ + // http://www.w3.org/TR/2010/REC-MathML3-20101021/chapter6.html#interf.link + // The REC says that the following elements should not be linking elements: + nsIAtom* tag = Tag(); + if (tag == nsGkAtoms::mprescripts_ || + tag == nsGkAtoms::none || + tag == nsGkAtoms::malignmark_ || + tag == nsGkAtoms::maligngroup_) { + *aURI = nsnull; + return PR_FALSE; + } + + PRBool hasHref = PR_FALSE; + const nsAttrValue* href = mAttrsAndChildren.GetAttr(nsGkAtoms::href, + kNameSpaceID_None); + if (href) { + // MathML href + // The REC says: "When user agents encounter MathML elements with both href + // and xlink:href attributes, the href attribute should take precedence." + hasHref = PR_TRUE; + } else { + // To be a clickable XLink for styling and interaction purposes, we require: + // + // xlink:href - must be set + // xlink:type - must be unset or set to "" or set to "simple" + // xlink:show - must be unset or set to "", "new" or "replace" + // xlink:actuate - must be unset or set to "" or "onRequest" + // + // For any other values, we're either not a *clickable* XLink, or the end + // result is poorly specified. Either way, we return PR_FALSE. + + static nsIContent::AttrValuesArray sTypeVals[] = + { &nsGkAtoms::_empty, &nsGkAtoms::simple, nsnull }; + + static nsIContent::AttrValuesArray sShowVals[] = + { &nsGkAtoms::_empty, &nsGkAtoms::_new, &nsGkAtoms::replace, nsnull }; + + static nsIContent::AttrValuesArray sActuateVals[] = + { &nsGkAtoms::_empty, &nsGkAtoms::onRequest, nsnull }; + + // Optimization: check for href first for early return + href = mAttrsAndChildren.GetAttr(nsGkAtoms::href, + kNameSpaceID_XLink); + if (href && + FindAttrValueIn(kNameSpaceID_XLink, nsGkAtoms::type, + sTypeVals, eCaseMatters) != + nsIContent::ATTR_VALUE_NO_MATCH && + FindAttrValueIn(kNameSpaceID_XLink, nsGkAtoms::show, + sShowVals, eCaseMatters) != + nsIContent::ATTR_VALUE_NO_MATCH && + FindAttrValueIn(kNameSpaceID_XLink, nsGkAtoms::actuate, + sActuateVals, eCaseMatters) != + nsIContent::ATTR_VALUE_NO_MATCH) { + hasHref = PR_TRUE; + } + } + + if (hasHref) { + nsCOMPtr baseURI = GetBaseURI(); + // Get absolute URI + nsAutoString hrefStr; + href->ToString(hrefStr); + nsContentUtils::NewURIWithDocumentCharset(aURI, hrefStr, + GetOwnerDoc(), baseURI); + // must promise out param is non-null if we return true + return !!*aURI; + } + + *aURI = nsnull; + return PR_FALSE; +} + +void +nsMathMLElement::GetLinkTarget(nsAString& aTarget) +{ + const nsAttrValue* target = mAttrsAndChildren.GetAttr(nsGkAtoms::target, + kNameSpaceID_XLink); + if (target) { + target->ToString(aTarget); + } + + if (aTarget.IsEmpty()) { + + static nsIContent::AttrValuesArray sShowVals[] = + { &nsGkAtoms::_new, &nsGkAtoms::replace, nsnull }; + + switch (FindAttrValueIn(kNameSpaceID_XLink, nsGkAtoms::show, + sShowVals, eCaseMatters)) { + case 0: + aTarget.AssignLiteral("_blank"); + return; + case 1: + return; + } + nsIDocument* ownerDoc = GetOwnerDoc(); + if (ownerDoc) { + ownerDoc->GetBaseTarget(aTarget); + } + } +} + +nsLinkState +nsMathMLElement::GetLinkState() const +{ + return Link::GetLinkState(); +} + +void +nsMathMLElement::RequestLinkStateUpdate() +{ + UpdateLinkState(Link::LinkState()); +} + +already_AddRefed +nsMathMLElement::GetHrefURI() const +{ + nsCOMPtr hrefURI; + return IsLink(getter_AddRefs(hrefURI)) ? hrefURI.forget() : nsnull; +} + +nsresult +nsMathMLElement::SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, + nsIAtom* aPrefix, const nsAString& aValue, + PRBool aNotify) +{ + nsresult rv = nsMathMLElementBase::SetAttr(aNameSpaceID, aName, aPrefix, + aValue, aNotify); + + // The ordering of the parent class's SetAttr call and Link::ResetLinkState + // is important here! The attribute is not set until SetAttr returns, and + // we will need the updated attribute value because notifying the document + // that content states have changed will call IntrinsicState, which will try + // to get updated information about the visitedness from Link. + if (aName == nsGkAtoms::href && + (aNameSpaceID == kNameSpaceID_None || + aNameSpaceID == kNameSpaceID_XLink)) { + Link::ResetLinkState(!!aNotify); + } + + return rv; +} + +nsresult +nsMathMLElement::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttr, + PRBool aNotify) +{ + nsresult rv = nsMathMLElementBase::UnsetAttr(aNameSpaceID, aAttr, aNotify); + + // The ordering of the parent class's UnsetAttr call and Link::ResetLinkState + // is important here! The attribute is not unset until UnsetAttr returns, and + // we will need the updated attribute value because notifying the document + // that content states have changed will call IntrinsicState, which will try + // to get updated information about the visitedness from Link. + if (aAttr == nsGkAtoms::href && + (aNameSpaceID == kNameSpaceID_None || + aNameSpaceID == kNameSpaceID_XLink)) { + Link::ResetLinkState(!!aNotify); + } + + return rv; +} diff --git a/content/mathml/content/src/nsMathMLElement.h b/content/mathml/content/src/nsMathMLElement.h index 92058f4da12..3e6dd56ba72 100644 --- a/content/mathml/content/src/nsMathMLElement.h +++ b/content/mathml/content/src/nsMathMLElement.h @@ -42,6 +42,8 @@ #include "nsMappedAttributeElement.h" #include "nsIDOMElement.h" +#include "nsILink.h" +#include "Link.h" class nsCSSValue; @@ -50,12 +52,15 @@ typedef nsMappedAttributeElement nsMathMLElementBase; /* * The base class for MathML elements. */ -class nsMathMLElement : public nsMathMLElementBase - , public nsIDOMElement +class nsMathMLElement : public nsMathMLElementBase, + public nsIDOMElement, + public nsILink, + public mozilla::dom::Link { public: nsMathMLElement(already_AddRefed aNodeInfo) - : nsMathMLElementBase(aNodeInfo), mIncrementScriptLevel(PR_FALSE) + : nsMathMLElementBase(aNodeInfo), Link(this), + mIncrementScriptLevel(PR_FALSE) {} // Implementation of nsISupports is inherited from nsMathMLElementBase @@ -69,6 +74,8 @@ public: nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent, nsIContent* aBindingParent, PRBool aCompileEventHandlers); + virtual void UnbindFromTree(PRBool aDeep = PR_TRUE, + PRBool aNullParent = PR_TRUE); virtual PRBool ParseAttribute(PRInt32 aNamespaceID, nsIAtom* aAttribute, @@ -89,6 +96,8 @@ public: static void MapMathMLAttributesInto(const nsMappedAttributes* aAttributes, nsRuleData* aRuleData); + virtual nsresult PreHandleEvent(nsEventChainPreVisitor& aVisitor); + virtual nsresult PostHandleEvent(nsEventChainPostVisitor& aVisitor); nsresult Clone(nsINodeInfo*, nsINode**) const; virtual nsEventStates IntrinsicState() const; virtual PRBool IsNodeOfType(PRUint32 aFlags) const; @@ -100,6 +109,26 @@ public: return mIncrementScriptLevel; } + NS_IMETHOD LinkAdded() { return NS_OK; } + NS_IMETHOD LinkRemoved() { return NS_OK; } + virtual PRBool IsFocusable(PRInt32 *aTabIndex = nsnull, + PRBool aWithMouse = PR_FALSE); + virtual PRBool IsLink(nsIURI** aURI) const; + virtual void GetLinkTarget(nsAString& aTarget); + virtual nsLinkState GetLinkState() const; + virtual void RequestLinkStateUpdate(); + virtual already_AddRefed GetHrefURI() const; + nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, + const nsAString& aValue, PRBool aNotify) + { + return SetAttr(aNameSpaceID, aName, nsnull, aValue, aNotify); + } + virtual nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, + nsIAtom* aPrefix, const nsAString& aValue, + PRBool aNotify); + virtual nsresult UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttribute, + PRBool aNotify); + virtual nsXPCClassInfo* GetClassInfo(); private: PRPackedBool mIncrementScriptLevel; diff --git a/content/xbl/src/nsXBLService.cpp b/content/xbl/src/nsXBLService.cpp index 17c1a1fb41c..9bc997ab559 100644 --- a/content/xbl/src/nsXBLService.cpp +++ b/content/xbl/src/nsXBLService.cpp @@ -87,7 +87,7 @@ #ifdef MOZ_XUL #include "nsXULPrototypeCache.h" #endif -#include "nsIDOMLoadListener.h" +#include "nsIDOMEventListener.h" #include "mozilla/Preferences.h" using namespace mozilla; @@ -272,19 +272,13 @@ int nsXBLBindingRequest::gRefCnt = 0; // nsXBLStreamListener, a helper class used for // asynchronous parsing of URLs /* Header file */ -class nsXBLStreamListener : public nsIStreamListener, public nsIDOMLoadListener +class nsXBLStreamListener : public nsIStreamListener, public nsIDOMEventListener { public: NS_DECL_ISUPPORTS NS_DECL_NSISTREAMLISTENER NS_DECL_NSIREQUESTOBSERVER - - NS_IMETHOD Load(nsIDOMEvent* aEvent); - NS_IMETHOD BeforeUnload(nsIDOMEvent* aEvent) { return NS_OK; } - NS_IMETHOD Unload(nsIDOMEvent* aEvent) { return NS_OK; } - NS_IMETHOD Abort(nsIDOMEvent* aEvent) { return NS_OK; } - NS_IMETHOD Error(nsIDOMEvent* aEvent) { return NS_OK; } - NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent) { return NS_OK; } + NS_DECL_NSIDOMEVENTLISTENER nsXBLStreamListener(nsXBLService* aXBLService, nsIDocument* aBoundDocument, @@ -307,7 +301,10 @@ private: }; /* Implementation file */ -NS_IMPL_ISUPPORTS4(nsXBLStreamListener, nsIStreamListener, nsIRequestObserver, nsIDOMLoadListener, nsIDOMEventListener) +NS_IMPL_ISUPPORTS3(nsXBLStreamListener, + nsIStreamListener, + nsIRequestObserver, + nsIDOMEventListener) nsXBLStreamListener::nsXBLStreamListener(nsXBLService* aXBLService, nsIDocument* aBoundDocument, @@ -401,7 +398,7 @@ nsXBLStreamListener::HasRequest(nsIURI* aURI, nsIContent* aElt) } nsresult -nsXBLStreamListener::Load(nsIDOMEvent* aEvent) +nsXBLStreamListener::HandleEvent(nsIDOMEvent* aEvent) { nsresult rv = NS_OK; PRUint32 i; @@ -481,7 +478,7 @@ nsXBLStreamListener::Load(nsIDOMEvent* aEvent) } } - target->RemoveEventListener(NS_LITERAL_STRING("load"), (nsIDOMLoadListener*)this, PR_FALSE); + target->RemoveEventListener(NS_LITERAL_STRING("load"), this, PR_FALSE); return rv; } diff --git a/content/xbl/src/nsXBLWindowKeyHandler.cpp b/content/xbl/src/nsXBLWindowKeyHandler.cpp index 317bc513d7d..868a7381895 100644 --- a/content/xbl/src/nsXBLWindowKeyHandler.cpp +++ b/content/xbl/src/nsXBLWindowKeyHandler.cpp @@ -201,8 +201,7 @@ nsXBLWindowKeyHandler::~nsXBLWindowKeyHandler() } } -NS_IMPL_ISUPPORTS2(nsXBLWindowKeyHandler, - nsIDOMKeyListener, +NS_IMPL_ISUPPORTS1(nsXBLWindowKeyHandler, nsIDOMEventListener) static void @@ -393,28 +392,20 @@ nsXBLWindowKeyHandler::WalkHandlers(nsIDOMKeyEvent* aKeyEvent, nsIAtom* aEventTy return NS_OK; } -nsresult nsXBLWindowKeyHandler::KeyUp(nsIDOMEvent* aEvent) +NS_IMETHODIMP +nsXBLWindowKeyHandler::HandleEvent(nsIDOMEvent* aEvent) { nsCOMPtr keyEvent(do_QueryInterface(aEvent)); NS_ENSURE_TRUE(keyEvent, NS_ERROR_INVALID_ARG); - return WalkHandlers(keyEvent, nsGkAtoms::keyup); -} -nsresult nsXBLWindowKeyHandler::KeyDown(nsIDOMEvent* aEvent) -{ - nsCOMPtr keyEvent(do_QueryInterface(aEvent)); - NS_ENSURE_TRUE(keyEvent, NS_ERROR_INVALID_ARG); - return WalkHandlers(keyEvent, nsGkAtoms::keydown); -} + nsAutoString eventType; + aEvent->GetType(eventType); + nsCOMPtr eventTypeAtom = do_GetAtom(eventType); + NS_ENSURE_TRUE(eventTypeAtom, NS_ERROR_OUT_OF_MEMORY); -nsresult nsXBLWindowKeyHandler::KeyPress(nsIDOMEvent* aEvent) -{ - nsCOMPtr keyEvent(do_QueryInterface(aEvent)); - NS_ENSURE_TRUE(keyEvent, NS_ERROR_INVALID_ARG); - return WalkHandlers(keyEvent, nsGkAtoms::keypress); + return WalkHandlers(keyEvent, eventTypeAtom); } - // // EventMatched // diff --git a/content/xbl/src/nsXBLWindowKeyHandler.h b/content/xbl/src/nsXBLWindowKeyHandler.h index b4a33a1a4be..820a704506c 100644 --- a/content/xbl/src/nsXBLWindowKeyHandler.h +++ b/content/xbl/src/nsXBLWindowKeyHandler.h @@ -41,7 +41,7 @@ #define nsXBLWindowKeyHandler_h__ #include "nsWeakPtr.h" -#include "nsIDOMKeyListener.h" +#include "nsIDOMEventListener.h" class nsIAtom; class nsIDOMElement; @@ -52,23 +52,14 @@ class nsIXBLDocumentInfo; class nsXBLSpecialDocInfo; class nsXBLPrototypeHandler; -class nsXBLWindowKeyHandler : public nsIDOMKeyListener +class nsXBLWindowKeyHandler : public nsIDOMEventListener { public: nsXBLWindowKeyHandler(nsIDOMElement* aElement, nsIDOMEventTarget* aTarget); virtual ~nsXBLWindowKeyHandler(); - - // nsIDOMetc. - NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent) - { - return NS_OK; - } - NS_IMETHOD KeyUp(nsIDOMEvent* aKeyEvent); - NS_IMETHOD KeyDown(nsIDOMEvent* aKeyEvent); - NS_IMETHOD KeyPress(nsIDOMEvent* aKeyEvent); - NS_DECL_ISUPPORTS + NS_DECL_NSIDOMEVENTLISTENER // release globals static NS_HIDDEN_(void) ShutDown(); diff --git a/docshell/base/nsDefaultURIFixup.cpp b/docshell/base/nsDefaultURIFixup.cpp index e46cc81f911..0b43f8028f4 100644 --- a/docshell/base/nsDefaultURIFixup.cpp +++ b/docshell/base/nsDefaultURIFixup.cpp @@ -44,8 +44,6 @@ #include "nsEscape.h" #include "nsCRT.h" -#include "nsIPrefService.h" -#include "nsIPrefLocalizedString.h" #include "nsIPlatformCharset.h" #include "nsILocalFile.h" @@ -55,6 +53,9 @@ #include "nsIURIFixup.h" #include "nsDefaultURIFixup.h" +#include "mozilla/Preferences.h" + +using namespace mozilla; /* Implementation file */ NS_IMPL_ISUPPORTS1(nsDefaultURIFixup, nsIURIFixup) @@ -62,9 +63,6 @@ NS_IMPL_ISUPPORTS1(nsDefaultURIFixup, nsIURIFixup) nsDefaultURIFixup::nsDefaultURIFixup() { /* member initializers and constructor code */ - - // Try and get the pref service - mPrefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID); } @@ -134,13 +132,10 @@ nsDefaultURIFixup::CreateExposableURI(nsIURI *aURI, nsIURI **aReturn) } // hide user:pass unless overridden by pref - PRBool hideUserPass = PR_TRUE; - if (mPrefBranch) + if (Preferences::GetBool("browser.fixup.hide_user_pass", PR_TRUE)) { - mPrefBranch->GetBoolPref("browser.fixup.hide_user_pass", &hideUserPass); - } - if (hideUserPass) uri->SetUserPass(EmptyCString()); + } // return the fixed-up URI *aReturn = uri; @@ -274,10 +269,8 @@ nsDefaultURIFixup::CreateFixupURI(const nsACString& aStringURI, PRUint32 aFixupF // Test whether keywords need to be fixed up PRBool fixupKeywords = PR_FALSE; if (aFixupFlags & FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP) { - if (mPrefBranch) - { - NS_ENSURE_SUCCESS(mPrefBranch->GetBoolPref("keyword.enabled", &fixupKeywords), NS_ERROR_FAILURE); - } + nsresult rv = Preferences::GetBool("keyword.enabled", &fixupKeywords); + NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); if (fixupKeywords) { KeywordURIFixup(uriString, aURI); @@ -358,7 +351,7 @@ NS_IMETHODIMP nsDefaultURIFixup::KeywordToURI(const nsACString& aKeyword, nsIURI **aURI) { *aURI = nsnull; - NS_ENSURE_STATE(mPrefBranch); + NS_ENSURE_STATE(Preferences::GetRootBranch()); // Strip leading "?" and leading/trailing spaces from aKeyword nsCAutoString keyword(aKeyword); @@ -367,19 +360,10 @@ NS_IMETHODIMP nsDefaultURIFixup::KeywordToURI(const nsACString& aKeyword, } keyword.Trim(" "); - nsXPIDLCString url; - nsCOMPtr keywordURL; - mPrefBranch->GetComplexValue("keyword.URL", - NS_GET_IID(nsIPrefLocalizedString), - getter_AddRefs(keywordURL)); - - if (keywordURL) { - nsXPIDLString wurl; - keywordURL->GetData(getter_Copies(wurl)); - CopyUTF16toUTF8(wurl, url); - } else { + nsAdoptingCString url = Preferences::GetLocalizedCString("keyword.URL"); + if (!url) { // Fall back to a non-localized pref, for backwards compat - mPrefBranch->GetCharPref("keyword.URL", getter_Copies(url)); + url = Preferences::GetCString("keyword.URL"); } // If the pref is set and non-empty, use it. @@ -441,13 +425,11 @@ NS_IMETHODIMP nsDefaultURIFixup::KeywordToURI(const nsACString& aKeyword, PRBool nsDefaultURIFixup::MakeAlternateURI(nsIURI *aURI) { - if (!mPrefBranch) + if (!Preferences::GetRootBranch()) { return PR_FALSE; } - PRBool makeAlternate = PR_TRUE; - mPrefBranch->GetBoolPref("browser.fixup.alternate.enabled", &makeAlternate); - if (!makeAlternate) + if (!Preferences::GetBool("browser.fixup.alternate.enabled", PR_TRUE)) { return PR_FALSE; } @@ -489,17 +471,17 @@ PRBool nsDefaultURIFixup::MakeAlternateURI(nsIURI *aURI) // are www. & .com but they could be any other value, e.g. www. & .org nsCAutoString prefix("www."); - nsXPIDLCString prefPrefix; - rv = mPrefBranch->GetCharPref("browser.fixup.alternate.prefix", getter_Copies(prefPrefix)); - if (NS_SUCCEEDED(rv)) + nsAdoptingCString prefPrefix = + Preferences::GetCString("browser.fixup.alternate.prefix"); + if (prefPrefix) { prefix.Assign(prefPrefix); } nsCAutoString suffix(".com"); - nsXPIDLCString prefSuffix; - rv = mPrefBranch->GetCharPref("browser.fixup.alternate.suffix", getter_Copies(prefSuffix)); - if (NS_SUCCEEDED(rv)) + nsAdoptingCString prefSuffix = + Preferences::GetCString("browser.fixup.alternate.suffix"); + if (prefSuffix) { suffix.Assign(prefSuffix); } diff --git a/docshell/base/nsDefaultURIFixup.h b/docshell/base/nsDefaultURIFixup.h index bc8a5487ef9..388cee5e25c 100644 --- a/docshell/base/nsDefaultURIFixup.h +++ b/docshell/base/nsDefaultURIFixup.h @@ -40,7 +40,6 @@ #ifndef NSDEFAULTURIFIXUP_H #define NSDEFAULTURIFIXUP_H -#include "nsIPrefBranch.h" #include "nsIURIFixup.h" #include "nsCOMPtr.h" @@ -71,7 +70,6 @@ private: const char * GetFileSystemCharset(); const char * GetCharsetForUrlBar(); - nsCOMPtr mPrefBranch; nsCString mFsCharset; }; diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index 968d6bedf88..6674e527f17 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -95,9 +95,6 @@ #include "nsXPCOMCID.h" #include "nsISeekableStream.h" #include "nsAutoPtr.h" -#include "nsIPrefService.h" -#include "nsIPrefBranch.h" -#include "nsIPrefBranch2.h" #include "nsIWritablePropertyBag2.h" #include "nsIAppShell.h" #include "nsWidgetsCID.h" @@ -111,6 +108,7 @@ #include "nsJSON.h" #include "IHistory.h" #include "mozilla/Services.h" +#include "mozilla/Preferences.h" // we want to explore making the document own the load group // so we can associate the document URI with the load group. @@ -307,21 +305,14 @@ FavorPerformanceHint(PRBool perfOverStarvation, PRUint32 starvationDelay) static PRBool PingsEnabled(PRInt32 *maxPerLink, PRBool *requireSameHost) { - PRBool allow = PR_FALSE; + PRBool allow = Preferences::GetBool(PREF_PINGS_ENABLED, PR_FALSE); *maxPerLink = 1; *requireSameHost = PR_TRUE; - nsCOMPtr prefs = - do_GetService(NS_PREFSERVICE_CONTRACTID); - if (prefs) { - PRBool val; - if (NS_SUCCEEDED(prefs->GetBoolPref(PREF_PINGS_ENABLED, &val))) - allow = val; - if (allow) { - prefs->GetIntPref(PREF_PINGS_MAX_PER_LINK, maxPerLink); - prefs->GetBoolPref(PREF_PINGS_REQUIRE_SAME_HOST, requireSameHost); - } + if (allow) { + Preferences::GetInt(PREF_PINGS_MAX_PER_LINK, maxPerLink); + Preferences::GetBool(PREF_PINGS_REQUIRE_SAME_HOST, requireSameHost); } return allow; @@ -739,6 +730,7 @@ nsDocShell::nsDocShell(): mPreviousTransIndex(-1), mLoadType(0), mLoadedTransIndex(-1), + mCreated(PR_FALSE), mAllowSubframes(PR_TRUE), mAllowPlugins(PR_TRUE), mAllowJavascript(PR_TRUE), @@ -1600,9 +1592,7 @@ nsDocShell::MaybeInitTiming() return NS_OK; } - PRBool enabled; - nsresult rv = mPrefs->GetBoolPref("dom.enable_performance", &enabled); - if (NS_SUCCEEDED(rv) && enabled) { + if (Preferences::GetBool("dom.enable_performance", PR_FALSE)) { mTiming = new nsDOMNavigationTiming(); mTiming->NotifyNavigationStart(); } @@ -2201,11 +2191,8 @@ nsDocShell::SetUseErrorPages(PRBool aUseErrorPages) { // If mUseErrorPages is set explicitly, stop observing the pref. if (mObserveErrorPages) { - nsCOMPtr prefs(do_QueryInterface(mPrefs)); - if (prefs) { - prefs->RemoveObserver("browser.xul.error_pages.enabled", this); - mObserveErrorPages = PR_FALSE; - } + Preferences::RemoveObserver(this, "browser.xul.error_pages.enabled"); + mObserveErrorPages = PR_FALSE; } mUseErrorPages = aUseErrorPages; return NS_OK; @@ -3919,17 +3906,15 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI *aURI, if (isStsHost) cssClass.AssignLiteral("badStsCert"); - PRBool expert = PR_FALSE; - mPrefs->GetBoolPref("browser.xul.error_pages.expert_bad_cert", - &expert); - if (expert) { + if (Preferences::GetBool( + "browser.xul.error_pages.expert_bad_cert", PR_FALSE)) { cssClass.AssignLiteral("expertBadCert"); } // See if an alternate cert error page is registered - nsXPIDLCString alternateErrorPage; - mPrefs->GetCharPref("security.alternate_certificate_error_page", - getter_Copies(alternateErrorPage)); + nsAdoptingCString alternateErrorPage = + Preferences::GetCString( + "security.alternate_certificate_error_page"); if (alternateErrorPage) errorPage.Assign(alternateErrorPage); } else { @@ -3944,9 +3929,8 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI *aURI, // Malware and phishing detectors may want to use an alternate error // page, but if the pref's not set, we'll fall back on the standard page - nsXPIDLCString alternateErrorPage; - mPrefs->GetCharPref("urlclassifier.alternate_error_page", - getter_Copies(alternateErrorPage)); + nsAdoptingCString alternateErrorPage = + Preferences::GetCString("urlclassifier.alternate_error_page"); if (alternateErrorPage) errorPage.Assign(alternateErrorPage); @@ -4492,7 +4476,7 @@ nsDocShell::InitWindow(nativeWindow parentNativeWindow, NS_IMETHODIMP nsDocShell::Create() { - if (mPrefs) { + if (mCreated) { // We've already been created return NS_OK; } @@ -4500,34 +4484,24 @@ nsDocShell::Create() NS_ASSERTION(mItemType == typeContent || mItemType == typeChrome, "Unexpected item type in docshell"); - nsresult rv = NS_ERROR_FAILURE; - mPrefs = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv); - NS_ENSURE_SUCCESS(rv, rv); + NS_ENSURE_TRUE(Preferences::GetRootBranch(), NS_ERROR_FAILURE); + mCreated = PR_TRUE; - PRBool tmpbool; - - rv = mPrefs->GetBoolPref("browser.frames.enabled", &tmpbool); - if (NS_SUCCEEDED(rv)) - mAllowSubframes = tmpbool; + mAllowSubframes = + Preferences::GetBool("browser.frames.enabled", mAllowSubframes); if (gValidateOrigin == (PRBool)0xffffffff) { // Check pref to see if we should prevent frameset spoofing - rv = mPrefs->GetBoolPref("browser.frame.validate_origin", &tmpbool); - if (NS_SUCCEEDED(rv)) { - gValidateOrigin = tmpbool; - } else { - gValidateOrigin = PR_TRUE; - } + gValidateOrigin = + Preferences::GetBool("browser.frame.validate_origin", PR_TRUE); } // Should we use XUL error pages instead of alerts if possible? - rv = mPrefs->GetBoolPref("browser.xul.error_pages.enabled", &tmpbool); - if (NS_SUCCEEDED(rv)) - mUseErrorPages = tmpbool; + mUseErrorPages = + Preferences::GetBool("browser.xul.error_pages.enabled", mUseErrorPages); - nsCOMPtr prefs(do_QueryInterface(mPrefs, &rv)); - if (NS_SUCCEEDED(rv) && mObserveErrorPages) { - prefs->AddObserver("browser.xul.error_pages.enabled", this, PR_FALSE); + if (mObserveErrorPages) { + Preferences::AddStrongObserver(this, "browser.xul.error_pages.enabled"); } nsCOMPtr serv = do_GetService(NS_OBSERVERSERVICE_CONTRACTID); @@ -4560,11 +4534,8 @@ nsDocShell::Destroy() // Remove our pref observers if (mObserveErrorPages) { - nsCOMPtr prefs(do_QueryInterface(mPrefs)); - if (prefs) { - prefs->RemoveObserver("browser.xul.error_pages.enabled", this); - mObserveErrorPages = PR_FALSE; - } + Preferences::RemoveObserver(this, "browser.xul.error_pages.enabled"); + mObserveErrorPages = PR_FALSE; } // Make sure to blow away our mLoadingURI just in case. No loads @@ -5971,9 +5942,7 @@ nsDocShell::OnStateChange(nsIWebProgress * aProgress, nsIRequest * aRequest, if ((aStateFlags & STATE_RESTORING) == 0) { // Show the progress cursor if the pref is set - PRBool tmpBool = PR_FALSE; - if (NS_SUCCEEDED(mPrefs->GetBoolPref("ui.use_activity_cursor", &tmpBool)) - && tmpBool) { + if (Preferences::GetBool("ui.use_activity_cursor", PR_FALSE)) { nsCOMPtr mainWidget; GetMainWidget(getter_AddRefs(mainWidget)); if (mainWidget) { @@ -5991,9 +5960,7 @@ nsDocShell::OnStateChange(nsIWebProgress * aProgress, nsIRequest * aRequest, mBusyFlags = BUSY_FLAGS_NONE; // Hide the progress cursor if the pref is set - PRBool tmpBool = PR_FALSE; - if (NS_SUCCEEDED(mPrefs->GetBoolPref("ui.use_activity_cursor", &tmpBool)) - && tmpBool) { + if (Preferences::GetBool("ui.use_activity_cursor", PR_FALSE)) { nsCOMPtr mainWidget; GetMainWidget(getter_AddRefs(mainWidget)); if (mainWidget) { @@ -6240,12 +6207,8 @@ nsDocShell::EndPageLoad(nsIWebProgress * aProgress, // First try keyword fixup // if (aStatus == NS_ERROR_UNKNOWN_HOST && mAllowKeywordFixup) { - PRBool keywordsEnabled = PR_FALSE; - - if (mPrefs && - NS_FAILED(mPrefs->GetBoolPref("keyword.enabled", - &keywordsEnabled))) - keywordsEnabled = PR_FALSE; + PRBool keywordsEnabled = + Preferences::GetBool("keyword.enabled", PR_FALSE); nsCAutoString host; url->GetHost(host); @@ -6700,9 +6663,9 @@ nsDocShell::CanSavePresentation(PRUint32 aLoadType, // Don't cache the content viewer if we're in a subframe and the subframe // pref is disabled. - PRBool cacheFrames = PR_FALSE; - mPrefs->GetBoolPref("browser.sessionhistory.cache_subframes", - &cacheFrames); + PRBool cacheFrames = + Preferences::GetBool("browser.sessionhistory.cache_subframes", + PR_FALSE); if (!cacheFrames) { nsCOMPtr root; GetSameTypeParent(getter_AddRefs(root)); @@ -9212,22 +9175,16 @@ nsresult nsDocShell::DoChannelLoad(nsIChannel * aChannel, case LOAD_NORMAL: case LOAD_LINK: // Set cache checking flags - PRInt32 prefSetting; - if (NS_SUCCEEDED - (mPrefs-> - GetIntPref("browser.cache.check_doc_frequency", - &prefSetting))) { - switch (prefSetting) { - case 0: - loadFlags |= nsIRequest::VALIDATE_ONCE_PER_SESSION; - break; - case 1: - loadFlags |= nsIRequest::VALIDATE_ALWAYS; - break; - case 2: - loadFlags |= nsIRequest::VALIDATE_NEVER; - break; - } + switch (Preferences::GetInt("browser.cache.check_doc_frequency", -1)) { + case 0: + loadFlags |= nsIRequest::VALIDATE_ONCE_PER_SESSION; + break; + case 1: + loadFlags |= nsIRequest::VALIDATE_ALWAYS; + break; + case 2: + loadFlags |= nsIRequest::VALIDATE_NEVER; + break; } break; } @@ -9700,11 +9657,8 @@ nsDocShell::AddState(nsIVariant *aData, const nsAString& aTitle, // Check that the state object isn't too long. // Default max length: 640k bytes. - PRInt32 maxStateObjSize = 0xA0000; - if (mPrefs) { - mPrefs->GetIntPref("browser.history.maxStateObjectSize", - &maxStateObjSize); - } + PRInt32 maxStateObjSize = + Preferences::GetInt("browser.history.maxStateObjectSize", 0xA0000); if (maxStateObjSize < 0) { maxStateObjSize = 0; } @@ -11206,11 +11160,8 @@ nsDocShell::Observe(nsISupports *aSubject, const char *aTopic, !nsCRT::strcmp(aData, NS_LITERAL_STRING("browser.xul.error_pages.enabled").get())) { - nsCOMPtr prefs(do_QueryInterface(aSubject, &rv)); - NS_ENSURE_SUCCESS(rv, rv); - PRBool tmpbool; - rv = prefs->GetBoolPref("browser.xul.error_pages.enabled", &tmpbool); + rv = Preferences::GetBool("browser.xul.error_pages.enabled", &tmpbool); if (NS_SUCCEEDED(rv)) mUseErrorPages = tmpbool; diff --git a/docshell/base/nsDocShell.h b/docshell/base/nsDocShell.h index 9dc8f837e11..175d01d1f58 100644 --- a/docshell/base/nsDocShell.h +++ b/docshell/base/nsDocShell.h @@ -44,7 +44,6 @@ #include "nsIDOMNode.h" #include "nsIDOMNodeList.h" #include "nsIContentViewer.h" -#include "nsIPrefBranch.h" #include "nsInterfaceHashtable.h" #include "nsIScriptContext.h" #include "nsITimer.h" @@ -718,7 +717,6 @@ protected: nsCOMPtr mContentViewer; nsCOMPtr mDocumentCharsetInfo; nsCOMPtr mParentWidget; - nsCOMPtr mPrefs; // mCurrentURI should be marked immutable on set if possible. nsCOMPtr mCurrentURI; @@ -791,6 +789,7 @@ protected: PRInt32 mPreviousTransIndex; PRInt32 mLoadedTransIndex; + PRPackedBool mCreated; PRPackedBool mAllowSubframes; PRPackedBool mAllowPlugins; PRPackedBool mAllowJavascript; diff --git a/docshell/build/nsDocShellModule.cpp b/docshell/build/nsDocShellModule.cpp index 9df5c0cee7a..c9b190f0173 100644 --- a/docshell/build/nsDocShellModule.cpp +++ b/docshell/build/nsDocShellModule.cpp @@ -94,6 +94,7 @@ Initialize() static void Shutdown() { + nsSHistory::Shutdown(); nsSHEntry::Shutdown(); gInitialized = PR_FALSE; } diff --git a/docshell/shistory/src/nsSHistory.cpp b/docshell/shistory/src/nsSHistory.cpp index 06499a57447..b391407daa4 100644 --- a/docshell/shistory/src/nsSHistory.cpp +++ b/docshell/shistory/src/nsSHistory.cpp @@ -43,6 +43,7 @@ // Helper Classes #include "nsXPIDLString.h" #include "nsReadableUtils.h" +#include "mozilla/Preferences.h" // Interfaces Needed #include "nsILayoutHistoryState.h" @@ -53,7 +54,6 @@ #include "nsIDocShellTreeNode.h" #include "nsIDocShellLoadInfo.h" #include "nsIServiceManager.h" -#include "nsIPrefService.h" #include "nsIURI.h" #include "nsIContentViewer.h" #include "nsICacheService.h" @@ -68,10 +68,19 @@ #include "nspr.h" #include // for log() +using namespace mozilla; + #define PREF_SHISTORY_SIZE "browser.sessionhistory.max_entries" #define PREF_SHISTORY_MAX_TOTAL_VIEWERS "browser.sessionhistory.max_total_viewers" #define PREF_SHISTORY_OPTIMIZE_EVICTION "browser.sessionhistory.optimize_eviction" +static const char* kObservedPrefs[] = { + PREF_SHISTORY_SIZE, + PREF_SHISTORY_MAX_TOTAL_VIEWERS, + PREF_SHISTORY_OPTIMIZE_EVICTION, + nsnull +}; + static PRInt32 gHistoryMaxSize = 50; // Max viewers allowed per SHistory objects static const PRInt32 gHistoryMaxViewers = 3; @@ -115,6 +124,8 @@ protected: ~nsSHistoryObserver() {} }; +static nsSHistoryObserver* gObserver = nsnull; + NS_IMPL_ISUPPORTS1(nsSHistoryObserver, nsIObserver) NS_IMETHODIMP @@ -122,11 +133,8 @@ nsSHistoryObserver::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *aData) { if (!strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) { - nsCOMPtr prefs = do_QueryInterface(aSubject); - if (prefs) { - nsSHistory::UpdatePrefs(prefs); - nsSHistory::EvictGlobalContentViewer(); - } + nsSHistory::UpdatePrefs(); + nsSHistory::EvictGlobalContentViewer(); } else if (!strcmp(aTopic, NS_CACHESERVICE_EMPTYCACHE_TOPIC_ID) || !strcmp(aTopic, "memory-pressure")) { nsSHistory::EvictAllContentViewersGlobally(); @@ -227,13 +235,12 @@ nsSHistory::CalcMaxTotalViewers() // static void -nsSHistory::UpdatePrefs(nsIPrefBranch *aPrefBranch) +nsSHistory::UpdatePrefs() { - aPrefBranch->GetIntPref(PREF_SHISTORY_SIZE, &gHistoryMaxSize); - aPrefBranch->GetIntPref(PREF_SHISTORY_MAX_TOTAL_VIEWERS, - &sHistoryMaxTotalViewers); - aPrefBranch->GetBoolPref(PREF_SHISTORY_OPTIMIZE_EVICTION, - &gOptimizeEviction); + Preferences::GetInt(PREF_SHISTORY_SIZE, &gHistoryMaxSize); + Preferences::GetInt(PREF_SHISTORY_MAX_TOTAL_VIEWERS, + &sHistoryMaxTotalViewers); + Preferences::GetBool(PREF_SHISTORY_OPTIMIZE_EVICTION, &gOptimizeEviction); // If the pref is negative, that means we calculate how many viewers // we think we should cache, based on total memory if (sHistoryMaxTotalViewers < 0) { @@ -245,52 +252,33 @@ nsSHistory::UpdatePrefs(nsIPrefBranch *aPrefBranch) nsresult nsSHistory::Startup() { - nsCOMPtr prefs = do_GetService(NS_PREFSERVICE_CONTRACTID); - if (prefs) { - nsCOMPtr sesHBranch; - prefs->GetBranch(nsnull, getter_AddRefs(sesHBranch)); - if (sesHBranch) { - UpdatePrefs(sesHBranch); - } + UpdatePrefs(); - // The goal of this is to unbreak users who have inadvertently set their - // session history size to less than the default value. - PRInt32 defaultHistoryMaxSize = 50; - nsCOMPtr defaultBranch; - prefs->GetDefaultBranch(nsnull, getter_AddRefs(defaultBranch)); - if (defaultBranch) { - defaultBranch->GetIntPref(PREF_SHISTORY_SIZE, &defaultHistoryMaxSize); - } + // The goal of this is to unbreak users who have inadvertently set their + // session history size to less than the default value. + PRInt32 defaultHistoryMaxSize = + Preferences::GetDefaultInt(PREF_SHISTORY_SIZE, 50); + if (gHistoryMaxSize < defaultHistoryMaxSize) { + gHistoryMaxSize = defaultHistoryMaxSize; + } + + // Allow the user to override the max total number of cached viewers, + // but keep the per SHistory cached viewer limit constant + if (!gObserver) { + gObserver = new nsSHistoryObserver(); + NS_ADDREF(gObserver); + Preferences::AddStrongObservers(gObserver, kObservedPrefs); - if (gHistoryMaxSize < defaultHistoryMaxSize) { - gHistoryMaxSize = defaultHistoryMaxSize; - } - - // Allow the user to override the max total number of cached viewers, - // but keep the per SHistory cached viewer limit constant - nsCOMPtr branch = do_QueryInterface(sesHBranch); - if (branch) { - nsSHistoryObserver* obs = new nsSHistoryObserver(); - if (!obs) { - return NS_ERROR_OUT_OF_MEMORY; - } - branch->AddObserver(PREF_SHISTORY_SIZE, obs, PR_FALSE); - branch->AddObserver(PREF_SHISTORY_MAX_TOTAL_VIEWERS, - obs, PR_FALSE); - branch->AddObserver(PREF_SHISTORY_OPTIMIZE_EVICTION, - obs, PR_FALSE); + nsCOMPtr obsSvc = + mozilla::services::GetObserverService(); + if (obsSvc) { + // Observe empty-cache notifications so tahat clearing the disk/memory + // cache will also evict all content viewers. + obsSvc->AddObserver(gObserver, + NS_CACHESERVICE_EMPTYCACHE_TOPIC_ID, PR_FALSE); - nsCOMPtr obsSvc = - mozilla::services::GetObserverService(); - if (obsSvc) { - // Observe empty-cache notifications so tahat clearing the disk/memory - // cache will also evict all content viewers. - obsSvc->AddObserver(obs, - NS_CACHESERVICE_EMPTYCACHE_TOPIC_ID, PR_FALSE); - - // Same for memory-pressure notifications - obsSvc->AddObserver(obs, "memory-pressure", PR_FALSE); - } + // Same for memory-pressure notifications + obsSvc->AddObserver(gObserver, "memory-pressure", PR_FALSE); } } @@ -299,6 +287,22 @@ nsSHistory::Startup() return NS_OK; } +// static +void +nsSHistory::Shutdown() +{ + if (gObserver) { + Preferences::RemoveObservers(gObserver, kObservedPrefs); + nsCOMPtr obsSvc = + mozilla::services::GetObserverService(); + if (obsSvc) { + obsSvc->RemoveObserver(gObserver, NS_CACHESERVICE_EMPTYCACHE_TOPIC_ID); + obsSvc->RemoveObserver(gObserver, "memory-pressure"); + } + NS_RELEASE(gObserver); + } +} + /* Add an entry to the History list at mIndex and * increment the index to point to the new entry */ diff --git a/docshell/shistory/src/nsSHistory.h b/docshell/shistory/src/nsSHistory.h index 94a9650ef73..01cdf465454 100644 --- a/docshell/shistory/src/nsSHistory.h +++ b/docshell/shistory/src/nsSHistory.h @@ -53,7 +53,6 @@ #include "nsISHistoryListener.h" #include "nsIHistoryEntry.h" #include "nsIObserver.h" -#include "nsIPrefBranch2.h" // Needed to maintain global list of all SHistory objects #include "prclist.h" @@ -76,7 +75,8 @@ public: // One time initialization method called upon docshell module construction static nsresult Startup(); - static void UpdatePrefs(nsIPrefBranch *aPrefBranch); + static void Shutdown(); + static void UpdatePrefs(); // Max number of total cached content viewers. If the pref // browser.sessionhistory.max_total_viewers is negative, then diff --git a/dom/base/nsJSTimeoutHandler.cpp b/dom/base/nsJSTimeoutHandler.cpp index a7adb74cd63..cca7ec56920 100644 --- a/dom/base/nsJSTimeoutHandler.cpp +++ b/dom/base/nsJSTimeoutHandler.cpp @@ -142,13 +142,12 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsJSScriptTimeoutHandler) } } } - cb.DescribeNode(RefCounted, tmp->mRefCnt.get(), - sizeof(nsJSScriptTimeoutHandler), foo.get()); + cb.DescribeRefCountedNode(tmp->mRefCnt.get(), + sizeof(nsJSScriptTimeoutHandler), foo.get()); } else { - cb.DescribeNode(RefCounted, tmp->mRefCnt.get(), - sizeof(nsJSScriptTimeoutHandler), - "nsJSScriptTimeoutHandler"); + NS_IMPL_CYCLE_COLLECTION_DESCRIBE(nsJSScriptTimeoutHandler, + tmp->mRefCnt.get()) } NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mContext) diff --git a/editor/libeditor/html/nsHTMLEditor.cpp b/editor/libeditor/html/nsHTMLEditor.cpp index 0a16671b164..3f36166e9df 100644 --- a/editor/libeditor/html/nsHTMLEditor.cpp +++ b/editor/libeditor/html/nsHTMLEditor.cpp @@ -168,11 +168,6 @@ nsHTMLEditor::~nsHTMLEditor() // free any default style propItems RemoveAllDefaultProperties(); - while (mStyleSheetURLs.Length()) - { - RemoveOverrideStyleSheet(mStyleSheetURLs[0]); - } - if (mLinkHandler && mDocWeak) { nsCOMPtr ps = GetPresShell(); @@ -359,6 +354,11 @@ nsHTMLEditor::PreDestroy(PRBool aDestroyingFrames) document->RemoveMutationObserver(this); } + while (mStyleSheetURLs.Length()) + { + RemoveOverrideStyleSheet(mStyleSheetURLs[0]); + } + return nsPlaintextEditor::PreDestroy(aDestroyingFrames); } diff --git a/gfx/2d/2D.h b/gfx/2d/2D.h new file mode 100644 index 00000000000..da001346e82 --- /dev/null +++ b/gfx/2d/2D.h @@ -0,0 +1,668 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.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/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Corporation code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Bas Schouten + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef _MOZILLA_GFX_2D_H +#define _MOZILLA_GFX_2D_H + +#include "Point.h" +#include "Rect.h" +#include "Matrix.h" + +// This RefPtr class isn't ideal for usage in Azure, as it doesn't allow T** +// outparams using the &-operator. But it will have to do as there's no easy +// solution. +#include "mozilla/RefPtr.h" + +struct _cairo_surface; +typedef _cairo_surface cairo_surface_t; + +struct ID3D10Device1; +struct ID3D10Texture2D; + +namespace mozilla { +namespace gfx { + +class SourceSurface; +class DataSourceSurface; +class DrawTarget; + +struct NativeSurface { + NativeSurfaceType mType; + SurfaceFormat mFormat; + void *mSurface; +}; + +struct NativeFont { + NativeFontType mType; + void *mFont; +}; + +/* + * This structure is used to send draw options that are universal to all drawing + * operations. It consists of the following: + * + * mAlpha - Alpha value by which the mask generated by this operation is + * multiplied. + * mCompositionOp - The operator that indicates how the source and destination + * patterns are blended. + * mAntiAliasMode - The AntiAlias mode used for this drawing operation. + * mSnapping - Whether this operation is snapped to pixel boundaries. + */ +struct DrawOptions { + DrawOptions(Float aAlpha = 1.0f, + CompositionOp aCompositionOp = OP_OVER, + AntialiasMode aAntialiasMode = AA_GRAY, + Snapping aSnapping = SNAP_NONE) + : mAlpha(aAlpha) + , mCompositionOp(aCompositionOp) + , mAntialiasMode(aAntialiasMode) + , mSnapping(aSnapping) + {} + + Float mAlpha; + CompositionOp mCompositionOp : 8; + AntialiasMode mAntialiasMode : 2; + Snapping mSnapping : 1; +}; + +/* + * This structure is used to send stroke options that are used in stroking + * operations. It consists of the following: + * + * mLineWidth - Width of the stroke in userspace. + * mLineJoin - Join style used for joining lines. + * mLineCap - Cap style used for capping lines. + * mMiterLimit - Miter limit in units of linewidth + */ +struct StrokeOptions { + StrokeOptions(Float aLineWidth = 1.0f, + JoinStyle aLineJoin = JOIN_MITER_OR_BEVEL, + CapStyle aLineCap = CAP_BUTT, + Float aMiterLimit = 10.0f) + : mLineWidth(aLineWidth) + , mMiterLimit(aMiterLimit) + , mLineJoin(aLineJoin) + , mLineCap(aLineCap) + {} + + Float mLineWidth; + Float mMiterLimit; + JoinStyle mLineJoin : 4; + CapStyle mLineCap : 3; +}; + +/* + * This structure supplies additional options for calls to DrawSurface. + * + * mFilter - Filter used when resampling source surface region to the + * destination region. + */ +struct DrawSurfaceOptions { + DrawSurfaceOptions(Filter aFilter = FILTER_LINEAR) + : mFilter(aFilter) + { } + + Filter mFilter : 3; +}; + +/* + * This class is used to store gradient stops, it can only be used with a + * matching DrawTarget. Not adhering to this condition will make a draw call + * fail. + */ +class GradientStops : public RefCounted +{ +public: + virtual ~GradientStops() {} + + virtual BackendType GetBackendType() const = 0; + +protected: + GradientStops() {} +}; + +/* + * This is the base class for 'patterns'. Patterns describe the pixels used as + * the source for a masked composition operation that is done by the different + * drawing commands. These objects are not backend specific, however for + * example the gradient stops on a gradient pattern can be backend specific. + */ +class Pattern +{ +public: + virtual ~Pattern() {} + + virtual PatternType GetType() const = 0; + +protected: + Pattern() {} +}; + +class ColorPattern : public Pattern +{ +public: + ColorPattern(const Color &aColor) + : mColor(aColor) + {} + + virtual PatternType GetType() const { return PATTERN_COLOR; } + + Color mColor; +}; + +/* + * This class is used for Linear Gradient Patterns, the gradient stops are + * stored in a separate object and are backend dependent. This class itself + * may be used on the stack. + */ +class LinearGradientPattern : public Pattern +{ +public: + /* + * aBegin Start of the linear gradient + * aEnd End of the linear gradient + * aStops GradientStops object for this gradient, this should match the + * backend type of the draw target this pattern will be used with. + */ + LinearGradientPattern(const Point &aBegin, + const Point &aEnd, + GradientStops *aStops) + : mBegin(aBegin) + , mEnd(aEnd) + , mStops(aStops) + { + } + + virtual PatternType GetType() const { return PATTERN_LINEAR_GRADIENT; } + + Point mBegin; + Point mEnd; + RefPtr mStops; +}; + +/* + * This class is used for Radial Gradient Patterns, the gradient stops are + * stored in a separate object and are backend dependent. This class itself + * may be used on the stack. + */ +class RadialGradientPattern : public Pattern +{ +public: + /* + * aBegin Start of the linear gradient + * aEnd End of the linear gradient + * aStops GradientStops object for this gradient, this should match the + * backend type of the draw target this pattern will be used with. + */ + RadialGradientPattern(const Point &aCenter, + const Point &aOrigin, + Float aRadius, + GradientStops *aStops) + : mCenter(aCenter) + , mOrigin(aOrigin) + , mRadius(aRadius) + , mStops(aStops) + { + } + + virtual PatternType GetType() const { return PATTERN_RADIAL_GRADIENT; } + + Point mCenter; + Point mOrigin; + Float mRadius; + RefPtr mStops; +}; + +/* + * This class is used for Surface Patterns, they wrap a surface and a + * repetition mode for the surface. This may be used on the stack. + */ +class SurfacePattern : public Pattern +{ +public: + SurfacePattern(SourceSurface *aSourceSurface, ExtendMode aExtendMode) + : mSurface(aSourceSurface) + , mExtendMode(aExtendMode) + {} + + virtual PatternType GetType() const { return PATTERN_SURFACE; } + + RefPtr mSurface; + ExtendMode mExtendMode; + Filter mFilter; +}; + +/* + * This is the base class for source surfaces. These objects are surfaces + * which may be used as a source in a SurfacePattern of a DrawSurface call. + * They cannot be drawn to directly. + */ +class SourceSurface : public RefCounted +{ +public: + virtual ~SourceSurface() {} + + virtual SurfaceType GetType() const = 0; + virtual IntSize GetSize() const = 0; + virtual SurfaceFormat GetFormat() const = 0; + + /* + * This function will get a DataSourceSurface for this surface, a + * DataSourceSurface's data can be accessed directly. + */ + virtual TemporaryRef GetDataSurface() = 0; +}; + +class DataSourceSurface : public SourceSurface +{ +public: + /* Get the raw bitmap data of the surface */ + virtual unsigned char *GetData() = 0; + /* + * Stride of the surface, distance in bytes between the start of the image + * data belonging to row y and row y+1. This may be negative. + */ + virtual int32_t Stride() = 0; + + virtual TemporaryRef GetDataSurface() { RefPtr temp = this; return temp.forget(); } +}; + +/* This is an abstract object that accepts path segments. */ +class PathSink : public RefCounted +{ +public: + virtual ~PathSink() {} + + /* Move the current point in the path, any figure currently being drawn will + * be considered closed during fill operations, however when stroking the + * closing line segment will not be drawn. + */ + virtual void MoveTo(const Point &aPoint) = 0; + /* Add a linesegment to the current figure */ + virtual void LineTo(const Point &aPoint) = 0; + /* Add a cubic bezier curve to the current figure */ + virtual void BezierTo(const Point &aCP1, + const Point &aCP2, + const Point &aCP3) = 0; + /* Add a quadratic bezier curve to the current figure */ + virtual void QuadraticBezierTo(const Point &aCP1, + const Point &aCP2) = 0; + /* Close the current figure, this will essentially generate a line segment + * from the current point to the starting point for the current figure + */ + virtual void Close() = 0; + /* Add an arc to the current figure */ + virtual void Arc(const Point &aOrigin, float aRadius, float aStartAngle, + float aEndAngle, bool aAntiClockwise = false) = 0; + /* Point the current subpath is at - or where the next subpath will start + * if there is no active subpath. + */ + virtual Point CurrentPoint() const = 0; +}; + +class PathBuilder; + +/* The path class is used to create (sets of) figures of any shape that can be + * filled or stroked to a DrawTarget + */ +class Path : public RefCounted +{ +public: + virtual ~Path() {} + + virtual BackendType GetBackendType() const = 0; + + /* This returns a PathBuilder object that contains a copy of the contents of + * this path and is still writable. + */ + virtual TemporaryRef CopyToBuilder(FillRule aFillRule = FILL_WINDING) const = 0; + virtual TemporaryRef TransformedCopyToBuilder(const Matrix &aTransform, + FillRule aFillRule = FILL_WINDING) const = 0; + + /* This function checks if a point lies within a path. It allows passing a + * transform that will transform the path to the coordinate space in which + * aPoint is given. + */ + virtual bool ContainsPoint(const Point &aPoint, const Matrix &aTransform) const = 0; + + /* This gets the fillrule this path's builder was created with. This is not + * mutable. + */ + virtual FillRule GetFillRule() const = 0; +}; + +/* The PathBuilder class allows path creation. Once finish is called on the + * pathbuilder it may no longer be written to. + */ +class PathBuilder : public PathSink +{ +public: + /* Finish writing to the path and return a Path object that can be used for + * drawing. Future use of the builder results in a crash! + */ + virtual TemporaryRef Finish() = 0; +}; + +struct Glyph +{ + uint32_t mIndex; + Point mPosition; +}; + +/* This class functions as a glyph buffer that can be drawn to a DrawTarget. + * XXX - This should probably contain the guts of gfxTextRun in the future as + * roc suggested. But for now it's a simple container for a glyph vector. + */ +struct GlyphBuffer +{ + // A pointer to a buffer of glyphs. Managed by the caller. + const Glyph *mGlyphs; + // Number of glyphs mGlyphs points to. + uint32_t mNumGlyphs; +}; + +/* This class is an abstraction of a backend/platform specific font object + * at a particular size. It is passed into text drawing calls to describe + * the font used for the drawing call. + */ +class ScaledFont : public RefCounted +{ +public: + virtual ~ScaledFont() {} + + virtual FontType GetType() const = 0; + + /* This allows getting a path that describes the outline of a set of glyphs. + * A target is passed in so that the guarantee is made the returned path + * can be used with any DrawTarget that has the same backend as the one + * passed in. + */ + virtual TemporaryRef GetPathForGlyphs(const GlyphBuffer &aBuffer, const DrawTarget *aTarget) = 0; + +protected: + ScaledFont() {} +}; + +/* This is the main class used for all the drawing. It is created through the + * factory and accepts drawing commands. The results of drawing to a target + * may be used either through a Snapshot or by flushing the target and directly + * accessing the backing store a DrawTarget was created with. + */ +class DrawTarget : public RefCounted +{ +public: + DrawTarget() : mTransformDirty(false) {} + virtual ~DrawTarget() {} + + virtual BackendType GetType() const = 0; + virtual TemporaryRef Snapshot() = 0; + virtual IntSize GetSize() = 0; + + /* Ensure that the DrawTarget backend has flushed all drawing operations to + * this draw target. This must be called before using the backing surface of + * this draw target outside of GFX 2D code. + */ + virtual void Flush() = 0; + + /* + * Draw a surface to the draw target. Possibly doing partial drawing or + * applying scaling. No sampling happens outside the source. + * + * aSurface Source surface to draw + * aDest Destination rectangle that this drawing operation should draw to + * aSource Source rectangle in aSurface coordinates, this area of aSurface + * will be stretched to the size of aDest. + * aOptions General draw options that are applied to the operation + * aSurfOptions DrawSurface options that are applied + */ + virtual void DrawSurface(SourceSurface *aSurface, + const Rect &aDest, + const Rect &aSource, + const DrawSurfaceOptions &aSurfOptions = DrawSurfaceOptions(), + const DrawOptions &aOptions = DrawOptions()) = 0; + + /* + * Blend a surface to the draw target with a shadow. The shadow is drawn as a + * gaussian blur using a specified sigma. + * NOTE: This function works in device space! + * + * aSurface Source surface to draw. + * aDest Destination point that this drawing operation should draw to. + * aColor Color of the drawn shadow + * aOffset Offset of the shadow + * aSigma Sigma used for the guassian filter kernel + */ + virtual void DrawSurfaceWithShadow(SourceSurface *aSurface, + const Point &aDest, + const Color &aColor, + const Point &aOffset, + Float aSigma) = 0; + + /* + * Clear a rectangle on the draw target to transparent black. This will + * respect the clipping region and transform. + * + * aRect Rectangle to clear + */ + virtual void ClearRect(const Rect &aRect) = 0; + + /* + * This is essentially a 'memcpy' between two surfaces. It moves a pixel + * aligned area from the source surface unscaled directly onto the + * drawtarget. This ignores both transform and clip. + * + * aSurface Surface to copy from + * aSourceRect Source rectangle to be copied + * aDest Destination point to copy the surface to + */ + virtual void CopySurface(SourceSurface *aSurface, + const IntRect &aSourceRect, + const IntPoint &aDestination) = 0; + + /* + * Fill a rectangle on the DrawTarget with a certain source pattern. + * + * aRect Rectangle that forms the mask of this filling operation + * aPattern Pattern that forms the source of this filling operation + * aOptions Options that are applied to this operation + */ + virtual void FillRect(const Rect &aRect, + const Pattern &aPattern, + const DrawOptions &aOptions = DrawOptions()) = 0; + + /* + * Stroke a rectangle on the DrawTarget with a certain source pattern. + * + * aRect Rectangle that forms the mask of this stroking operation + * aPattern Pattern that forms the source of this stroking operation + * aOptions Options that are applied to this operation + */ + virtual void StrokeRect(const Rect &aRect, + const Pattern &aPattern, + const StrokeOptions &aStrokeOptions = StrokeOptions(), + const DrawOptions &aOptions = DrawOptions()) = 0; + + /* + * Stroke a line on the DrawTarget with a certain source pattern. + * + * aStart Starting point of the line + * aEnd End point of the line + * aPattern Pattern that forms the source of this stroking operation + * aOptions Options that are applied to this operation + */ + virtual void StrokeLine(const Point &aStart, + const Point &aEnd, + const Pattern &aPattern, + const StrokeOptions &aStrokeOptions = StrokeOptions(), + const DrawOptions &aOptions = DrawOptions()) = 0; + + /* + * Stroke a path on the draw target with a certain source pattern. + * + * aPath Path that is to be stroked + * aPattern Pattern that should be used for the stroke + * aStrokeOptions Stroke options used for this operation + * aOptions Draw options used for this operation + */ + virtual void Stroke(const Path *aPath, + const Pattern &aPattern, + const StrokeOptions &aStrokeOptions = StrokeOptions(), + const DrawOptions &aOptions = DrawOptions()) = 0; + + /* + * Fill a path on the draw target with a certain source pattern. + * + * aPath Path that is to be filled + * aPattern Pattern that should be used for the fill + * aOptions Draw options used for this operation + */ + virtual void Fill(const Path *aPath, + const Pattern &aPattern, + const DrawOptions &aOptions = DrawOptions()) = 0; + + /* + * Fill a series of clyphs on the draw target with a certain source pattern. + */ + virtual void FillGlyphs(ScaledFont *aFont, + const GlyphBuffer &aBuffer, + const Pattern &aPattern, + const DrawOptions &aOptions = DrawOptions()) = 0; + + /* + * Push a clip to the DrawTarget. + * + * aPath The path to clip to + */ + virtual void PushClip(const Path *aPath) = 0; + + /* Pop a clip from the DrawTarget. A pop without a corresponding push will + * be ignored. + */ + virtual void PopClip() = 0; + + /* + * Create a SourceSurface optimized for use with this DrawTarget for + * existing bitmap data in memory. + */ + virtual TemporaryRef CreateSourceSurfaceFromData(unsigned char *aData, + const IntSize &aSize, + int32_t aStride, + SurfaceFormat aFormat) const = 0; + + /* + * Create a SourceSurface optimized for use with this DrawTarget from + * an arbitrary other SourceSurface. This may return aSourceSurface or some + * other existing surface. + */ + virtual TemporaryRef OptimizeSourceSurface(SourceSurface *aSurface) const = 0; + + /* + * Create a SourceSurface for a type of NativeSurface. This may fail if the + * draw target does not know how to deal with the type of NativeSurface passed + * in. + */ + virtual TemporaryRef + CreateSourceSurfaceFromNativeSurface(const NativeSurface &aSurface) const = 0; + + /* + * Create a DrawTarget whose snapshot is optimized for use with this DrawTarget. + */ + virtual TemporaryRef + CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFormat) const = 0; + + /* + * Create a path builder with the specified fillmode. + */ + virtual TemporaryRef CreatePathBuilder(FillRule aFillRule = FILL_WINDING) const = 0; + + /* + * Create a GradientStops object that holds information about a set of + * gradient stops, this object is required for linear or radial gradient + * patterns to represent the color stops in the gradient. + * + * aStops An array of gradient stops + * aNumStops Number of stops in the array aStops + */ + virtual TemporaryRef CreateGradientStops(GradientStop *aStops, uint32_t aNumStops) const = 0; + + const Matrix &GetTransform() const { return mTransform; } + + /* + * Set a transform on the surface, this transform is applied at drawing time + * to both the mask and source of the operation. + */ + virtual void SetTransform(const Matrix &aTransform) + { mTransform = aTransform; mTransformDirty = true; } + + SurfaceFormat GetFormat() { return mFormat; } + + /* Tries to get a native surface for a DrawTarget, this may fail if the + * draw target cannot convert to this surface type. + */ + virtual void *GetNativeSurface(NativeSurfaceType aType) = 0; + +protected: + Matrix mTransform; + bool mTransformDirty : 1; + + SurfaceFormat mFormat; +}; + +class Factory +{ +public: +#ifdef USE_CAIRO + static TemporaryRef CreateDrawTargetForCairoSurface(cairo_surface_t* aSurface); +#endif + + static TemporaryRef CreateDrawTarget(BackendType aBackend, const IntSize &aSize, SurfaceFormat aFormat); + static TemporaryRef CreateScaledFontForNativeFont(const NativeFont &aNativeFont, Float aSize); + +#ifdef WIN32 + static TemporaryRef CreateDrawTargetForD3D10Texture(ID3D10Texture2D *aTexture, SurfaceFormat aFormat); + static void SetDirect3D10Device(ID3D10Device1 *aDevice); + static ID3D10Device1 *GetDirect3D10Device(); + +private: + static ID3D10Device1 *mD3D10Device; +#endif +}; + +} +} + +#endif // _MOZILLA_GFX_2D_H diff --git a/gfx/src/BaseMargin.h b/gfx/2d/BaseMargin.h similarity index 93% rename from gfx/src/BaseMargin.h rename to gfx/2d/BaseMargin.h index a25089473e0..1b99482cce7 100644 --- a/gfx/src/BaseMargin.h +++ b/gfx/2d/BaseMargin.h @@ -35,12 +35,13 @@ * * ***** END LICENSE BLOCK ***** */ -#ifndef MOZILLA_BASEMARGIN_H_ -#define MOZILLA_BASEMARGIN_H_ +#ifndef MOZILLA_GFX_BASEMARGIN_H_ +#define MOZILLA_GFX_BASEMARGIN_H_ -#include "gfxCore.h" +#include "Types.h" namespace mozilla { +namespace gfx { /** * Do not use this class directly. Subclass it, pass that subclass as the @@ -68,12 +69,10 @@ struct BaseMargin { T TopBottom() const { return top + bottom; } T& Side(SideT aSide) { - NS_PRECONDITION(aSide <= NS_SIDE_LEFT, "Out of range side"); // This is ugly! return *(&top + aSide); } T Side(SideT aSide) const { - NS_PRECONDITION(aSide <= NS_SIDE_LEFT, "Out of range side"); // This is ugly! return *(&top + aSide); } @@ -104,6 +103,7 @@ struct BaseMargin { } }; +} } -#endif /* MOZILLA_BASEMARGIN_H_ */ +#endif /* MOZILLA_GFX_BASEMARGIN_H_ */ diff --git a/gfx/src/BasePoint.h b/gfx/2d/BasePoint.h similarity index 96% rename from gfx/src/BasePoint.h rename to gfx/2d/BasePoint.h index 21cb0b64251..08f695fd262 100644 --- a/gfx/src/BasePoint.h +++ b/gfx/2d/BasePoint.h @@ -35,10 +35,11 @@ * * ***** END LICENSE BLOCK ***** */ -#ifndef MOZILLA_BASEPOINT_H_ -#define MOZILLA_BASEPOINT_H_ +#ifndef MOZILLA_GFX_BASEPOINT_H_ +#define MOZILLA_GFX_BASEPOINT_H_ namespace mozilla { +namespace gfx { /** * Do not use this class directly. Subclass it, pass that subclass as the @@ -95,6 +96,7 @@ struct BasePoint { } }; +} } -#endif /* MOZILLA_BASEPOINT_H_ */ +#endif /* MOZILLA_GFX_BASEPOINT_H_ */ diff --git a/gfx/src/BaseRect.h b/gfx/2d/BaseRect.h similarity index 88% rename from gfx/src/BaseRect.h rename to gfx/2d/BaseRect.h index cb3be231de2..9359f5a7f2f 100644 --- a/gfx/src/BaseRect.h +++ b/gfx/2d/BaseRect.h @@ -35,12 +35,27 @@ * * ***** END LICENSE BLOCK ***** */ -#ifndef MOZILLA_BASERECT_H_ -#define MOZILLA_BASERECT_H_ +#ifndef MOZILLA_GFX_BASERECT_H_ +#define MOZILLA_GFX_BASERECT_H_ -#include "nsAlgorithm.h" +#include namespace mozilla { +namespace gfx { + +// XXX - conflicts with exceptions on 10.6. Define our own gfx_min/gfx_max +// functions here. Avoid min/max to avoid conflicts with existing #defines on windows. +template +T gfx_min(T aVal1, T aVal2) +{ + return (aVal1 < aVal2) ? aVal1 : aVal2; +} + +template +T gfx_max(T aVal1, T aVal2) +{ + return (aVal1 > aVal2) ? aVal1 : aVal2; +} /** * Rectangles have two interpretations: a set of (zero-size) points, @@ -113,15 +128,15 @@ struct BaseRect { } // Returns the rectangle containing the intersection of the points // (including edges) of *this and aRect. If there are no points in that - // intersection, returns an empty rectangle with x/y set to the max of the x/y + // intersection, returns an empty rectangle with x/y set to the gfx_max of the x/y // of *this and aRect. Sub Intersect(const Sub& aRect) const { Sub result; - result.x = NS_MAX(x, aRect.x); - result.y = NS_MAX(y, aRect.y); - result.width = NS_MIN(XMost(), aRect.XMost()) - result.x; - result.height = NS_MIN(YMost(), aRect.YMost()) - result.y; + result.x = gfx_max(x, aRect.x); + result.y = gfx_max(y, aRect.y); + result.width = gfx_min(XMost(), aRect.XMost()) - result.x; + result.height = gfx_min(YMost(), aRect.YMost()) - result.y; if (result.width < 0 || result.height < 0) { result.SizeTo(0, 0); } @@ -129,7 +144,7 @@ struct BaseRect { } // Sets *this to be the rectangle containing the intersection of the points // (including edges) of *this and aRect. If there are no points in that - // intersection, sets *this to be an empty rectangle with x/y set to the max + // intersection, sets *this to be an empty rectangle with x/y set to the gfx_max // of the x/y of *this and aRect. // // 'this' can be the same object as either aRect1 or aRect2 @@ -159,10 +174,10 @@ struct BaseRect { Sub UnionEdges(const Sub& aRect) const { Sub result; - result.x = NS_MIN(x, aRect.x); - result.y = NS_MIN(y, aRect.y); - result.width = NS_MAX(XMost(), aRect.XMost()) - result.x; - result.height = NS_MAX(YMost(), aRect.YMost()) - result.y; + result.x = gfx_min(x, aRect.x); + result.y = gfx_min(y, aRect.y); + result.width = gfx_max(XMost(), aRect.XMost()) - result.x; + result.height = gfx_max(YMost(), aRect.YMost()) - result.y; return result; } // Computes the smallest rectangle that contains both the area of both @@ -223,15 +238,15 @@ struct BaseRect { { x += aDx; y += aDy; - width = NS_MAX(T(0), width - 2 * aDx); - height = NS_MAX(T(0), height - 2 * aDy); + width = gfx_max(T(0), width - 2 * aDx); + height = gfx_max(T(0), height - 2 * aDy); } void Deflate(const Margin& aMargin) { x += aMargin.left; y += aMargin.top; - width = NS_MAX(T(0), width - aMargin.LeftRight()); - height = NS_MAX(T(0), height - aMargin.TopBottom()); + width = gfx_max(T(0), width - aMargin.LeftRight()); + height = gfx_max(T(0), height - aMargin.TopBottom()); } void Deflate(const SizeT& aSize) { Deflate(aSize.width, aSize.height); } @@ -303,10 +318,10 @@ struct BaseRect { // Note: this can turn an empty rectangle into a non-empty rectangle void ScaleRoundOut(double aXScale, double aYScale) { - T right = static_cast(NS_ceil(double(XMost()) * aXScale)); - T bottom = static_cast(NS_ceil(double(YMost()) * aYScale)); - x = static_cast(NS_floor(double(x) * aXScale)); - y = static_cast(NS_floor(double(y) * aYScale)); + T right = static_cast(ceil(double(XMost()) * aXScale)); + T bottom = static_cast(ceil(double(YMost()) * aYScale)); + x = static_cast(floor(double(x) * aXScale)); + y = static_cast(floor(double(y) * aYScale)); width = right - x; height = bottom - y; } @@ -318,12 +333,12 @@ struct BaseRect { // unrounded result. void ScaleRoundIn(double aXScale, double aYScale) { - T right = static_cast(NS_floor(double(XMost()) * aXScale)); - T bottom = static_cast(NS_floor(double(YMost()) * aYScale)); - x = static_cast(NS_ceil(double(x) * aXScale)); - y = static_cast(NS_ceil(double(y) * aYScale)); - width = NS_MAX(0, right - x); - height = NS_MAX(0, bottom - y); + T right = static_cast(floor(double(XMost()) * aXScale)); + T bottom = static_cast(floor(double(YMost()) * aYScale)); + x = static_cast(ceil(double(x) * aXScale)); + y = static_cast(ceil(double(y) * aYScale)); + width = gfx_max(0, right - x); + height = gfx_max(0, bottom - y); } // Scale 'this' by 1/aScale, converting coordinates to integers so that the result is // the smallest integer-coordinate rectangle containing the unrounded result. @@ -350,6 +365,7 @@ private: bool operator!=(const Sub& aRect) const { return false; } }; +} } -#endif /* MOZILLA_BASERECT_H_ */ +#endif /* MOZILLA_GFX_BASERECT_H_ */ diff --git a/gfx/src/BaseSize.h b/gfx/2d/BaseSize.h similarity index 96% rename from gfx/src/BaseSize.h rename to gfx/2d/BaseSize.h index f995b337261..0751887af53 100644 --- a/gfx/src/BaseSize.h +++ b/gfx/2d/BaseSize.h @@ -35,10 +35,11 @@ * * ***** END LICENSE BLOCK ***** */ -#ifndef MOZILLA_BASESIZE_H_ -#define MOZILLA_BASESIZE_H_ +#ifndef MOZILLA_GFX_BASESIZE_H_ +#define MOZILLA_GFX_BASESIZE_H_ namespace mozilla { +namespace gfx { /** * Do not use this class directly. Subclass it, pass that subclass as the @@ -96,6 +97,7 @@ struct BaseSize { } }; +} } -#endif /* MOZILLA_BASESIZE_H_ */ +#endif /* MOZILLA_GFX_BASESIZE_H_ */ diff --git a/gfx/2d/DrawTargetCG.cpp b/gfx/2d/DrawTargetCG.cpp new file mode 100644 index 00000000000..6e7d91e36b3 --- /dev/null +++ b/gfx/2d/DrawTargetCG.cpp @@ -0,0 +1,184 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.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/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Corporation code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Bas Schouten + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +#include "DrawTargetCG.h" +#include "SourceSurfaceCG.h" +#include "Rect.h" + +//CG_EXTERN void CGContextSetCompositeOperation (CGContextRef, PrivateCGCompositeMode); + +namespace mozilla { +namespace gfx { + +static CGRect RectToCGRect(Rect r) +{ + return CGRectMake(r.x, r.y, r.width, r.height); +} + +CGBlendMode ToBlendMode(CompositionOp op) +{ + CGBlendMode mode; + switch (op) { + case OP_OVER: + mode = kCGBlendModeNormal; + break; + case OP_SOURCE: + mode = kCGBlendModeCopy; + break; + case OP_CLEAR: + mode = kCGBlendModeClear; + break; + case OP_ADD: + mode = kCGBlendModePlusLighter; + break; + case OP_ATOP: + mode = kCGBlendModeSourceAtop; + break; + default: + mode = kCGBlendModeNormal; + } + return mode; +} + + + +DrawTargetCG::DrawTargetCG() +{ +} + +DrawTargetCG::~DrawTargetCG() +{ +} + +TemporaryRef +DrawTargetCG::Snapshot() +{ + return NULL; +} + +TemporaryRef +DrawTargetCG::CreateSourceSurfaceFromData(unsigned char *aData, + const IntSize &aSize, + int32_t aStride, + SurfaceFormat aFormat) const +{ + RefPtr newSurf = new SourceSurfaceCG(); + + if (!newSurf->InitFromData(aData, aSize, aStride, aFormat)) { + return NULL; + } + + return newSurf; +} + +TemporaryRef +DrawTargetCG::OptimizeSourceSurface(SourceSurface *aSurface) const +{ + return NULL; +} + +void +DrawTargetCG::DrawSurface(SourceSurface *aSurface, + const Rect &aDest, + const Rect &aSource, + const DrawOptions &aOptions, + const DrawSurfaceOptions &aSurfOptions) +{ + CGImageRef image; + CGImageRef subimage = NULL; + if (aSurface->GetType() == COREGRAPHICS_IMAGE) { + image = static_cast(aSurface)->GetImage(); + /* we have two options here: + * - create a subimage -- this is slower + * - fancy things with clip and different dest rects */ + { + subimage = CGImageCreateWithImageInRect(image, RectToCGRect(aSource)); + image = subimage; + } + + CGContextDrawImage(mCg, RectToCGRect(aDest), image); + + CGImageRelease(subimage); + } +} + +void +DrawTargetCG::FillRect(const Rect &aRect, + const Pattern &aPattern, + const DrawOptions &aOptions) +{ + //XXX: it would be nice to hang a CGColor off of the pattern here + if (aPattern.GetType() == COLOR) { + Color color = static_cast(&aPattern)->mColor; + //XXX: the m prefixes are painful here + CGContextSetRGBFillColor(mCg, color.mR, color.mG, color.mB, color.mA); + } + + CGContextSetBlendMode(mCg, ToBlendMode(aOptions.mCompositionOp)); + CGContextFillRect(mCg, RectToCGRect(aRect)); +} + + +bool +DrawTargetCG::Init(const IntSize &aSize) +{ + CGColorSpaceRef cgColorspace; + cgColorspace = CGColorSpaceCreateDeviceRGB(); + + mSize = aSize; + + int bitsPerComponent = 8; + int stride = mSize.width; + + CGBitmapInfo bitinfo; + + bitinfo = kCGBitmapByteOrder32Host | kCGImageAlphaPremultipliedFirst; + + // XXX: mWidth is ugly + mCg = CGBitmapContextCreate (NULL, + mSize.width, + mSize.height, + bitsPerComponent, + stride, + cgColorspace, + bitinfo); + + CGColorSpaceRelease (cgColorspace); + + return true; +} +} +} diff --git a/gfx/2d/DrawTargetCG.h b/gfx/2d/DrawTargetCG.h new file mode 100644 index 00000000000..d6908f91751 --- /dev/null +++ b/gfx/2d/DrawTargetCG.h @@ -0,0 +1,85 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.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/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Corporation code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Jeff Muizelaar + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#pragma once + +#include + +#include "2D.h" +#include "Rect.h" +namespace mozilla { +namespace gfx { + +class DrawTargetCG : public DrawTarget +{ +public: + DrawTargetCG(); + virtual ~DrawTargetCG(); + + virtual BackendType GetType() const { return COREGRAPHICS; } + virtual TemporaryRef Snapshot(); + + virtual void DrawSurface(SourceSurface *aSurface, + const Rect &aDest, + const Rect &aSource, + const DrawOptions &aOptions = DrawOptions(), + const DrawSurfaceOptions &aSurfOptions = DrawSurfaceOptions()); + + virtual void FillRect(const Rect &aRect, + const Pattern &aPattern, + const DrawOptions &aOptions = DrawOptions()); + + + bool Init(const IntSize &aSize); + bool Init(CGContextRef cgContext, const IntSize &aSize); + + /* This is for creating good compatible surfaces */ + virtual TemporaryRef CreateSourceSurfaceFromData(unsigned char *aData, + const IntSize &aSize, + int32_t aStride, + SurfaceFormat aFormat) const; + virtual TemporaryRef OptimizeSourceSurface(SourceSurface *aSurface) const; +private: + bool InitCGRenderTarget(); + + IntSize mSize; + CGContextRef mCg; + +}; + +} +} diff --git a/gfx/2d/DrawTargetCairo.cpp b/gfx/2d/DrawTargetCairo.cpp new file mode 100644 index 00000000000..8687e5ba0f0 --- /dev/null +++ b/gfx/2d/DrawTargetCairo.cpp @@ -0,0 +1,221 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.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/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Corporation code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "DrawTargetCairo.h" +#include "SourceSurfaceCairo.h" + +#include "cairo/cairo.h" + +namespace mozilla { +namespace gfx { + +cairo_operator_t +GfxOpToCairoOp(CompositionOp op) +{ + switch (op) + { + case OP_OVER: + return CAIRO_OPERATOR_OVER; + case OP_SOURCE: + return CAIRO_OPERATOR_SOURCE; + case OP_ADD: + return CAIRO_OPERATOR_ADD; + case OP_ATOP: + return CAIRO_OPERATOR_ATOP; + case OP_COUNT: + break; + } + + return CAIRO_OPERATOR_OVER; +} + +cairo_filter_t +GfxFilterToCairoFilter(Filter filter) +{ + switch (filter) + { + case FILTER_LINEAR: + return CAIRO_FILTER_BILINEAR; + case FILTER_POINT: + return CAIRO_FILTER_NEAREST; + } + + return CAIRO_FILTER_BILINEAR; +} + +cairo_format_t +GfxFormatToCairoFormat(SurfaceFormat format) +{ + switch (format) + { + case FORMAT_B8G8R8A8: + return CAIRO_FORMAT_ARGB32; + case FORMAT_B8G8R8X8: + return CAIRO_FORMAT_RGB24; + case FORMAT_A8: + return CAIRO_FORMAT_A8; + } + + return CAIRO_FORMAT_ARGB32; +} + +void +GfxMatrixToCairoMatrix(const Matrix& mat, cairo_matrix_t& retval) +{ + cairo_matrix_init(&retval, mat._11, mat._12, mat._21, mat._22, mat._31, mat._32); +} + +DrawTargetCairo::DrawTargetCairo() + : mContext(NULL) +{ +} + +DrawTargetCairo::~DrawTargetCairo() +{ + cairo_destroy(mContext); +} + +TemporaryRef +DrawTargetCairo::Snapshot() +{ + return NULL; +} + +void +DrawTargetCairo::Flush() +{ + cairo_surface_t* surf = cairo_get_target(mContext); + cairo_surface_flush(surf); +} + +void +DrawTargetCairo::DrawSurface(SourceSurface *aSurface, + const Rect &aDest, + const Rect &aSource, + const DrawSurfaceOptions &aSurfOptions, + const DrawOptions &aOptions) +{ + float sx = aSource.Width() / aDest.Width(); + float sy = aSource.Height() / aDest.Height(); + + cairo_matrix_t src_mat; + cairo_matrix_init_scale(&src_mat, sx, sy); + cairo_matrix_translate(&src_mat, -aSource.X(), -aSource.Y()); + + cairo_surface_t* surf = NULL; + if (aSurface->GetType() == SURFACE_CAIRO) { + surf = static_cast(aSurface)->GetSurface(); + } + + cairo_pattern_t* pat = cairo_pattern_create_for_surface(surf); + cairo_pattern_set_matrix(pat, &src_mat); + cairo_pattern_set_filter(pat, GfxFilterToCairoFilter(aSurfOptions.mFilter)); + + cairo_set_operator(mContext, GfxOpToCairoOp(aOptions.mCompositionOp)); + cairo_rectangle(mContext, aDest.X(), aDest.Y(), + aDest.Width(), aDest.Height()); + cairo_fill(mContext); + + cairo_pattern_destroy(pat); +} + +void +DrawTargetCairo::FillRect(const Rect &aRect, + const Pattern &aPattern, + const DrawOptions &aOptions) +{ + cairo_new_path(mContext); + cairo_rectangle(mContext, aRect.x, aRect.y, aRect.Width(), aRect.Height()); + + cairo_set_operator(mContext, GfxOpToCairoOp(aOptions.mCompositionOp)); + + if (aPattern.GetType() == PATTERN_COLOR) { + Color color = static_cast(aPattern).mColor; + cairo_set_source_rgba(mContext, color.r, color.g, + color.b, color.a); + } + + cairo_fill(mContext); +} + +TemporaryRef +DrawTargetCairo::CreateSourceSurfaceFromData(unsigned char *aData, + const IntSize &aSize, + int32_t aStride, + SurfaceFormat aFormat) const +{ + cairo_surface_t* surf = cairo_image_surface_create_for_data(aData, + GfxFormatToCairoFormat(aFormat), + aSize.width, + aSize.height, + aStride); + RefPtr source_surf = new SourceSurfaceCairo(); + source_surf->InitFromSurface(surf, aSize, aFormat); + cairo_surface_destroy(surf); + return source_surf; +} + +TemporaryRef +DrawTargetCairo::OptimizeSourceSurface(SourceSurface *aSurface) const +{ + return NULL; +} + +TemporaryRef +DrawTargetCairo::CreateSourceSurfaceFromNativeSurface(const NativeSurface &aSurface) const +{ + return NULL; +} + +bool +DrawTargetCairo::Init(cairo_surface_t* aSurface) +{ + mContext = cairo_create(aSurface); + + return true; +} + +void +DrawTargetCairo::SetTransform(const Matrix& aTransform) +{ + cairo_matrix_t mat; + GfxMatrixToCairoMatrix(aTransform, mat); + cairo_set_matrix(mContext, &mat); + mTransform = aTransform; +} + +} +} diff --git a/gfx/2d/DrawTargetCairo.h b/gfx/2d/DrawTargetCairo.h new file mode 100644 index 00000000000..3a69fe98183 --- /dev/null +++ b/gfx/2d/DrawTargetCairo.h @@ -0,0 +1,143 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.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/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Corporation code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef _MOZILLA_GFX_DRAWTARGET_CAIRO_H_ +#define _MOZILLA_GFX_DRAWTARGET_CAIRO_H_ + +#include "2D.h" +#include "cairo/cairo.h" + +namespace mozilla { +namespace gfx { + +class DrawTargetCairo : public DrawTarget +{ +public: + DrawTargetCairo(); + virtual ~DrawTargetCairo(); + + virtual BackendType GetType() const { return BACKEND_CAIRO; } + virtual TemporaryRef Snapshot(); + virtual IntSize GetSize() { return IntSize(); } + + virtual void Flush(); + virtual void DrawSurface(SourceSurface *aSurface, + const Rect &aDest, + const Rect &aSource, + const DrawSurfaceOptions &aSurfOptions = DrawSurfaceOptions(), + const DrawOptions &aOptions = DrawOptions()); + virtual void DrawSurfaceWithShadow(SourceSurface *aSurface, + const Point &aDest, + const Color &aColor, + const Point &aOffset, + Float aSigma) + { } + + virtual void ClearRect(const Rect &aRect) + { } + + virtual void CopySurface(SourceSurface *aSurface, + const IntRect &aSourceRect, + const IntPoint &aDestination) + { } + + virtual void FillRect(const Rect &aRect, + const Pattern &aPattern, + const DrawOptions &aOptions = DrawOptions()); + virtual void StrokeRect(const Rect &aRect, + const Pattern &aPattern, + const StrokeOptions &aStrokeOptions = StrokeOptions(), + const DrawOptions &aOptions = DrawOptions()) + { return; } + virtual void StrokeLine(const Point &aStart, + const Point &aEnd, + const Pattern &aPattern, + const StrokeOptions &aStrokeOptions = StrokeOptions(), + const DrawOptions &aOptions = DrawOptions()) + { return; } + + virtual void Stroke(const Path *aPath, + const Pattern &aPattern, + const StrokeOptions &aStrokeOptions = StrokeOptions(), + const DrawOptions &aOptions = DrawOptions()) + { return; } + + virtual void Fill(const Path *aPath, + const Pattern &aPattern, + const DrawOptions &aOptions = DrawOptions()) + { return; } + + virtual void FillGlyphs(ScaledFont *aFont, + const GlyphBuffer &aBuffer, + const Pattern &aPattern, + const DrawOptions &aOptions) + { return; } + + virtual void PushClip(const Path *aPath) { } + virtual void PopClip() { } + + virtual TemporaryRef CreatePathBuilder(FillRule aFillRule = FILL_WINDING) const { return NULL; } + + virtual TemporaryRef CreateSourceSurfaceFromData(unsigned char *aData, + const IntSize &aSize, + int32_t aStride, + SurfaceFormat aFormat) const; + virtual TemporaryRef OptimizeSourceSurface(SourceSurface *aSurface) const; + virtual TemporaryRef + CreateSourceSurfaceFromNativeSurface(const NativeSurface &aSurface) const; + virtual TemporaryRef + CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFormat) const + { return NULL; } + + virtual TemporaryRef CreateGradientStops(GradientStop *aStops, uint32_t aNumStops) const + { return NULL; } + + virtual void *GetNativeSurface(NativeSurfaceType aType) + { return NULL; } + + virtual void SetTransform(const Matrix& aTransform); + + bool Init(cairo_surface_t* aSurface); + +private: + + cairo_t* mContext; +}; + +} +} + +#endif // _MOZILLA_GFX_DRAWTARGET_CAIRO_H_ diff --git a/gfx/2d/DrawTargetD2D.cpp b/gfx/2d/DrawTargetD2D.cpp new file mode 100644 index 00000000000..5d80061f4b4 --- /dev/null +++ b/gfx/2d/DrawTargetD2D.cpp @@ -0,0 +1,1679 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.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/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Corporation code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Bas Schouten + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "DrawTargetD2D.h" +#include "SourceSurfaceD2D.h" +#include "SourceSurfaceD2DTarget.h" +#include "ShadersD2D.h" +#include "PathD2D.h" +#include "GradientStopsD2D.h" +#include "ScaledFontDWrite.h" +#include "Logging.h" +#include "Tools.h" + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +typedef HRESULT (WINAPI*D2D1CreateFactoryFunc)( + __in D2D1_FACTORY_TYPE factoryType, + __in REFIID iid, + __in_opt CONST D2D1_FACTORY_OPTIONS *pFactoryOptions, + __out void **factory +); + +typedef HRESULT (WINAPI*D3D10CreateEffectFromMemoryFunc)( + __in void *pData, + __in SIZE_T DataLength, + __in UINT FXFlags, + __in ID3D10Device *pDevice, + __in ID3D10EffectPool *pEffectPool, + __out ID3D10Effect **ppEffect +); + +namespace mozilla { +namespace gfx { + +struct Vertex { + float x; + float y; +}; + +ID2D1Factory *DrawTargetD2D::mFactory; + +// Helper class to restore surface contents that was clipped out but may have +// been altered by a drawing call. +class AutoSaveRestoreClippedOut +{ +public: + AutoSaveRestoreClippedOut(DrawTargetD2D *aDT) + : mDT(aDT) + {} + + void Save() { + if (!mDT->mPushedClips.size()) { + return; + } + + mDT->Flush(); + + RefPtr tmpTexture; + IntSize size = mDT->mSize; + SurfaceFormat format = mDT->mFormat; + + CD3D10_TEXTURE2D_DESC desc(DXGIFormat(format), size.width, size.height, + 1, 1); + desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE; + + HRESULT hr = mDT->mDevice->CreateTexture2D(&desc, NULL, byRef(tmpTexture)); + if (FAILED(hr)) { + gfxWarning() << "Failed to create temporary texture to hold surface data."; + } + mDT->mDevice->CopyResource(tmpTexture, mDT->mTexture); + + D2D1_BITMAP_PROPERTIES props = + D2D1::BitmapProperties(D2D1::PixelFormat(DXGIFormat(format), + AlphaMode(format))); + + RefPtr surf; + + tmpTexture->QueryInterface((IDXGISurface**)byRef(surf)); + + hr = mDT->mRT->CreateSharedBitmap(IID_IDXGISurface, surf, + &props, byRef(mOldSurfBitmap)); + + if (FAILED(hr)) { + gfxWarning() << "Failed to create shared bitmap for old surface."; + } + + factory()->CreatePathGeometry(byRef(mClippedArea)); + RefPtr currentSink; + mClippedArea->Open(byRef(currentSink)); + + std::vector::iterator iter = mDT->mPushedClips.begin(); + iter->mPath->GetGeometry()->Simplify(D2D1_GEOMETRY_SIMPLIFICATION_OPTION_CUBICS_AND_LINES, + iter->mTransform, currentSink); + + currentSink->Close(); + + iter++; + for (;iter != mDT->mPushedClips.end(); iter++) { + RefPtr newGeom; + factory()->CreatePathGeometry(byRef(newGeom)); + + newGeom->Open(byRef(currentSink)); + mClippedArea->CombineWithGeometry(iter->mPath->GetGeometry(), D2D1_COMBINE_MODE_INTERSECT, + iter->mTransform, currentSink); + + currentSink->Close(); + + mClippedArea = newGeom; + } + } + + ID2D1Factory *factory() { return mDT->factory(); } + + ~AutoSaveRestoreClippedOut() + { + if (!mOldSurfBitmap) { + return; + } + + ID2D1RenderTarget *rt = mDT->mRT; + + // Write the area that was clipped out back to the surface. This all + // happens in device space. + rt->SetTransform(D2D1::IdentityMatrix()); + mDT->mTransformDirty = true; + + RefPtr rectGeom; + factory()->CreateRectangleGeometry(D2D1::InfiniteRect(), byRef(rectGeom)); + + RefPtr invClippedArea; + factory()->CreatePathGeometry(byRef(invClippedArea)); + RefPtr sink; + invClippedArea->Open(byRef(sink)); + + HRESULT hr = rectGeom->CombineWithGeometry(mClippedArea, D2D1_COMBINE_MODE_EXCLUDE, + NULL, sink); + sink->Close(); + + RefPtr brush; + rt->CreateBitmapBrush(mOldSurfBitmap, D2D1::BitmapBrushProperties(), D2D1::BrushProperties(), byRef(brush)); + + rt->FillGeometry(invClippedArea, brush); + } + +private: + + DrawTargetD2D *mDT; + + // If we have an operator unbound by the source, this will contain a bitmap + // with the old dest surface data. + RefPtr mOldSurfBitmap; + // This contains the area drawing is clipped to. + RefPtr mClippedArea; +}; + +DrawTargetD2D::DrawTargetD2D() + : mClipsArePushed(false) + , mPrivateData(NULL) +{ +} + +DrawTargetD2D::~DrawTargetD2D() +{ + if (mRT) { + PopAllClips(); + + mRT->EndDraw(); + } + if (mTempRT) { + mTempRT->EndDraw(); + } +} + +/* + * DrawTarget Implementation + */ +TemporaryRef +DrawTargetD2D::Snapshot() +{ + RefPtr newSurf = new SourceSurfaceD2DTarget(); + + newSurf->mFormat = mFormat; + newSurf->mTexture = mTexture; + newSurf->mDrawTarget = this; + + mSnapshots.push_back(newSurf); + + Flush(); + + return newSurf; +} + +void +DrawTargetD2D::Flush() +{ + PopAllClips(); + + HRESULT hr = mRT->Flush(); + + if (FAILED(hr)) { + gfxWarning() << "Error reported when trying to flush D2D rendertarget. Code: " << hr; + } +} + +void +DrawTargetD2D::DrawSurface(SourceSurface *aSurface, + const Rect &aDest, + const Rect &aSource, + const DrawSurfaceOptions &aSurfOptions, + const DrawOptions &aOptions) +{ + RefPtr bitmap; + + ID2D1RenderTarget *rt = GetRTForOperator(aOptions.mCompositionOp); + + PrepareForDrawing(rt); + + Rect srcRect = aSource; + + switch (aSurface->GetType()) { + + case SURFACE_D2D1_BITMAP: + { + SourceSurfaceD2D *srcSurf = static_cast(aSurface); + bitmap = srcSurf->GetBitmap(); + + if (!bitmap) { + if (aSource.width > rt->GetMaximumBitmapSize() || + aSource.height > rt->GetMaximumBitmapSize()) { + gfxDebug() << "Bitmap source larger than texture size specified. DrawBitmap will silently fail."; + // Don't know how to deal with this yet. + return; + } + + int stride = srcSurf->GetSize().width * BytesPerPixel(srcSurf->GetFormat()); + + unsigned char *data = &srcSurf->mRawData.front() + + (uint32_t)aSource.y * stride + + (uint32_t)aSource.x * BytesPerPixel(srcSurf->GetFormat()); + + D2D1_BITMAP_PROPERTIES props = + D2D1::BitmapProperties(D2D1::PixelFormat(DXGIFormat(srcSurf->GetFormat()), AlphaMode(srcSurf->GetFormat()))); + mRT->CreateBitmap(D2D1::SizeU(UINT32(aSource.width), UINT32(aSource.height)), data, stride, props, byRef(bitmap)); + + srcRect.x -= (uint32_t)aSource.x; + srcRect.y -= (uint32_t)aSource.y; + } + } + break; + case SURFACE_D2D1_DRAWTARGET: + { + SourceSurfaceD2DTarget *srcSurf = static_cast(aSurface); + bitmap = srcSurf->GetBitmap(mRT); + + if (!srcSurf->IsCopy()) { + srcSurf->mDrawTarget->mDependentTargets.push_back(this); + } + } + break; + } + + rt->DrawBitmap(bitmap, D2DRect(aDest), aOptions.mAlpha, D2DFilter(aSurfOptions.mFilter), D2DRect(srcRect)); + + FinalizeRTForOperator(aOptions.mCompositionOp, aDest); +} + +void +DrawTargetD2D::DrawSurfaceWithShadow(SourceSurface *aSurface, + const Point &aDest, + const Color &aColor, + const Point &aOffset, + Float aSigma) +{ + RefPtr srView = NULL; + if (aSurface->GetType() != SURFACE_D2D1_DRAWTARGET) { + return; + } + + Flush(); + + srView = static_cast(aSurface)->GetSRView(); + + EnsureViews(); + + if (!mTempRTView) { + // This view is only needed in this path. + HRESULT hr = mDevice->CreateRenderTargetView(mTempTexture, NULL, byRef(mTempRTView)); + + if (FAILED(hr)) { + gfxWarning() << "Failure to create RenderTargetView. Code: " << hr; + return; + } + } + + RefPtr destRTView = mRTView; + RefPtr destTexture; + HRESULT hr; + + if (mPushedClips.size()) { + // We need to take clips into account, draw into a temporary surface, which + // we then blend back with the proper clips set, using D2D. + CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM, + mSize.width, mSize.height, + 1, 1); + desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE; + + hr = mDevice->CreateTexture2D(&desc, NULL, byRef(destTexture)); + if (FAILED(hr)) { + gfxWarning() << "Failure to create temporary texture. Size: " << mSize << " Code: " << hr; + return; + } + + hr = mDevice->CreateRenderTargetView(destTexture, NULL, byRef(destRTView)); + if (FAILED(hr)) { + gfxWarning() << "Failure to create RenderTargetView. Code: " << hr; + return; + } + + float color[4] = { 0, 0, 0, 0 }; + mDevice->ClearRenderTargetView(destRTView, color); + } + + + IntSize srcSurfSize; + ID3D10RenderTargetView *rtViews; + D3D10_VIEWPORT viewport; + + UINT stride = sizeof(Vertex); + UINT offset = 0; + ID3D10Buffer *buff = mPrivateData->mVB; + + mDevice->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + mDevice->IASetVertexBuffers(0, 1, &buff, &stride, &offset); + mDevice->IASetInputLayout(mPrivateData->mInputLayout); + + mPrivateData->mEffect->GetVariableByName("QuadDesc")->AsVector()-> + SetFloatVector(ShaderConstantRectD3D10(-1.0f, 1.0f, 2.0f, -2.0f)); + mPrivateData->mEffect->GetVariableByName("TexCoords")->AsVector()-> + SetFloatVector(ShaderConstantRectD3D10(0, 0, 1.0f, 1.0f)); + + // If we create a downsampled source surface we need to correct aOffset for that. + Point correctedOffset = aOffset + aDest; + + // The 'practical' scaling factors. + Float dsFactorX = 1.0f; + Float dsFactorY = 1.0f; + + if (aSigma > 1.7f) { + // In this case 9 samples of our original will not cover it. Generate the + // mip levels for the original and create a downsampled version from + // them. We generate a version downsampled so that a kernel for a sigma + // of 1.7 will produce the right results. + float blurWeights[9] = { 0.234671f, 0.197389f, 0.197389f, 0.117465f, 0.117465f, 0.049456f, 0.049456f, 0.014732f, 0.014732f }; + mPrivateData->mEffect->GetVariableByName("BlurWeights")->SetRawValue(blurWeights, 0, sizeof(blurWeights)); + + CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM, + aSurface->GetSize().width, + aSurface->GetSize().height); + desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE; + desc.MiscFlags = D3D10_RESOURCE_MISC_GENERATE_MIPS; + + RefPtr mipTexture; + hr = mDevice->CreateTexture2D(&desc, NULL, byRef(mipTexture)); + + if (FAILED(hr)) { + gfxWarning() << "Failure to create temporary texture. Size: " << + aSurface->GetSize() << " Code: " << hr; + return; + } + + IntSize dsSize = IntSize(int32_t(aSurface->GetSize().width * (1.7f / aSigma)), + int32_t(aSurface->GetSize().height * (1.7f / aSigma))); + + if (dsSize.width < 1) { + dsSize.width = 1; + } + if (dsSize.height < 1) { + dsSize.height = 1; + } + + dsFactorX = dsSize.width / Float(aSurface->GetSize().width); + dsFactorY = dsSize.height / Float(aSurface->GetSize().height); + correctedOffset.x *= dsFactorX; + correctedOffset.y *= dsFactorY; + + desc = CD3D10_TEXTURE2D_DESC(DXGI_FORMAT_B8G8R8A8_UNORM, + dsSize.width, + dsSize.height, 1, 1); + desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE; + RefPtr tmpDSTexture; + hr = mDevice->CreateTexture2D(&desc, NULL, byRef(tmpDSTexture)); + + if (FAILED(hr)) { + gfxWarning() << "Failure to create temporary texture. Size: " << dsSize << " Code: " << hr; + return; + } + + D3D10_BOX box; + box.left = box.top = box.front = 0; + box.back = 1; + box.right = aSurface->GetSize().width; + box.bottom = aSurface->GetSize().height; + mDevice->CopySubresourceRegion(mipTexture, 0, 0, 0, 0, static_cast(aSurface)->mTexture, 0, &box); + + mDevice->CreateShaderResourceView(mipTexture, NULL, byRef(srView)); + mDevice->GenerateMips(srView); + + RefPtr dsRTView; + RefPtr dsSRView; + mDevice->CreateRenderTargetView(tmpDSTexture, NULL, byRef(dsRTView)); + mDevice->CreateShaderResourceView(tmpDSTexture, NULL, byRef(dsSRView)); + + rtViews = dsRTView; + mDevice->OMSetRenderTargets(1, &rtViews, NULL); + + viewport.MaxDepth = 1; + viewport.MinDepth = 0; + viewport.Height = dsSize.height; + viewport.Width = dsSize.width; + viewport.TopLeftX = 0; + viewport.TopLeftY = 0; + + mDevice->RSSetViewports(1, &viewport); + mPrivateData->mEffect->GetVariableByName("tex")->AsShaderResource()->SetResource(srView); + mPrivateData->mEffect->GetTechniqueByName("SampleTexture")-> + GetPassByIndex(0)->Apply(0); + + mDevice->OMSetBlendState(GetBlendStateForOperator(OP_OVER), NULL, 0xffffffff); + + mDevice->Draw(4, 0); + + srcSurfSize = dsSize; + + srView = dsSRView; + } else { + // In this case generate a kernel to draw the blur directly to the temp + // surf in one direction and to final in the other. + float blurWeights[9]; + + float normalizeFactor = 1.0f; + if (aSigma != 0) { + normalizeFactor = 1.0f / Float(sqrt(2 * M_PI * pow(aSigma, 2))); + } + + blurWeights[0] = normalizeFactor; + + // XXX - We should actually optimize for Sigma = 0 here. We could use a + // much simpler shader and save a lot of texture lookups. + for (int i = 1; i < 9; i += 2) { + if (aSigma != 0) { + blurWeights[i] = blurWeights[i + 1] = normalizeFactor * + exp(-pow(float((i + 1) / 2), 2) / (2 * pow(aSigma, 2))); + } else { + blurWeights[i] = blurWeights[i + 1] = 0; + } + } + + mPrivateData->mEffect->GetVariableByName("BlurWeights")->SetRawValue(blurWeights, 0, sizeof(blurWeights)); + + viewport.MaxDepth = 1; + viewport.MinDepth = 0; + viewport.Height = aSurface->GetSize().height; + viewport.Width = aSurface->GetSize().width; + viewport.TopLeftX = 0; + viewport.TopLeftY = 0; + + mDevice->RSSetViewports(1, &viewport); + + srcSurfSize = aSurface->GetSize(); + } + + // We may need to draw to a different intermediate surface if our temp + // texture isn't big enough. + bool needBiggerTemp = srcSurfSize.width > mSize.width || + srcSurfSize.height > mSize.height; + + RefPtr tmpRTView; + RefPtr tmpSRView; + RefPtr tmpTexture; + + IntSize tmpSurfSize = mSize; + + if (!needBiggerTemp) { + tmpRTView = mTempRTView; + tmpSRView = mSRView; + } else { + CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM, + srcSurfSize.width, + srcSurfSize.height, + 1, 1); + desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE; + + mDevice->CreateTexture2D(&desc, NULL, byRef(tmpTexture)); + mDevice->CreateRenderTargetView(tmpTexture, NULL, byRef(tmpRTView)); + mDevice->CreateShaderResourceView(tmpTexture, NULL, byRef(tmpSRView)); + + tmpSurfSize = srcSurfSize; + } + + rtViews = tmpRTView; + mDevice->OMSetRenderTargets(1, &rtViews, NULL); + + mPrivateData->mEffect->GetVariableByName("tex")->AsShaderResource()->SetResource(srView); + + // Premultiplied! + float shadowColor[4] = { aColor.r * aColor.a, aColor.g * aColor.a, + aColor.b * aColor.a, aColor.a }; + mPrivateData->mEffect->GetVariableByName("ShadowColor")->AsVector()-> + SetFloatVector(shadowColor); + + float pixelOffset = 1.0f / float(srcSurfSize.width); + float blurOffsetsH[9] = { 0, pixelOffset, -pixelOffset, + 2.0f * pixelOffset, -2.0f * pixelOffset, + 3.0f * pixelOffset, -3.0f * pixelOffset, + 4.0f * pixelOffset, - 4.0f * pixelOffset }; + + pixelOffset = 1.0f / float(tmpSurfSize.height); + float blurOffsetsV[9] = { 0, pixelOffset, -pixelOffset, + 2.0f * pixelOffset, -2.0f * pixelOffset, + 3.0f * pixelOffset, -3.0f * pixelOffset, + 4.0f * pixelOffset, - 4.0f * pixelOffset }; + + mPrivateData->mEffect->GetVariableByName("BlurOffsetsH")-> + SetRawValue(blurOffsetsH, 0, sizeof(blurOffsetsH)); + mPrivateData->mEffect->GetVariableByName("BlurOffsetsV")-> + SetRawValue(blurOffsetsV, 0, sizeof(blurOffsetsV)); + + mPrivateData->mEffect->GetTechniqueByName("SampleTextureWithShadow")-> + GetPassByIndex(0)->Apply(0); + + mDevice->Draw(4, 0); + + viewport.MaxDepth = 1; + viewport.MinDepth = 0; + viewport.Height = mSize.height; + viewport.Width = mSize.width; + viewport.TopLeftX = 0; + viewport.TopLeftY = 0; + + mDevice->RSSetViewports(1, &viewport); + + mPrivateData->mEffect->GetVariableByName("tex")->AsShaderResource()->SetResource(tmpSRView); + + rtViews = destRTView; + mDevice->OMSetRenderTargets(1, &rtViews, NULL); + + mPrivateData->mEffect->GetVariableByName("TexCoords")->AsVector()-> + SetFloatVector(ShaderConstantRectD3D10(-correctedOffset.x / Float(tmpSurfSize.width), -correctedOffset.y / Float(tmpSurfSize.height), + mSize.width / Float(tmpSurfSize.width) * dsFactorX, + mSize.height / Float(tmpSurfSize.height) * dsFactorY)); + mPrivateData->mEffect->GetTechniqueByName("SampleTextureWithShadow")-> + GetPassByIndex(1)->Apply(0); + + mDevice->Draw(4, 0); + + mPrivateData->mEffect->GetVariableByName("tex")->AsShaderResource()->SetResource(static_cast(aSurface)->GetSRView()); + mPrivateData->mEffect->GetVariableByName("TexCoords")->AsVector()-> + SetFloatVector(ShaderConstantRectD3D10(-aDest.x / aSurface->GetSize().width, -aDest.y / aSurface->GetSize().height, + Float(mSize.width) / aSurface->GetSize().width, + Float(mSize.height) / aSurface->GetSize().height)); + mPrivateData->mEffect->GetTechniqueByName("SampleTexture")-> + GetPassByIndex(0)->Apply(0); + mDevice->OMSetBlendState(GetBlendStateForOperator(OP_OVER), NULL, 0xffffffff); + + mDevice->Draw(4, 0); + + if (mPushedClips.size()) { + // Assert destTexture + + // Blend back using the proper clips. + PrepareForDrawing(mRT); + + RefPtr surf; + hr = destTexture->QueryInterface((IDXGISurface**) byRef(surf)); + + if (FAILED(hr)) { + gfxWarning() << "Failure to QI texture to surface. Code: " << hr; + return; + } + + D2D1_BITMAP_PROPERTIES props = + D2D1::BitmapProperties(D2D1::PixelFormat(DXGIFormat(mFormat), AlphaMode(mFormat))); + RefPtr bitmap; + hr = mRT->CreateSharedBitmap(IID_IDXGISurface, surf, + &props, byRef(bitmap)); + + if (FAILED(hr)) { + gfxWarning() << "Failure to create shared bitmap for surface. Code: " << hr; + return; + } + + mRT->DrawBitmap(bitmap); + } +} + +void +DrawTargetD2D::ClearRect(const Rect &aRect) +{ + mRT->SetTransform(D2DMatrix(mTransform)); + PopAllClips(); + + AutoSaveRestoreClippedOut restoreClippedOut(this); + + restoreClippedOut.Save(); + + bool needsClip = false; + + needsClip = aRect.x > 0 || aRect.y > 0 || + aRect.XMost() < mSize.width || + aRect.YMost() < mSize.height; + + if (needsClip) { + mRT->PushAxisAlignedClip(D2DRect(aRect), D2D1_ANTIALIAS_MODE_PER_PRIMITIVE); + } + mRT->Clear(D2D1::ColorF(0, 0.0f)); + if (needsClip) { + mRT->PopAxisAlignedClip(); + } + return; +} + +void +DrawTargetD2D::CopySurface(SourceSurface *aSurface, + const IntRect &aSourceRect, + const IntPoint &aDestination) +{ + Rect srcRect(aSourceRect.x, aSourceRect.y, aSourceRect.width, aSourceRect.height); + Rect dstRect(aDestination.x, aDestination.y, aSourceRect.width, aSourceRect.height); + + mRT->SetTransform(D2D1::IdentityMatrix()); + mRT->PushAxisAlignedClip(D2DRect(dstRect), D2D1_ANTIALIAS_MODE_ALIASED); + mRT->Clear(D2D1::ColorF(0, 0.0f)); + mRT->PopAxisAlignedClip(); + + RefPtr bitmap; + + switch (aSurface->GetType()) { + case SURFACE_D2D1_BITMAP: + { + SourceSurfaceD2D *srcSurf = static_cast(aSurface); + bitmap = srcSurf->GetBitmap(); + } + break; + case SURFACE_D2D1_DRAWTARGET: + { + SourceSurfaceD2DTarget *srcSurf = static_cast(aSurface); + bitmap = srcSurf->GetBitmap(mRT); + + if (!srcSurf->IsCopy()) { + srcSurf->mDrawTarget->mDependentTargets.push_back(this); + } + } + break; + } + + if (!bitmap) { + return; + } + + mRT->DrawBitmap(bitmap, D2DRect(dstRect), 1.0f, + D2D1_BITMAP_INTERPOLATION_MODE_LINEAR, + D2DRect(srcRect)); +} + +void +DrawTargetD2D::FillRect(const Rect &aRect, + const Pattern &aPattern, + const DrawOptions &aOptions) +{ + ID2D1RenderTarget *rt = GetRTForOperator(aOptions.mCompositionOp); + + PrepareForDrawing(rt); + + RefPtr brush = CreateBrushForPattern(aPattern, aOptions.mAlpha); + + if (brush) { + rt->FillRectangle(D2DRect(aRect), brush); + } + + FinalizeRTForOperator(aOptions.mCompositionOp, aRect); +} + +void +DrawTargetD2D::StrokeRect(const Rect &aRect, + const Pattern &aPattern, + const StrokeOptions &aStrokeOptions, + const DrawOptions &aOptions) +{ + ID2D1RenderTarget *rt = GetRTForOperator(aOptions.mCompositionOp); + + PrepareForDrawing(rt); + + RefPtr brush = CreateBrushForPattern(aPattern, aOptions.mAlpha); + + RefPtr strokeStyle = CreateStrokeStyleForOptions(aStrokeOptions); + + if (brush && strokeStyle) { + rt->DrawRectangle(D2DRect(aRect), brush, aStrokeOptions.mLineWidth, strokeStyle); + } + + FinalizeRTForOperator(aOptions.mCompositionOp, aRect); +} + +void +DrawTargetD2D::StrokeLine(const Point &aStart, + const Point &aEnd, + const Pattern &aPattern, + const StrokeOptions &aStrokeOptions, + const DrawOptions &aOptions) +{ + ID2D1RenderTarget *rt = GetRTForOperator(aOptions.mCompositionOp); + + PrepareForDrawing(rt); + + RefPtr brush = CreateBrushForPattern(aPattern, aOptions.mAlpha); + + RefPtr strokeStyle = CreateStrokeStyleForOptions(aStrokeOptions); + + if (brush && strokeStyle) { + rt->DrawLine(D2DPoint(aStart), D2DPoint(aEnd), brush, aStrokeOptions.mLineWidth, strokeStyle); + } + + FinalizeRTForOperator(aOptions.mCompositionOp, Rect(0, 0, Float(mSize.width), Float(mSize.height))); +} + +void +DrawTargetD2D::Stroke(const Path *aPath, + const Pattern &aPattern, + const StrokeOptions &aStrokeOptions, + const DrawOptions &aOptions) +{ + if (aPath->GetBackendType() != BACKEND_DIRECT2D) { + gfxDebug() << *this << ": Ignoring drawing call for incompatible path."; + return; + } + + const PathD2D *d2dPath = static_cast(aPath); + + ID2D1RenderTarget *rt = GetRTForOperator(aOptions.mCompositionOp); + + PrepareForDrawing(rt); + + RefPtr brush = CreateBrushForPattern(aPattern, aOptions.mAlpha); + + RefPtr strokeStyle = CreateStrokeStyleForOptions(aStrokeOptions); + + if (brush && strokeStyle) { + rt->DrawGeometry(d2dPath->mGeometry, brush, aStrokeOptions.mLineWidth, strokeStyle); + } + + FinalizeRTForOperator(aOptions.mCompositionOp, Rect(0, 0, Float(mSize.width), Float(mSize.height))); +} + +void +DrawTargetD2D::Fill(const Path *aPath, + const Pattern &aPattern, + const DrawOptions &aOptions) +{ + if (aPath->GetBackendType() != BACKEND_DIRECT2D) { + gfxDebug() << *this << ": Ignoring drawing call for incompatible path."; + return; + } + + const PathD2D *d2dPath = static_cast(aPath); + + ID2D1RenderTarget *rt = GetRTForOperator(aOptions.mCompositionOp); + + PrepareForDrawing(rt); + + RefPtr brush = CreateBrushForPattern(aPattern, aOptions.mAlpha); + + if (brush) { + rt->FillGeometry(d2dPath->mGeometry, brush); + } + + Rect bounds; + if (aOptions.mCompositionOp != OP_OVER) { + D2D1_RECT_F d2dbounds; + d2dPath->mGeometry->GetBounds(D2D1::IdentityMatrix(), &d2dbounds); + bounds = ToRect(d2dbounds); + } + FinalizeRTForOperator(aOptions.mCompositionOp, bounds); +} + +void +DrawTargetD2D::FillGlyphs(ScaledFont *aFont, + const GlyphBuffer &aBuffer, + const Pattern &aPattern, + const DrawOptions &aOptions) +{ + if (aFont->GetType() != FONT_DWRITE) { + gfxDebug() << *this << ": Ignoring drawing call for incompatible font."; + return; + } + + ScaledFontDWrite *font = static_cast(aFont); + + ID2D1RenderTarget *rt = GetRTForOperator(aOptions.mCompositionOp); + + PrepareForDrawing(rt); + + RefPtr brush = CreateBrushForPattern(aPattern, aOptions.mAlpha); + + DWRITE_GLYPH_RUN glyphRun; + + glyphRun.bidiLevel = 0; + glyphRun.fontEmSize = font->mSize; + glyphRun.isSideways = FALSE; + glyphRun.fontFace = font->mFontFace; + glyphRun.glyphCount = aBuffer.mNumGlyphs; + + std::vector indices; + std::vector advances; + std::vector offsets; + indices.resize(aBuffer.mNumGlyphs); + advances.resize(aBuffer.mNumGlyphs); + offsets.resize(aBuffer.mNumGlyphs); + + memset(&advances.front(), 0, sizeof(FLOAT) * aBuffer.mNumGlyphs); + for (unsigned int i = 0; i < aBuffer.mNumGlyphs; i++) { + indices[i] = aBuffer.mGlyphs[i].mIndex; + offsets[i].advanceOffset = aBuffer.mGlyphs[i].mPosition.x; + offsets[i].ascenderOffset = -aBuffer.mGlyphs[i].mPosition.y; + } + + glyphRun.glyphAdvances = &advances.front(); + glyphRun.glyphIndices = &indices.front(); + glyphRun.glyphOffsets = &offsets.front(); + + if (brush) { + rt->DrawGlyphRun(D2D1::Point2F(), &glyphRun, brush); + } + + FinalizeRTForOperator(aOptions.mCompositionOp, Rect(0, 0, (Float)mSize.width, (Float)mSize.height)); +} + +void +DrawTargetD2D::PushClip(const Path *aPath) +{ + if (aPath->GetBackendType() != BACKEND_DIRECT2D) { + gfxDebug() << *this << ": Ignoring clipping call for incompatible path."; + return; + } + + RefPtr pathD2D = static_cast(const_cast(aPath)); + + PushedClip clip; + clip.mTransform = D2DMatrix(mTransform); + clip.mPath = pathD2D; + + RefPtr layer; + pathD2D->mGeometry->GetBounds(clip.mTransform, &clip.mBounds); + + mRT->CreateLayer( byRef(layer)); + + clip.mLayer = layer; + mPushedClips.push_back(clip); + + // The transform of clips is relative to the world matrix, since we use the total + // transform for the clips, make the world matrix identity. + mRT->SetTransform(D2D1::IdentityMatrix()); + mTransformDirty = true; + + if (mClipsArePushed) { + mRT->PushLayer(D2D1::LayerParameters(D2D1::InfiniteRect(), pathD2D->mGeometry, + D2D1_ANTIALIAS_MODE_PER_PRIMITIVE, + clip.mTransform), layer); + } +} + +void +DrawTargetD2D::PopClip() +{ + if (mClipsArePushed) { + mRT->PopLayer(); + } + mPushedClips.pop_back(); +} + +TemporaryRef +DrawTargetD2D::CreateSourceSurfaceFromData(unsigned char *aData, + const IntSize &aSize, + int32_t aStride, + SurfaceFormat aFormat) const +{ + RefPtr newSurf = new SourceSurfaceD2D(); + + if (!newSurf->InitFromData(aData, aSize, aStride, aFormat, mRT)) { + gfxDebug() << *this << ": Failure to create source surface from data. Size: " << aSize; + return NULL; + } + + return newSurf; +} + +TemporaryRef +DrawTargetD2D::OptimizeSourceSurface(SourceSurface *aSurface) const +{ + // Unsupported! + return NULL; +} + +TemporaryRef +DrawTargetD2D::CreateSourceSurfaceFromNativeSurface(const NativeSurface &aSurface) const +{ + if (aSurface.mType != NATIVE_SURFACE_D3D10_TEXTURE) { + gfxDebug() << *this << ": Failure to create source surface from non-D3D10 texture native surface."; + return NULL; + } + RefPtr newSurf = new SourceSurfaceD2D(); + + if (!newSurf->InitFromTexture(static_cast(aSurface.mSurface), + aSurface.mFormat, + mRT)) + { + gfxWarning() << *this << ": Failed to create SourceSurface from texture."; + return NULL; + } + + return newSurf; +} + +TemporaryRef +DrawTargetD2D::CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFormat) const +{ + RefPtr newTarget = + new DrawTargetD2D(); + + if (!newTarget->Init(aSize, aFormat)) { + gfxDebug() << *this << ": Failed to create optimal draw target. Size: " << aSize; + return NULL; + } + + return newTarget; +} + +TemporaryRef +DrawTargetD2D::CreatePathBuilder(FillRule aFillRule) const +{ + RefPtr path; + HRESULT hr = factory()->CreatePathGeometry(byRef(path)); + + if (FAILED(hr)) { + gfxWarning() << "Failed to create Direct2D Path Geometry. Code: " << hr; + return NULL; + } + + RefPtr sink; + hr = path->Open(byRef(sink)); + if (FAILED(hr)) { + gfxWarning() << "Failed to access Direct2D Path Geometry. Code: " << hr; + return NULL; + } + + if (aFillRule == FILL_WINDING) { + sink->SetFillMode(D2D1_FILL_MODE_WINDING); + } + + return new PathBuilderD2D(sink, path, aFillRule); +} + +TemporaryRef +DrawTargetD2D::CreateGradientStops(GradientStop *aStops, uint32_t aNumStops) const +{ + D2D1_GRADIENT_STOP *stops = new D2D1_GRADIENT_STOP[aNumStops]; + + for (uint32_t i = 0; i < aNumStops; i++) { + stops[i].position = aStops[i].offset; + stops[i].color = D2DColor(aStops[i].color); + } + + RefPtr stopCollection; + + HRESULT hr = mRT->CreateGradientStopCollection(stops, aNumStops, byRef(stopCollection)); + + if (FAILED(hr)) { + gfxWarning() << "Failed to create GradientStopCollection. Code: " << hr; + return NULL; + } + + return new GradientStopsD2D(stopCollection); +} + +void* +DrawTargetD2D::GetNativeSurface(NativeSurfaceType aType) +{ + if (aType != NATIVE_SURFACE_D3D10_TEXTURE) { + return NULL; + } + + return mTexture; +} + +/* + * Public functions + */ +bool +DrawTargetD2D::Init(const IntSize &aSize, SurfaceFormat aFormat) +{ + HRESULT hr; + + mSize = aSize; + mFormat = aFormat; + + if (!Factory::GetDirect3D10Device()) { + gfxDebug() << "Failed to Init Direct2D DrawTarget (No D3D10 Device set.)"; + return false; + } + mDevice = Factory::GetDirect3D10Device(); + + CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM, + mSize.width, + mSize.height, + 1, 1); + desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE; + + hr = mDevice->CreateTexture2D(&desc, NULL, byRef(mTexture)); + + if (FAILED(hr)) { + gfxDebug() << "Failed to init Direct2D DrawTarget. Size: " << mSize << " Code: " << hr; + return false; + } + + return InitD2DRenderTarget(); +} + +bool +DrawTargetD2D::Init(ID3D10Texture2D *aTexture, SurfaceFormat aFormat) +{ + HRESULT hr; + + mTexture = aTexture; + mFormat = aFormat; + + if (!mTexture) { + gfxDebug() << "No valid texture for Direct2D draw target initialization."; + return false; + } + + RefPtr device; + mTexture->GetDevice(byRef(device)); + + hr = device->QueryInterface((ID3D10Device1**)byRef(mDevice)); + + if (FAILED(hr)) { + gfxWarning() << "Failed to get D3D10 device from texture."; + return false; + } + + D3D10_TEXTURE2D_DESC desc; + mTexture->GetDesc(&desc); + mSize.width = desc.Width; + mSize.height = desc.Height; + + return InitD2DRenderTarget(); +} + +// {0D398B49-AE7B-416F-B26D-EA3C137D1CF7} +static const GUID sPrivateDataD2D = +{ 0xd398b49, 0xae7b, 0x416f, { 0xb2, 0x6d, 0xea, 0x3c, 0x13, 0x7d, 0x1c, 0xf7 } }; + +bool +DrawTargetD2D::InitD3D10Data() +{ + HRESULT hr; + + UINT privateDataSize; + privateDataSize = sizeof(mPrivateData); + hr = mDevice->GetPrivateData(sPrivateDataD2D, &privateDataSize, &mPrivateData); + + if (SUCCEEDED(hr)) { + return true; + } + + mPrivateData = new PrivateD3D10DataD2D; + + D3D10CreateEffectFromMemoryFunc createD3DEffect; + HMODULE d3dModule = LoadLibraryW(L"d3d10_1.dll"); + createD3DEffect = (D3D10CreateEffectFromMemoryFunc) + GetProcAddress(d3dModule, "D3D10CreateEffectFromMemory"); + + hr = createD3DEffect((void*)d2deffect, sizeof(d2deffect), 0, mDevice, NULL, byRef(mPrivateData->mEffect)); + + if (FAILED(hr)) { + gfxWarning() << "Failed to initialize Direct2D required effects. Code: " << hr; + return false; + } + + privateDataSize = sizeof(mPrivateData); + mDevice->SetPrivateData(sPrivateDataD2D, privateDataSize, &mPrivateData); + + D3D10_INPUT_ELEMENT_DESC layout[] = + { + { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 }, + }; + D3D10_PASS_DESC passDesc; + + mPrivateData->mEffect->GetTechniqueByName("SampleTexture")->GetPassByIndex(0)->GetDesc(&passDesc); + + hr = mDevice->CreateInputLayout(layout, + sizeof(layout) / sizeof(D3D10_INPUT_ELEMENT_DESC), + passDesc.pIAInputSignature, + passDesc.IAInputSignatureSize, + byRef(mPrivateData->mInputLayout)); + + if (FAILED(hr)) { + gfxWarning() << "Failed to initialize Direct2D required InputLayout. Code: " << hr; + return false; + } + + D3D10_SUBRESOURCE_DATA data; + Vertex vertices[] = { {0.0, 0.0}, {1.0, 0.0}, {0.0, 1.0}, {1.0, 1.0} }; + data.pSysMem = vertices; + CD3D10_BUFFER_DESC bufferDesc(sizeof(vertices), D3D10_BIND_VERTEX_BUFFER); + + hr = mDevice->CreateBuffer(&bufferDesc, &data, byRef(mPrivateData->mVB)); + + if (FAILED(hr)) { + gfxWarning() << "Failed to initialize Direct2D required VertexBuffer. Code: " << hr; + return false; + } + + return true; +} + +/* + * Private helpers + */ +bool +DrawTargetD2D::InitD2DRenderTarget() +{ + if (!factory()) { + return false; + } + + mRT = CreateRTForTexture(mTexture); + + if (!mRT) { + return false; + } + + mRT->BeginDraw(); + + mRT->Clear(D2D1::ColorF(0, 0)); + + return InitD3D10Data(); +} + +void +DrawTargetD2D::PrepareForDrawing(ID2D1RenderTarget *aRT) +{ + if (!mClipsArePushed || aRT == mTempRT) { + if (mPushedClips.size()) { + // The transform of clips is relative to the world matrix, since we use the total + // transform for the clips, make the world matrix identity. + mRT->SetTransform(D2D1::IdentityMatrix()); + for (std::vector::iterator iter = mPushedClips.begin(); + iter != mPushedClips.end(); iter++) { + aRT->PushLayer(D2D1::LayerParameters(D2D1::InfiniteRect(), iter->mPath->mGeometry, + D2D1_ANTIALIAS_MODE_PER_PRIMITIVE, + iter->mTransform), iter->mLayer); + } + if (aRT == mRT) { + mClipsArePushed = true; + } + } + } + mRT->SetTransform(D2DMatrix(mTransform)); + MarkChanged(); + + if (aRT == mTempRT) { + mTempRT->SetTransform(D2DMatrix(mTransform)); + } +} + +void +DrawTargetD2D::MarkChanged() +{ + if (mSnapshots.size()) { + for (std::vector::iterator iter = mSnapshots.begin(); + iter != mSnapshots.end(); iter++) { + (*iter)->DrawTargetWillChange(); + } + // All snapshots will now have copied data. + mSnapshots.clear(); + } + if (mDependentTargets.size()) { + for (std::vector>::iterator iter = mDependentTargets.begin(); + iter != mDependentTargets.end(); iter++) { + (*iter)->Flush(); + } + mDependentTargets.clear(); + } +} + +ID3D10BlendState* +DrawTargetD2D::GetBlendStateForOperator(CompositionOp aOperator) +{ + if (mPrivateData->mBlendStates[aOperator]) { + return mPrivateData->mBlendStates[aOperator]; + } + + D3D10_BLEND_DESC desc; + + memset(&desc, 0, sizeof(D3D10_BLEND_DESC)); + + desc.AlphaToCoverageEnable = FALSE; + desc.BlendEnable[0] = TRUE; + desc.RenderTargetWriteMask[0] = D3D10_COLOR_WRITE_ENABLE_ALL; + desc.BlendOp = desc.BlendOpAlpha = D3D10_BLEND_OP_ADD; + + switch (aOperator) { + case OP_ADD: + desc.SrcBlend = desc.SrcBlendAlpha = D3D10_BLEND_ONE; + desc.DestBlend = desc.DestBlendAlpha = D3D10_BLEND_ONE; + break; + case OP_IN: + desc.SrcBlend = desc.SrcBlendAlpha = D3D10_BLEND_DEST_ALPHA; + desc.DestBlend = desc.DestBlendAlpha = D3D10_BLEND_ZERO; + break; + case OP_OUT: + desc.SrcBlend = desc.SrcBlendAlpha = D3D10_BLEND_INV_DEST_ALPHA; + desc.DestBlend = desc.DestBlendAlpha = D3D10_BLEND_ZERO; + break; + case OP_ATOP: + desc.SrcBlend = desc.SrcBlendAlpha = D3D10_BLEND_DEST_ALPHA; + desc.DestBlend = desc.DestBlendAlpha = D3D10_BLEND_INV_SRC_ALPHA; + break; + case OP_DEST_IN: + desc.SrcBlend = desc.SrcBlendAlpha = D3D10_BLEND_ZERO; + desc.DestBlend = desc.DestBlendAlpha = D3D10_BLEND_SRC_ALPHA; + break; + case OP_DEST_OUT: + desc.SrcBlend = desc.SrcBlendAlpha = D3D10_BLEND_ZERO; + desc.DestBlend = desc.DestBlendAlpha = D3D10_BLEND_INV_SRC_ALPHA; + break; + case OP_DEST_ATOP: + desc.SrcBlend = desc.SrcBlendAlpha = D3D10_BLEND_INV_DEST_ALPHA; + desc.DestBlend = desc.DestBlendAlpha = D3D10_BLEND_SRC_ALPHA; + break; + case OP_DEST_OVER: + desc.SrcBlend = desc.SrcBlendAlpha = D3D10_BLEND_INV_DEST_ALPHA; + desc.DestBlend = desc.DestBlendAlpha = D3D10_BLEND_ONE; + break; + case OP_XOR: + desc.SrcBlend = desc.SrcBlendAlpha = D3D10_BLEND_INV_DEST_ALPHA; + desc.DestBlend = desc.DestBlendAlpha = D3D10_BLEND_INV_SRC_ALPHA; + break; + case OP_SOURCE: + desc.SrcBlend = desc.SrcBlendAlpha = D3D10_BLEND_ONE; + desc.DestBlend = desc.DestBlendAlpha = D3D10_BLEND_ZERO; + break; + default: + desc.SrcBlend = desc.SrcBlendAlpha = D3D10_BLEND_ONE; + desc.DestBlend = desc.DestBlendAlpha = D3D10_BLEND_INV_SRC_ALPHA; + } + + mDevice->CreateBlendState(&desc, byRef(mPrivateData->mBlendStates[aOperator])); + + return mPrivateData->mBlendStates[aOperator]; +} + +/* This function prepares the temporary RT for drawing and returns it when a + * drawing operation other than OVER is required. + */ +ID2D1RenderTarget* +DrawTargetD2D::GetRTForOperator(CompositionOp aOperator) +{ + if (aOperator == OP_OVER) { + return mRT; + } + + PopAllClips(); + + if (mTempRT) { + mTempRT->Clear(D2D1::ColorF(0, 0)); + return mTempRT; + } + + EnsureViews(); + + if (!mRTView || !mSRView) { + gfxDebug() << *this << ": Failed to get required views. Defaulting to OP_OVER."; + return mRT; + } + + mTempRT = CreateRTForTexture(mTempTexture); + + if (!mTempRT) { + return mRT; + } + + mTempRT->BeginDraw(); + + mTempRT->Clear(D2D1::ColorF(0, 0)); + + return mTempRT; +} + +/* This function blends back the content of a drawing operation (drawn to an + * empty surface with OVER, so the surface now contains the source operation + * contents) to the rendertarget using the requested composition operation. + * In order to respect clip for operations which are unbound by their mask, + * the old content of the surface outside the clipped area may be blended back + * to the surface. + */ +void +DrawTargetD2D::FinalizeRTForOperator(CompositionOp aOperator, const Rect &aBounds) +{ + if (aOperator == OP_OVER) { + return; + } + + if (!mTempRT) { + return; + } + + for (unsigned int i = 0; i < mPushedClips.size(); i++) { + mTempRT->PopLayer(); + } + + mRT->Flush(); + mTempRT->Flush(); + + AutoSaveRestoreClippedOut restoreClippedOut(this); + + bool needsWriteBack = + !IsOperatorBoundByMask(aOperator) && mPushedClips.size(); + + if (needsWriteBack) { + restoreClippedOut.Save(); + } + + ID3D10RenderTargetView *rtViews = mRTView; + mDevice->OMSetRenderTargets(1, &rtViews, NULL); + + UINT stride = sizeof(Vertex); + UINT offset = 0; + ID3D10Buffer *buff = mPrivateData->mVB; + + mDevice->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + mDevice->IASetVertexBuffers(0, 1, &buff, &stride, &offset); + mDevice->IASetInputLayout(mPrivateData->mInputLayout); + + D3D10_VIEWPORT viewport; + viewport.MaxDepth = 1; + viewport.MinDepth = 0; + viewport.Height = mSize.height; + viewport.Width = mSize.width; + viewport.TopLeftX = 0; + viewport.TopLeftY = 0; + + mDevice->RSSetViewports(1, &viewport); + mPrivateData->mEffect->GetVariableByName("tex")->AsShaderResource()->SetResource(mSRView); + mPrivateData->mEffect->GetVariableByName("QuadDesc")->AsVector()-> + SetFloatVector(ShaderConstantRectD3D10(-1.0f, 1.0f, 2.0f, -2.0f)); + mPrivateData->mEffect->GetVariableByName("TexCoords")->AsVector()-> + SetFloatVector(ShaderConstantRectD3D10(0, 0, 1.0f, 1.0f)); + + mPrivateData->mEffect->GetTechniqueByName("SampleTexture")->GetPassByIndex(0)->Apply(0); + + mDevice->OMSetBlendState(GetBlendStateForOperator(aOperator), NULL, 0xffffffff); + + mDevice->Draw(4, 0); +} + +TemporaryRef +DrawTargetD2D::CreateRTForTexture(ID3D10Texture2D *aTexture) +{ + HRESULT hr; + + RefPtr surface; + RefPtr rt; + + hr = aTexture->QueryInterface((IDXGISurface**)byRef(surface)); + + if (FAILED(hr)) { + gfxWarning() << "Failed to QI texture to surface."; + return NULL; + } + + D3D10_TEXTURE2D_DESC desc; + aTexture->GetDesc(&desc); + + D2D1_RENDER_TARGET_PROPERTIES props = + D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_DEFAULT, D2D1::PixelFormat(desc.Format, D2D1_ALPHA_MODE_PREMULTIPLIED)); + hr = factory()->CreateDxgiSurfaceRenderTarget(surface, props, byRef(rt)); + + if (FAILED(hr)) { + gfxWarning() << "Failed to create D2D render target for texture."; + return NULL; + } + + return rt; +} + +void +DrawTargetD2D::EnsureViews() +{ + if (mTempTexture && mSRView && mRTView) { + return; + } + + HRESULT hr; + + CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM, + mSize.width, + mSize.height, + 1, 1); + desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE; + + hr = mDevice->CreateTexture2D(&desc, NULL, byRef(mTempTexture)); + + if (FAILED(hr)) { + gfxWarning() << *this << "Failed to create temporary texture for rendertarget. Size: " + << mSize << " Code: " << hr; + return; + } + + hr = mDevice->CreateShaderResourceView(mTempTexture, NULL, byRef(mSRView)); + + if (FAILED(hr)) { + gfxWarning() << *this << "Failed to create shader resource view for temp texture. Code: " << hr; + return; + } + + hr = mDevice->CreateRenderTargetView(mTexture, NULL, byRef(mRTView)); + + if (FAILED(hr)) { + gfxWarning() << *this << "Failed to create rendertarget view for temp texture. Code: " << hr; + } +} + +void +DrawTargetD2D::PopAllClips() +{ + if (mClipsArePushed) { + for (unsigned int i = 0; i < mPushedClips.size(); i++) { + mRT->PopLayer(); + } + + mClipsArePushed = false; + } +} + +TemporaryRef +DrawTargetD2D::CreateBrushForPattern(const Pattern &aPattern, Float aAlpha) +{ + if (aPattern.GetType() == PATTERN_COLOR) { + RefPtr colBrush; + Color color = static_cast(&aPattern)->mColor; + mRT->CreateSolidColorBrush(D2D1::ColorF(color.r, color.g, + color.b, color.a), + D2D1::BrushProperties(aAlpha), + byRef(colBrush)); + return colBrush; + } else if (aPattern.GetType() == PATTERN_LINEAR_GRADIENT) { + RefPtr gradBrush; + const LinearGradientPattern *pat = + static_cast(&aPattern); + + GradientStopsD2D *stops = static_cast(pat->mStops.get()); + + if (!stops) { + gfxDebug() << "No stops specified for gradient pattern."; + return NULL; + } + + mRT->CreateLinearGradientBrush(D2D1::LinearGradientBrushProperties(D2DPoint(pat->mBegin), + D2DPoint(pat->mEnd)), + D2D1::BrushProperties(aAlpha), + stops->mStopCollection, + byRef(gradBrush)); + return gradBrush; + } else if (aPattern.GetType() == PATTERN_RADIAL_GRADIENT) { + RefPtr gradBrush; + const RadialGradientPattern *pat = + static_cast(&aPattern); + + GradientStopsD2D *stops = static_cast(pat->mStops.get()); + + if (!stops) { + gfxDebug() << "No stops specified for gradient pattern."; + return NULL; + } + + mRT->CreateRadialGradientBrush(D2D1::RadialGradientBrushProperties(D2DPoint(pat->mCenter), + D2DPoint(pat->mOrigin - pat->mCenter), + pat->mRadius, + pat->mRadius), + D2D1::BrushProperties(aAlpha), + stops->mStopCollection, + byRef(gradBrush)); + return gradBrush; + } else if (aPattern.GetType() == PATTERN_SURFACE) { + RefPtr bmBrush; + const SurfacePattern *pat = + static_cast(&aPattern); + + if (!pat->mSurface) { + gfxDebug() << "No source surface specified for surface pattern"; + return NULL; + } + + RefPtr bitmap; + + switch (pat->mSurface->GetType()) { + case SURFACE_D2D1_BITMAP: + { + SourceSurfaceD2D *surf = static_cast(pat->mSurface.get()); + + bitmap = surf->mBitmap; + + if (!bitmap) { + gfxDebug() << "Source surface used for pattern too large!"; + return NULL; + } + } + break; + case SURFACE_D2D1_DRAWTARGET: + { + SourceSurfaceD2DTarget *surf = + static_cast(pat->mSurface.get()); + + bitmap = surf->GetBitmap(mRT); + + if (!surf->IsCopy()) { + surf->mDrawTarget->mDependentTargets.push_back(this); + } + } + break; + } + + D2D1_EXTEND_MODE extend = D2D1_EXTEND_MODE_CLAMP; + switch (pat->mExtendMode) { + case EXTEND_WRAP: + extend = D2D1_EXTEND_MODE_WRAP; + break; + case EXTEND_MIRROR: + extend = D2D1_EXTEND_MODE_MIRROR; + break; + } + + mRT->CreateBitmapBrush(bitmap, + D2D1::BitmapBrushProperties(extend, + extend, + D2DFilter(pat->mFilter)), + D2D1::BrushProperties(aAlpha), + byRef(bmBrush)); + + return bmBrush; + } + + gfxWarning() << "Invalid pattern type detected."; + return NULL; +} + +TemporaryRef +DrawTargetD2D::CreateStrokeStyleForOptions(const StrokeOptions &aStrokeOptions) +{ + RefPtr style; + + D2D1_CAP_STYLE capStyle; + D2D1_LINE_JOIN joinStyle; + + switch (aStrokeOptions.mLineCap) { + case CAP_BUTT: + capStyle = D2D1_CAP_STYLE_FLAT; + break; + case CAP_ROUND: + capStyle = D2D1_CAP_STYLE_ROUND; + break; + case CAP_SQUARE: + capStyle = D2D1_CAP_STYLE_SQUARE; + break; + } + + switch (aStrokeOptions.mLineJoin) { + case JOIN_MITER: + joinStyle = D2D1_LINE_JOIN_MITER; + break; + case JOIN_MITER_OR_BEVEL: + joinStyle = D2D1_LINE_JOIN_MITER_OR_BEVEL; + break; + case JOIN_ROUND: + joinStyle = D2D1_LINE_JOIN_ROUND; + break; + case JOIN_BEVEL: + joinStyle = D2D1_LINE_JOIN_BEVEL; + break; + } + + + HRESULT hr = factory()->CreateStrokeStyle(D2D1::StrokeStyleProperties(capStyle, capStyle, + capStyle, joinStyle, + aStrokeOptions.mMiterLimit), + NULL, 0, byRef(style)); + + if (FAILED(hr)) { + gfxWarning() << "Failed to create Direct2D stroke style."; + } + + return style; +} + +ID2D1Factory* +DrawTargetD2D::factory() +{ + if (mFactory) { + return mFactory; + } + + D2D1CreateFactoryFunc createD2DFactory; + HMODULE d2dModule = LoadLibraryW(L"d2d1.dll"); + createD2DFactory = (D2D1CreateFactoryFunc) + GetProcAddress(d2dModule, "D2D1CreateFactory"); + + if (!createD2DFactory) { + gfxWarning() << "Failed to locate D2D1CreateFactory function."; + return NULL; + } + + D2D1_FACTORY_OPTIONS options; +#ifdef _DEBUG + options.debugLevel = D2D1_DEBUG_LEVEL_NONE; +#else + options.debugLevel = D2D1_DEBUG_LEVEL_NONE; +#endif + + HRESULT hr = createD2DFactory(D2D1_FACTORY_TYPE_MULTI_THREADED, + __uuidof(ID2D1Factory), + &options, + (void**)&mFactory); + + if (FAILED(hr)) { + gfxWarning() << "Failed to create Direct2D factory."; + } + + return mFactory; +} + +} +} diff --git a/gfx/2d/DrawTargetD2D.h b/gfx/2d/DrawTargetD2D.h new file mode 100644 index 00000000000..7c163298bbb --- /dev/null +++ b/gfx/2d/DrawTargetD2D.h @@ -0,0 +1,204 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.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/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Corporation code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Bas Schouten + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef MOZILLA_GFX_DRAWTARGETD2D_H_ +#define MOZILLA_GFX_DRAWTARGETD2D_H_ + +#include "2D.h" +#include "PathD2D.h" +#include +#include "HelpersD2D.h" + +#include +#include + +namespace mozilla { +namespace gfx { + +class SourceSurfaceD2DTarget; + +struct PrivateD3D10DataD2D +{ + RefPtr mEffect; + RefPtr mInputLayout; + RefPtr mVB; + RefPtr mBlendStates[OP_COUNT]; +}; + +class DrawTargetD2D : public DrawTarget +{ +public: + DrawTargetD2D(); + virtual ~DrawTargetD2D(); + + virtual BackendType GetType() const { return BACKEND_DIRECT2D; } + virtual TemporaryRef Snapshot(); + virtual IntSize GetSize() { return mSize; } + + virtual void Flush(); + virtual void DrawSurface(SourceSurface *aSurface, + const Rect &aDest, + const Rect &aSource, + const DrawSurfaceOptions &aSurfOptions = DrawSurfaceOptions(), + const DrawOptions &aOptions = DrawOptions()); + virtual void DrawSurfaceWithShadow(SourceSurface *aSurface, + const Point &aDest, + const Color &aColor, + const Point &aOffset, + Float aSigma); + virtual void ClearRect(const Rect &aRect); + + virtual void CopySurface(SourceSurface *aSurface, + const IntRect &aSourceRect, + const IntPoint &aDestination); + + virtual void FillRect(const Rect &aRect, + const Pattern &aPattern, + const DrawOptions &aOptions = DrawOptions()); + virtual void StrokeRect(const Rect &aRect, + const Pattern &aPattern, + const StrokeOptions &aStrokeOptions = StrokeOptions(), + const DrawOptions &aOptions = DrawOptions()); + virtual void StrokeLine(const Point &aStart, + const Point &aEnd, + const Pattern &aPattern, + const StrokeOptions &aStrokeOptions = StrokeOptions(), + const DrawOptions &aOptions = DrawOptions()); + virtual void Stroke(const Path *aPath, + const Pattern &aPattern, + const StrokeOptions &aStrokeOptions = StrokeOptions(), + const DrawOptions &aOptions = DrawOptions()); + virtual void Fill(const Path *aPath, + const Pattern &aPattern, + const DrawOptions &aOptions = DrawOptions()); + virtual void FillGlyphs(ScaledFont *aFont, + const GlyphBuffer &aBuffer, + const Pattern &aPattern, + const DrawOptions &aOptions = DrawOptions()); + virtual void PushClip(const Path *aPath); + virtual void PopClip(); + + virtual TemporaryRef CreateSourceSurfaceFromData(unsigned char *aData, + const IntSize &aSize, + int32_t aStride, + SurfaceFormat aFormat) const; + virtual TemporaryRef OptimizeSourceSurface(SourceSurface *aSurface) const; + + virtual TemporaryRef + CreateSourceSurfaceFromNativeSurface(const NativeSurface &aSurface) const; + + virtual TemporaryRef + CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFormat) const; + + virtual TemporaryRef CreatePathBuilder(FillRule aFillRule = FILL_WINDING) const; + + virtual TemporaryRef CreateGradientStops(GradientStop *aStops, uint32_t aNumStops) const; + + virtual void *GetNativeSurface(NativeSurfaceType aType); + + bool Init(const IntSize &aSize, SurfaceFormat aFormat); + bool Init(ID3D10Texture2D *aTexture, SurfaceFormat aFormat); + bool InitD3D10Data(); + + static ID2D1Factory *factory(); + + operator std::string() const { + std::stringstream stream; + stream << "DrawTargetD2D(" << this << ")"; + return stream.str(); + } +private: + friend class AutoSaveRestoreClippedOut; + friend class SourceSurfaceD2DTarget; + + bool InitD2DRenderTarget(); + void PrepareForDrawing(ID2D1RenderTarget *aRT); + + // This function will mark the surface as changing, and make sure any + // copy-on-write snapshots are notified. + void MarkChanged(); + + ID3D10BlendState *GetBlendStateForOperator(CompositionOp aOperator); + ID2D1RenderTarget *GetRTForOperator(CompositionOp aOperator); + void FinalizeRTForOperator(CompositionOp aOperator, const Rect &aBounds); + void EnsureViews(); + void PopAllClips(); + + TemporaryRef CreateRTForTexture(ID3D10Texture2D *aTexture); + + TemporaryRef CreateBrushForPattern(const Pattern &aPattern, Float aAlpha = 1.0f); + TemporaryRef CreateStrokeStyleForOptions(const StrokeOptions &aStrokeOptions); + + IntSize mSize; + + RefPtr mDevice; + RefPtr mTexture; + mutable RefPtr mRT; + + // Temporary texture and render target used for supporting alternative operators. + RefPtr mTempTexture; + RefPtr mRTView; + RefPtr mSRView; + RefPtr mTempRT; + RefPtr mTempRTView; + + // List of pushed clips. + struct PushedClip + { + RefPtr mLayer; + D2D1_RECT_F mBounds; + D2D1_MATRIX_3X2_F mTransform; + RefPtr mPath; + }; + std::vector mPushedClips; + + // List of Snapshots of this surface, these need to be told when this + // surface is modified. Possibly vector is not the best choice here. + std::vector mSnapshots; + // A list of targets we need to flush when we're modified. + std::vector> mDependentTargets; + + // True of the current clip stack is pushed to the main RT. + bool mClipsArePushed; + PrivateD3D10DataD2D *mPrivateData; + static ID2D1Factory *mFactory; +}; + +} +} + +#endif /* MOZILLA_GFX_DRAWTARGETD2D_H_ */ diff --git a/gfx/2d/Factory.cpp b/gfx/2d/Factory.cpp new file mode 100644 index 00000000000..527694e4976 --- /dev/null +++ b/gfx/2d/Factory.cpp @@ -0,0 +1,152 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.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/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Corporation code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Bas Schouten + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "2D.h" + +#ifdef USE_CAIRO +#include "DrawTargetCairo.h" +#endif + +#ifdef WIN32 +#include "DrawTargetD2D.h" +#include "ScaledFontDWrite.h" +#include +#endif + +#include "Logging.h" + +#ifdef PR_LOGGING +PRLogModuleInfo *sGFX2DLog = PR_NewLogModule("gfx2d"); +#endif + +namespace mozilla { +namespace gfx { + +// XXX - Need to define an API to set this. +int sGfxLogLevel = LOG_DEBUG; + +#ifdef WIN32 +ID3D10Device1 *Factory::mD3D10Device; +#endif + +TemporaryRef +Factory::CreateDrawTarget(BackendType aBackend, const IntSize &aSize, SurfaceFormat aFormat) +{ + switch (aBackend) { +#ifdef WIN32 + case BACKEND_DIRECT2D: + { + RefPtr newTarget; + newTarget = new DrawTargetD2D(); + if (newTarget->Init(aSize, aFormat)) { + return newTarget; + } + break; + } +#endif + default: + gfxDebug() << "Invalid draw target type specified."; + return NULL; + } + + gfxDebug() << "Failed to create DrawTarget, Type: " << aBackend << " Size: " << aSize; + // Failed + return NULL; +} + +TemporaryRef +Factory::CreateScaledFontForNativeFont(const NativeFont &aNativeFont, Float aSize) +{ + switch (aNativeFont.mType) { +#ifdef WIN32 + case NATIVE_FONT_DWRITE_FONT_FACE: + { + return new ScaledFontDWrite(static_cast(aNativeFont.mFont), aSize); + } +#endif + default: + gfxWarning() << "Invalid native font type specified."; + return NULL; + } +} + +#ifdef WIN32 +TemporaryRef +Factory::CreateDrawTargetForD3D10Texture(ID3D10Texture2D *aTexture, SurfaceFormat aFormat) +{ + RefPtr newTarget; + + newTarget = new DrawTargetD2D(); + if (newTarget->Init(aTexture, aFormat)) { + return newTarget; + } + + gfxWarning() << "Failed to create draw target for D3D10 texture."; + + // Failed + return NULL; +} + +void +Factory::SetDirect3D10Device(ID3D10Device1 *aDevice) +{ + mD3D10Device = aDevice; +} + +ID3D10Device1* +Factory::GetDirect3D10Device() +{ + return mD3D10Device; +} + +#endif // XP_WIN + +#ifdef USE_CAIRO +TemporaryRef +Factory::CreateDrawTargetForCairoSurface(cairo_surface_t* aSurface) +{ + RefPtr newTarget = new DrawTargetCairo(); + if (newTarget->Init(aSurface)) { + return newTarget; + } + + return NULL; +} +#endif + +} +} diff --git a/gfx/2d/GradientStopsD2D.h b/gfx/2d/GradientStopsD2D.h new file mode 100644 index 00000000000..bdb228c9114 --- /dev/null +++ b/gfx/2d/GradientStopsD2D.h @@ -0,0 +1,66 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.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/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Corporation code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Bas Schouten + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef MOZILLA_GFX_GRADIENTSTOPSD2D_H_ +#define MOZILLA_GFX_GRADIENTSTOPSD2D_H_ + +#include "2D.h" + +#include + +namespace mozilla { +namespace gfx { + +class GradientStopsD2D : public GradientStops +{ +public: + GradientStopsD2D(ID2D1GradientStopCollection *aStopCollection) + : mStopCollection(aStopCollection) + {} + + virtual BackendType GetBackendType() const { return BACKEND_DIRECT2D; } + +private: + friend class DrawTargetD2D; + + mutable RefPtr mStopCollection; +}; + +} +} + +#endif /* MOZILLA_GFX_GRADIENTSTOPSD2D_H_ */ diff --git a/gfx/2d/HelpersD2D.h b/gfx/2d/HelpersD2D.h new file mode 100644 index 00000000000..a1c1a0a5d97 --- /dev/null +++ b/gfx/2d/HelpersD2D.h @@ -0,0 +1,175 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.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/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Corporation code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Bas Schouten + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef MOZILLA_GFX_HELPERSD2D_H_ +#define MOZILLA_GFX_HELPERSD2D_H_ + +#include +#include "2D.h" + +namespace mozilla { +namespace gfx { + +static inline D2D1_POINT_2F D2DPoint(const Point &aPoint) +{ + return D2D1::Point2F(aPoint.x, aPoint.y); +} + +static inline D2D1_SIZE_U D2DIntSize(const IntSize &aSize) +{ + return D2D1::SizeU(aSize.width, aSize.height); +} + +static inline D2D1_RECT_F D2DRect(const Rect &aRect) +{ + return D2D1::RectF(aRect.x, aRect.y, aRect.XMost(), aRect.YMost()); +} + +static inline D2D1_BITMAP_INTERPOLATION_MODE D2DFilter(const Filter &aFilter) +{ + switch (aFilter) { + case FILTER_POINT: + return D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR; + } + + return D2D1_BITMAP_INTERPOLATION_MODE_LINEAR; +} + +static inline D2D1_ANTIALIAS_MODE D2DAAMode(const AntialiasMode &aMode) +{ + switch (aMode) { + case AA_NONE: + D2D1_ANTIALIAS_MODE_ALIASED; + } + + return D2D1_ANTIALIAS_MODE_PER_PRIMITIVE; +} + +static inline D2D1_MATRIX_3X2_F D2DMatrix(const Matrix &aTransform) +{ + return D2D1::Matrix3x2F(aTransform._11, aTransform._12, + aTransform._21, aTransform._22, + aTransform._31, aTransform._32); +} + +static inline D2D1_COLOR_F D2DColor(const Color &aColor) +{ + return D2D1::ColorF(aColor.r, aColor.g, aColor.b, aColor.a); +} + +static inline IntSize ToIntSize(const D2D1_SIZE_U &aSize) +{ + return IntSize(aSize.width, aSize.height); +} + +static inline SurfaceFormat ToPixelFormat(const D2D1_PIXEL_FORMAT &aFormat) +{ + switch(aFormat.format) { + case DXGI_FORMAT_A8_UNORM: + return FORMAT_A8; + case DXGI_FORMAT_B8G8R8A8_UNORM: + if (aFormat.alphaMode == D2D1_ALPHA_MODE_IGNORE) { + return FORMAT_B8G8R8X8; + } else { + return FORMAT_B8G8R8A8; + } + } + + return FORMAT_B8G8R8A8; +} + +static inline Rect ToRect(const D2D1_RECT_F &aRect) +{ + return Rect(aRect.left, aRect.top, aRect.right - aRect.left, aRect.bottom - aRect.top); +} + +static inline DXGI_FORMAT DXGIFormat(SurfaceFormat aFormat) +{ + switch (aFormat) { + case FORMAT_B8G8R8A8: + return DXGI_FORMAT_B8G8R8A8_UNORM; + case FORMAT_B8G8R8X8: + return DXGI_FORMAT_B8G8R8A8_UNORM; + case FORMAT_A8: + return DXGI_FORMAT_A8_UNORM; + } + + return DXGI_FORMAT_UNKNOWN; +} + +static inline D2D1_ALPHA_MODE AlphaMode(SurfaceFormat aFormat) +{ + switch (aFormat) { + case FORMAT_B8G8R8X8: + return D2D1_ALPHA_MODE_IGNORE; + } + + return D2D1_ALPHA_MODE_PREMULTIPLIED; +} + +static inline int BytesPerPixel(SurfaceFormat aFormat) +{ + switch (aFormat) { + case FORMAT_A8: + return 1; + default: + return 4; + } +} + +/** + * This structure is used to pass rectangles to our shader constant. We can use + * this for passing rectangular areas to SetVertexShaderConstant. In the format + * of a 4 component float(x,y,width,height). Our vertex shader can then use + * this to construct rectangular positions from the 0,0-1,1 quad that we source + * it with. + */ +struct ShaderConstantRectD3D10 +{ + float mX, mY, mWidth, mHeight; + ShaderConstantRectD3D10(float aX, float aY, float aWidth, float aHeight) + : mX(aX), mY(aY), mWidth(aWidth), mHeight(aHeight) + { } + + // For easy passing to SetVertexShaderConstantF. + operator float* () { return &mX; } +}; + +} +} + +#endif /* MOZILLA_GFX_HELPERSD2D_H_ */ diff --git a/gfx/2d/Logging.h b/gfx/2d/Logging.h new file mode 100644 index 00000000000..dcc365082ab --- /dev/null +++ b/gfx/2d/Logging.h @@ -0,0 +1,144 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.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/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Corporation code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Bas Schouten + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef MOZILLA_GFX_LOGGING_H_ +#define MOZILLA_GFX_LOGGING_H_ + +#include +#include + +#include "Point.h" + +#ifdef WIN32 +#include +#endif + +#ifdef PR_LOGGING +#include + +extern PRLogModuleInfo *sGFX2DLog; +#endif + +namespace mozilla { +namespace gfx { + +const int LOG_DEBUG = 1; +const int LOG_WARNING = 2; + +#ifdef PR_LOGGING + +inline PRLogModuleLevel PRLogLevelForLevel(int aLevel) { + switch (aLevel) { + case LOG_DEBUG: + return PR_LOG_DEBUG; + case LOG_WARNING: + return PR_LOG_WARNING; + } + return PR_LOG_DEBUG; +} + +#endif + +extern int sGfxLogLevel; + +static void OutputMessage(const std::string &aString, int aLevel) { +#if defined(WIN32) && !defined(PR_LOGGING) + if (aLevel >= sGfxLogLevel) { + ::OutputDebugStringA(aString.c_str()); + } +#elif defined(PR_LOGGING) + if (PR_LOG_TEST(sGFX2DLog, PRLogLevelForLevel(aLevel))) { + PR_LogPrint(aString.c_str()); + } +#else + if (aLevel >= sGfxLogLevel) { + printf(aString.c_str()); + } +#endif +} + +class NoLog +{ +public: + NoLog() {} + ~NoLog() {} + + template + NoLog &operator <<(const T &aLogText) { return *this; } +}; + +template +class Log +{ +public: + Log() {} + ~Log() { mMessage << '\n'; WriteLog(mMessage.str()); } + + Log &operator <<(const std::string &aLogText) { mMessage << aLogText; return *this; } + Log &operator <<(unsigned int aInt) { mMessage << aInt; return *this; } + Log &operator <<(const Size &aSize) + { mMessage << "(" << aSize.width << "x" << aSize.height << ")"; return *this; } + Log &operator <<(const IntSize &aSize) + { mMessage << "(" << aSize.width << "x" << aSize.height << ")"; return *this; } + +private: + + void WriteLog(const std::string &aString) { + OutputMessage(aString, L); + } + + std::stringstream mMessage; +}; + +typedef Log DebugLog; +typedef Log WarningLog; + +#ifdef GFX_LOG_DEBUG +#define gfxDebug DebugLog +#else +#define gfxDebug if (1) ; else NoLog +#endif +#ifdef GFX_LOG_WARNING +#define gfxWarning WarningLog +#else +#define gfxWarning if (1) ; else NoLog +#endif + +} +} + +#endif /* MOZILLA_GFX_LOGGING_H_ */ diff --git a/gfx/2d/Makefile.in b/gfx/2d/Makefile.in new file mode 100644 index 00000000000..e7ed0f45058 --- /dev/null +++ b/gfx/2d/Makefile.in @@ -0,0 +1,100 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.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/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is Mozilla Corporation code. +# +# The Initial Developer of the Original Code is Mozilla Foundation. +# Portions created by the Initial Developer are Copyright (C) 2011 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Bas Schouten +# +# Alternatively, the contents of this file may be used under the terms of +# either of the GNU General Public License Version 2 or later (the "GPL"), +# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = gfx2d +LIBRARY_NAME = gfx2d +LIBXUL_LIBRARY = 1 +EXPORT_LIBRARY = 1 + +EXPORTS_NAMESPACES = mozilla/gfx +EXPORTS_mozilla/gfx = \ + 2D.h \ + BasePoint.h \ + BaseMargin.h \ + BaseRect.h \ + BaseSize.h \ + Point.h \ + Matrix.h \ + Rect.h \ + Types.h \ + $(NULL) + +CPPSRCS = \ + Factory.cpp \ + Matrix.cpp \ + DrawTargetCairo.cpp \ + SourceSurfaceCairo.cpp \ + $(NULL) + +DEFINES += -DMOZ_GFX -DUSE_CAIRO + +ifdef MOZ_DEBUG +DEFINES += -DGFX_LOG_DEBUG -DGFX_LOG_WARNING +endif + +ifeq ($(MOZ_WIDGET_TOOLKIT),windows) +CPPSRCS += \ + DrawTargetD2D.cpp \ + SourceSurfaceD2D.cpp \ + SourceSurfaceD2DTarget.cpp \ + PathD2D.cpp \ + ScaledFontDWrite.cpp \ + $(NULL) + +DEFINES += -DWIN32 +endif + +#ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa) +#CPPSRCS += \ +# DrawTargetCG.cpp \ +# SourceSurfaceCG.cpp \ +# $(NULL) +# +## Always link with OpenGL/AGL +#EXTRA_DSO_LDOPTS += -framework OpenGL -framework AGL -framework QuickTime -framework AppKit -framework QuartzCore +#endif + + + +include $(topsrcdir)/config/rules.mk diff --git a/gfx/2d/Matrix.cpp b/gfx/2d/Matrix.cpp new file mode 100644 index 00000000000..641a97c9d5d --- /dev/null +++ b/gfx/2d/Matrix.cpp @@ -0,0 +1,92 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.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/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Corporation code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Bas Schouten + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "Matrix.h" +#include + +namespace mozilla { +namespace gfx { + +Matrix +Matrix::Rotation(Float aAngle) +{ + Matrix newMatrix; + + Float s = sin(aAngle); + Float c = cos(aAngle); + + newMatrix._11 = c; + newMatrix._12 = s; + newMatrix._21 = -s; + newMatrix._22 = c; + + return newMatrix; +} + +Rect +Matrix::TransformBounds(const Rect &aRect) const +{ + int i; + Point quad[4]; + Float min_x, max_x; + Float min_y, max_y; + + quad[0] = *this * aRect.TopLeft(); + quad[1] = *this * aRect.TopRight(); + quad[2] = *this * aRect.BottomLeft(); + quad[3] = *this * aRect.BottomRight(); + + min_x = max_x = quad[0].x; + min_y = max_y = quad[0].y; + + for (i = 1; i < 4; i++) { + if (quad[i].x < min_x) + min_x = quad[i].x; + if (quad[i].x > max_x) + max_x = quad[i].x; + + if (quad[i].y < min_y) + min_y = quad[i].y; + if (quad[i].y > max_y) + max_y = quad[i].y; + } + + return Rect(min_x, min_y, max_x - min_x, max_y - min_y); +} + +} +} diff --git a/gfx/2d/Matrix.h b/gfx/2d/Matrix.h new file mode 100644 index 00000000000..195b8e2e712 --- /dev/null +++ b/gfx/2d/Matrix.h @@ -0,0 +1,151 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.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/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Corporation code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Bas Schouten + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef MOZILLA_GFX_MATRIX_H_ +#define MOZILLA_GFX_MATRIX_H_ + +#include "Types.h" +#include "Rect.h" +#include "Point.h" +#include + +namespace mozilla { +namespace gfx { + +class Matrix +{ +public: + Matrix() + : _11(1.0f), _12(0) + , _21(0), _22(1.0f) + , _31(0), _32(0) + {} + Matrix(Float a11, Float a12, Float a21, Float a22, Float a31, Float a32) + : _11(a11), _12(a12) + , _21(a21), _22(a22) + , _31(a31), _32(a32) + {} + Float _11, _12; + Float _21, _22; + Float _31, _32; + + Point operator *(const Point &aPoint) const + { + Point retPoint; + + retPoint.x = aPoint.x * _11 + aPoint.y * _21 + _31; + retPoint.y = aPoint.x * _12 + aPoint.y * _22 + _32; + + return retPoint; + } + + Rect TransformBounds(const Rect& rect) const; + + // Apply a scale to this matrix. This scale will be applied -before- the + // existing transformation of the matrix. + Matrix &Scale(Float aX, Float aY) + { + _11 *= aX; + _12 *= aX; + _21 *= aY; + _22 *= aY; + + return *this; + } + + Matrix &Translate(Float aX, Float aY) + { + _31 += _11 * aX + _21 * aY; + _32 += _12 * aX + _22 * aY; + + return *this; + } + + bool Invert() + { + // Compute co-factors. + Float A = _22; + Float B = -_21; + Float C = _21 * _32 - _22 * _31; + Float D = -_12; + Float E = _11; + Float F = _31 * _12 - _11 * _32; + + Float det = Determinant(); + + if (!det) { + return false; + } + + Float inv_det = 1 / det; + + _11 = inv_det * A; + _12 = inv_det * D; + _21 = inv_det * B; + _22 = inv_det * E; + _31 = inv_det * C; + _32 = inv_det * F; + + return true; + } + + Float Determinant() const + { + return _11 * _22 - _12 * _21; + } + + static Matrix Rotation(Float aAngle); + + Matrix operator*(const Matrix &aMatrix) const + { + Matrix resultMatrix; + + resultMatrix._11 = this->_11 * aMatrix._11 + this->_12 * aMatrix._21; + resultMatrix._12 = this->_11 * aMatrix._12 + this->_12 * aMatrix._22; + resultMatrix._21 = this->_21 * aMatrix._11 + this->_22 * aMatrix._21; + resultMatrix._22 = this->_21 * aMatrix._12 + this->_22 * aMatrix._22; + resultMatrix._31 = this->_31 * aMatrix._11 + this->_32 * aMatrix._21 + aMatrix._31; + resultMatrix._32 = this->_31 * aMatrix._12 + this->_32 * aMatrix._22 + aMatrix._32; + + return resultMatrix; + } +}; + +} +} + +#endif /* MOZILLA_GFX_MATRIX_H_ */ diff --git a/gfx/2d/PathD2D.cpp b/gfx/2d/PathD2D.cpp new file mode 100644 index 00000000000..34c9f3e825d --- /dev/null +++ b/gfx/2d/PathD2D.cpp @@ -0,0 +1,348 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.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/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Corporation code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Bas Schouten + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#pragma once + +#include "PathD2D.h" +#include "HelpersD2D.h" +#include +#include "DrawTargetD2D.h" +#include "Logging.h" + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +namespace mozilla { +namespace gfx { + +// This class exists as a wrapper for ID2D1SimplifiedGeometry sink, it allows +// a geometry to be duplicated into a geometry sink, while removing the final +// figure end and thus allowing a figure that was implicitly closed to be +// continued. +class OpeningGeometrySink : public ID2D1SimplifiedGeometrySink +{ +public: + OpeningGeometrySink(ID2D1SimplifiedGeometrySink *aSink) + : mSink(aSink) + , mNeedsFigureEnded(false) + { + } + + HRESULT STDMETHODCALLTYPE QueryInterface(const IID &aIID, void **aPtr) + { + if (!aPtr) { + return E_POINTER; + } + + if (aIID == IID_IUnknown) { + *aPtr = static_cast(this); + return S_OK; + } else if (aIID == IID_ID2D1SimplifiedGeometrySink) { + *aPtr = static_cast(this); + return S_OK; + } + + return E_NOINTERFACE; + } + + ULONG STDMETHODCALLTYPE AddRef() + { + return 1; + } + + ULONG STDMETHODCALLTYPE Release() + { + return 1; + } + + // We ignore SetFillMode, the copier will decide. + STDMETHOD_(void, SetFillMode)(D2D1_FILL_MODE aMode) + { EnsureFigureEnded(); return; } + STDMETHOD_(void, BeginFigure)(D2D1_POINT_2F aPoint, D2D1_FIGURE_BEGIN aBegin) + { EnsureFigureEnded(); return mSink->BeginFigure(aPoint, aBegin); } + STDMETHOD_(void, AddLines)(const D2D1_POINT_2F *aLines, UINT aCount) + { EnsureFigureEnded(); return mSink->AddLines(aLines, aCount); } + STDMETHOD_(void, AddBeziers)(const D2D1_BEZIER_SEGMENT *aSegments, UINT aCount) + { EnsureFigureEnded(); return mSink->AddBeziers(aSegments, aCount); } + STDMETHOD(Close)() + { /* Should never be called! */ return S_OK; } + STDMETHOD_(void, SetSegmentFlags)(D2D1_PATH_SEGMENT aFlags) + { return mSink->SetSegmentFlags(aFlags); } + + // This function is special - it's the reason this class exists. + // It needs to intercept the very last endfigure. So that a user can + // continue writing to this sink as if they never stopped. + STDMETHOD_(void, EndFigure)(D2D1_FIGURE_END aEnd) + { + if (aEnd == D2D1_FIGURE_END_CLOSED) { + return mSink->EndFigure(aEnd); + } else { + mNeedsFigureEnded = true; + } + } +private: + void EnsureFigureEnded() + { + if (mNeedsFigureEnded) { + mSink->EndFigure(D2D1_FIGURE_END_OPEN); + mNeedsFigureEnded = false; + } + } + + ID2D1SimplifiedGeometrySink *mSink; + bool mNeedsFigureEnded; +}; + +PathBuilderD2D::~PathBuilderD2D() +{ +} + +void +PathBuilderD2D::MoveTo(const Point &aPoint) +{ + if (mFigureActive) { + mSink->EndFigure(D2D1_FIGURE_END_OPEN); + mFigureActive = false; + } + EnsureActive(aPoint); + mCurrentPoint = aPoint; +} + +void +PathBuilderD2D::LineTo(const Point &aPoint) +{ + EnsureActive(aPoint); + mSink->AddLine(D2DPoint(aPoint)); + + mCurrentPoint = aPoint; +} + +void +PathBuilderD2D::BezierTo(const Point &aCP1, + const Point &aCP2, + const Point &aCP3) + { + EnsureActive(aCP1); + mSink->AddBezier(D2D1::BezierSegment(D2DPoint(aCP1), + D2DPoint(aCP2), + D2DPoint(aCP3))); + + mCurrentPoint = aCP3; +} + +void +PathBuilderD2D::QuadraticBezierTo(const Point &aCP1, + const Point &aCP2) +{ + EnsureActive(aCP1); + mSink->AddQuadraticBezier(D2D1::QuadraticBezierSegment(D2DPoint(aCP1), + D2DPoint(aCP2))); + + mCurrentPoint = aCP2; +} + +void +PathBuilderD2D::Close() +{ + if (mFigureActive) { + mSink->EndFigure(D2D1_FIGURE_END_CLOSED); + + mFigureActive = false; + + EnsureActive(mBeginPoint); + } +} + +void +PathBuilderD2D::Arc(const Point &aOrigin, Float aRadius, Float aStartAngle, + Float aEndAngle, bool aAntiClockwise) +{ + if (aAntiClockwise && aStartAngle < aEndAngle) { + // D2D does things a little differently, and draws the arc by specifying an + // beginning and an end point. This means the circle will be the wrong way + // around if the start angle is smaller than the end angle. It might seem + // tempting to invert aAntiClockwise but that would change the sweeping + // direction of the arc to instead we exchange start/begin. + Float oldStart = aStartAngle; + aStartAngle = aEndAngle; + aEndAngle = oldStart; + } + + // XXX - Workaround for now, D2D does not appear to do the desired thing when + // the angle sweeps a complete circle. + if (aEndAngle - aStartAngle >= 2 * M_PI) { + aEndAngle = Float(aStartAngle + M_PI * 1.9999); + } else if (aStartAngle - aEndAngle >= 2 * M_PI) { + aStartAngle = Float(aEndAngle + M_PI * 1.9999); + } + + Point startPoint; + startPoint.x = aOrigin.x + aRadius * cos(aStartAngle); + startPoint.y = aOrigin.y + aRadius * sin(aStartAngle); + + if (!mFigureActive) { + EnsureActive(startPoint); + } else { + mSink->AddLine(D2DPoint(startPoint)); + } + + Point endPoint; + endPoint.x = aOrigin.x + aRadius * cos(aEndAngle); + endPoint.y = aOrigin.y + aRadius * sin(aEndAngle); + + D2D1_ARC_SIZE arcSize = D2D1_ARC_SIZE_SMALL; + + if (aAntiClockwise) { + if (aStartAngle - aEndAngle > M_PI) { + arcSize = D2D1_ARC_SIZE_LARGE; + } + } else { + if (aEndAngle - aStartAngle > M_PI) { + arcSize = D2D1_ARC_SIZE_LARGE; + } + } + + mSink->AddArc(D2D1::ArcSegment(D2DPoint(endPoint), + D2D1::SizeF(aRadius, aRadius), + 0.0f, + aAntiClockwise ? D2D1_SWEEP_DIRECTION_COUNTER_CLOCKWISE : + D2D1_SWEEP_DIRECTION_CLOCKWISE, + arcSize)); + + mCurrentPoint = endPoint; +} + +Point +PathBuilderD2D::CurrentPoint() const +{ + return mCurrentPoint; +} + +void +PathBuilderD2D::EnsureActive(const Point &aPoint) +{ + if (!mFigureActive) { + mSink->BeginFigure(D2DPoint(aPoint), D2D1_FIGURE_BEGIN_FILLED); + mBeginPoint = aPoint; + mFigureActive = true; + } +} + +TemporaryRef +PathBuilderD2D::Finish() +{ + if (mFigureActive) { + mSink->EndFigure(D2D1_FIGURE_END_OPEN); + } + + HRESULT hr = mSink->Close(); + if (FAILED(hr)) { + gfxDebug() << "Failed to close PathSink. Code: " << hr; + return NULL; + } + + return new PathD2D(mGeometry, mFigureActive, mCurrentPoint, mFillRule); +} + +TemporaryRef +PathD2D::CopyToBuilder(FillRule aFillRule) const +{ + return TransformedCopyToBuilder(Matrix(), aFillRule); +} + +TemporaryRef +PathD2D::TransformedCopyToBuilder(const Matrix &aTransform, FillRule aFillRule) const +{ + RefPtr path; + HRESULT hr = DrawTargetD2D::factory()->CreatePathGeometry(byRef(path)); + + if (FAILED(hr)) { + gfxWarning() << "Failed to create PathGeometry. Code: " << hr; + return NULL; + } + + RefPtr sink; + hr = path->Open(byRef(sink)); + if (FAILED(hr)) { + gfxWarning() << "Failed to open Geometry for writing. Code: " << hr; + return NULL; + } + + if (aFillRule == FILL_WINDING) { + sink->SetFillMode(D2D1_FILL_MODE_WINDING); + } + + if (mEndedActive) { + OpeningGeometrySink wrapSink(sink); + mGeometry->Simplify(D2D1_GEOMETRY_SIMPLIFICATION_OPTION_CUBICS_AND_LINES, + D2DMatrix(aTransform), + &wrapSink); + } else { + mGeometry->Simplify(D2D1_GEOMETRY_SIMPLIFICATION_OPTION_CUBICS_AND_LINES, + D2DMatrix(aTransform), + sink); + } + + RefPtr pathBuilder = new PathBuilderD2D(sink, path, mFillRule); + + pathBuilder->mCurrentPoint = aTransform * mEndPoint; + + if (mEndedActive) { + pathBuilder->mFigureActive = true; + } + + return pathBuilder; +} + +bool +PathD2D::ContainsPoint(const Point &aPoint, const Matrix &aTransform) const +{ + BOOL result; + + HRESULT hr = mGeometry->FillContainsPoint(D2DPoint(aPoint), D2DMatrix(aTransform), 0.001f, &result); + + if (FAILED(hr)) { + // Log + return false; + } + + return !!result; +} + +} +} \ No newline at end of file diff --git a/gfx/2d/PathD2D.h b/gfx/2d/PathD2D.h new file mode 100644 index 00000000000..cb3d90d8227 --- /dev/null +++ b/gfx/2d/PathD2D.h @@ -0,0 +1,126 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.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/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Corporation code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Bas Schouten + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef MOZILLA_GFX_PATHD2D_H_ +#define MOZILLA_GFX_PATHD2D_H_ + +#include "2D.h" +#include + +namespace mozilla { +namespace gfx { + +class PathD2D; + +class PathBuilderD2D : public PathBuilder +{ +public: + PathBuilderD2D(ID2D1GeometrySink *aSink, ID2D1PathGeometry *aGeom, FillRule aFillRule) + : mSink(aSink) + , mGeometry(aGeom) + , mFigureActive(false) + , mFillRule(aFillRule) + { + } + virtual ~PathBuilderD2D(); + + virtual void MoveTo(const Point &aPoint); + virtual void LineTo(const Point &aPoint); + virtual void BezierTo(const Point &aCP1, + const Point &aCP2, + const Point &aCP3); + virtual void QuadraticBezierTo(const Point &aCP1, + const Point &aCP2); + virtual void Close(); + virtual void Arc(const Point &aOrigin, Float aRadius, Float aStartAngle, + Float aEndAngle, bool aAntiClockwise = false); + virtual Point CurrentPoint() const; + + virtual TemporaryRef Finish(); + + ID2D1GeometrySink *GetSink() { return mSink; } + +private: + friend class PathD2D; + + void EnsureActive(const Point &aPoint); + + RefPtr mSink; + RefPtr mGeometry; + + bool mFigureActive; + Point mCurrentPoint; + Point mBeginPoint; + FillRule mFillRule; +}; + +class PathD2D : public Path +{ +public: + PathD2D(ID2D1PathGeometry *aGeometry, bool aEndedActive, + const Point &aEndPoint, FillRule aFillRule) + : mGeometry(aGeometry) + , mEndedActive(aEndedActive) + , mEndPoint(aEndPoint) + , mFillRule(aFillRule) + {} + + virtual BackendType GetBackendType() const { return BACKEND_DIRECT2D; } + + virtual TemporaryRef CopyToBuilder(FillRule aFillRule = FILL_WINDING) const; + virtual TemporaryRef TransformedCopyToBuilder(const Matrix &aTransform, + FillRule aFillRule = FILL_WINDING) const; + + virtual bool ContainsPoint(const Point &aPoint, const Matrix &aTransform) const; + + virtual FillRule GetFillRule() const { return mFillRule; } + + ID2D1Geometry *GetGeometry() { return mGeometry; } + +private: + friend class DrawTargetD2D; + + mutable RefPtr mGeometry; + bool mEndedActive; + Point mEndPoint; + FillRule mFillRule; +}; + +} +} + +#endif /* MOZILLA_GFX_PATHD2D_H_ */ diff --git a/gfx/2d/Point.h b/gfx/2d/Point.h new file mode 100644 index 00000000000..2d8913635c0 --- /dev/null +++ b/gfx/2d/Point.h @@ -0,0 +1,81 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.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/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Corporation code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Bas Schouten + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef MOZILLA_GFX_POINT_H_ +#define MOZILLA_GFX_POINT_H_ + +#include "Types.h" +#include "BasePoint.h" +#include "BaseSize.h" + +namespace mozilla { +namespace gfx { + +struct Point : + public BasePoint { + typedef BasePoint Super; + Point() : Super() {} + Point(Float aX, Float aY) : Super(aX, aY) {} +}; + +struct IntPoint : + public BasePoint { + typedef BasePoint Super; + IntPoint() : Super() {} + IntPoint(int32_t aX, int32_t aY) : Super(aX, aY) {} +}; + +struct Size : + public BaseSize { + typedef BaseSize Super; + + Size() : Super() {} + Size(Float aWidth, Float aHeight) : Super(aWidth, aHeight) {} +}; + +struct IntSize : + public BaseSize { + typedef BaseSize Super; + + IntSize() : Super() {} + IntSize(int32_t aWidth, int32_t aHeight) : Super(aWidth, aHeight) {} +}; + +} +} + +#endif /* MOZILLA_GFX_POINT_H_ */ diff --git a/gfx/2d/Rect.h b/gfx/2d/Rect.h new file mode 100644 index 00000000000..3028c08995d --- /dev/null +++ b/gfx/2d/Rect.h @@ -0,0 +1,83 @@ +/* -*- Mode: c++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.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/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Corporation code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (Sub) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Robert O'Callahan + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef MOZILLA_GFX_RECT_H_ +#define MOZILLA_GFX_RECT_H_ + +#include "BaseRect.h" +#include "BaseMargin.h" +#include "Point.h" + +namespace mozilla { +namespace gfx { + +struct Margin : + public BaseMargin { + typedef BaseMargin Super; + + // Constructors + Margin(const Margin& aMargin) : Super(aMargin) {} + Margin(Float aLeft, Float aTop, Float aRight, Float aBottom) + : Super(aLeft, aTop, aRight, aBottom) {} +}; + +struct Rect : + public BaseRect { + typedef BaseRect Super; + + Rect() : Super() {} + Rect(Point aPos, mozilla::gfx::Size aSize) : + Super(aPos, aSize) {} + Rect(Float _x, Float _y, Float _width, Float _height) : + Super(_x, _y, _width, _height) {} +}; + +struct IntRect : + public BaseRect { + typedef BaseRect Super; + + IntRect() : Super() {} + IntRect(IntPoint aPos, mozilla::gfx::IntSize aSize) : + Super(aPos, aSize) {} + IntRect(int32_t _x, int32_t _y, int32_t _width, int32_t _height) : + Super(_x, _y, _width, _height) {} +}; + +} +} + +#endif /* MOZILLA_GFX_RECT_H_ */ diff --git a/gfx/2d/ScaledFontDWrite.cpp b/gfx/2d/ScaledFontDWrite.cpp new file mode 100644 index 00000000000..27fa38cd464 --- /dev/null +++ b/gfx/2d/ScaledFontDWrite.cpp @@ -0,0 +1,81 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.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/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Corporation code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Bas Schouten + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "ScaledFontDWrite.h" +#include "PathD2D.h" + +#include + +namespace mozilla { +namespace gfx { + +TemporaryRef +ScaledFontDWrite::GetPathForGlyphs(const GlyphBuffer &aBuffer, const DrawTarget *aTarget) +{ + if (aTarget->GetType() != BACKEND_DIRECT2D) { + // For now we only support Direct2D. + return NULL; + } + + RefPtr pathBuilder = aTarget->CreatePathBuilder(); + + PathBuilderD2D *pathBuilderD2D = + static_cast(pathBuilder.get()); + + std::vector indices; + std::vector advances; + std::vector offsets; + indices.resize(aBuffer.mNumGlyphs); + advances.resize(aBuffer.mNumGlyphs); + offsets.resize(aBuffer.mNumGlyphs); + + memset(&advances.front(), 0, sizeof(FLOAT) * aBuffer.mNumGlyphs); + for (unsigned int i = 0; i < aBuffer.mNumGlyphs; i++) { + indices[i] = aBuffer.mGlyphs[i].mIndex; + offsets[i].advanceOffset = aBuffer.mGlyphs[i].mPosition.x; + offsets[i].ascenderOffset = -aBuffer.mGlyphs[i].mPosition.y; + } + + mFontFace->GetGlyphRunOutline(mSize, &indices.front(), &advances.front(), + &offsets.front(), aBuffer.mNumGlyphs, + FALSE, FALSE, pathBuilderD2D->GetSink()); + + return pathBuilder->Finish(); +} + +} +} diff --git a/gfx/2d/ScaledFontDWrite.h b/gfx/2d/ScaledFontDWrite.h new file mode 100644 index 00000000000..5e48d5b83ea --- /dev/null +++ b/gfx/2d/ScaledFontDWrite.h @@ -0,0 +1,69 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.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/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Corporation code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Bas Schouten + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef MOZILLA_GFX_SCALEDFONTDWRITE_H_ +#define MOZILLA_GFX_SCALEDFONTDWRITE_H_ + +#include "2D.h" +#include + +namespace mozilla { +namespace gfx { + +class ScaledFontDWrite : public ScaledFont +{ +public: + ScaledFontDWrite(IDWriteFontFace *aFont, Float aSize) + : mFontFace(aFont) + , mSize(aSize) + {} + + virtual FontType GetType() const { return FONT_DWRITE; } + + virtual TemporaryRef GetPathForGlyphs(const GlyphBuffer &aBuffer, const DrawTarget *aTarget); + +private: + friend class DrawTargetD2D; + + RefPtr mFontFace; + Float mSize; +}; + +} +} + +#endif /* MOZILLA_GFX_SCALEDFONTDWRITE_H_ */ diff --git a/gfx/2d/ShadersD2D.fx b/gfx/2d/ShadersD2D.fx new file mode 100644 index 00000000000..736d33fac07 --- /dev/null +++ b/gfx/2d/ShadersD2D.fx @@ -0,0 +1,156 @@ +// We store vertex coordinates and the quad shape in a constant buffer, this is +// easy to update and allows us to use a single call to set the x, y, w, h of +// the quad. +// The QuadDesc and TexCoords both work as follows: +// The x component is the quad left point, the y component is the top point +// the z component is the width, and the w component is the height. The quad +// are specified in viewport coordinates, i.e. { -1.0f, 1.0f, 2.0f, -2.0f } +// would cover the entire viewport (which runs from <-1.0f, 1.0f> left to right +// and <-1.0f, 1.0f> -bottom- to top. The TexCoords desc is specified in texture +// space <0, 1.0f> left to right and top to bottom. The input vertices of the +// shader stage always form a rectangle from {0, 0} - {1, 1} +cbuffer cb0 +{ + float4 QuadDesc; + float4 TexCoords; +} + +cbuffer cb1 +{ + float4 BlurOffsetsH[3]; + float4 BlurOffsetsV[3]; + float4 BlurWeights[3]; + float4 ShadowColor; +} + +struct VS_OUTPUT +{ + float4 Position : SV_Position; + float2 TexCoord : TEXCOORD0; +}; + +Texture2D tex; + +sampler sSampler = sampler_state { + Filter = MIN_MAG_MIP_LINEAR; + Texture = tex; + AddressU = Clamp; + AddressV = Clamp; +}; + +sampler sShadowSampler = sampler_state { + Filter = MIN_MAG_MIP_LINEAR; + Texture = tex; + AddressU = Border; + AddressV = Border; + BorderColor = float4(0, 0, 0, 0); +}; + +RasterizerState TextureRast +{ + ScissorEnable = False; + CullMode = None; +}; + +BlendState ShadowBlendH +{ + BlendEnable[0] = False; + RenderTargetWriteMask[0] = 0xF; +}; + +BlendState ShadowBlendV +{ + BlendEnable[0] = True; + SrcBlend = One; + DestBlend = Inv_Src_Alpha; + BlendOp = Add; + SrcBlendAlpha = One; + DestBlendAlpha = Inv_Src_Alpha; + BlendOpAlpha = Add; + RenderTargetWriteMask[0] = 0xF; +}; + +VS_OUTPUT SampleTextureVS(float3 pos : POSITION) +{ + VS_OUTPUT Output; + Output.Position.w = 1.0f; + Output.Position.x = pos.x * QuadDesc.z + QuadDesc.x; + Output.Position.y = pos.y * QuadDesc.w + QuadDesc.y; + Output.Position.z = 0; + Output.TexCoord.x = pos.x * TexCoords.z + TexCoords.x; + Output.TexCoord.y = pos.y * TexCoords.w + TexCoords.y; + return Output; +} + +float4 SampleTexturePS( VS_OUTPUT In) : SV_Target +{ + return tex.Sample(sSampler, In.TexCoord); +}; + +float4 SampleShadowHPS( VS_OUTPUT In) : SV_Target +{ + float outputStrength = 0; + + outputStrength += BlurWeights[0].x * tex.Sample(sShadowSampler, float2(In.TexCoord.x + BlurOffsetsH[0].x, In.TexCoord.y)).a; + outputStrength += BlurWeights[0].y * tex.Sample(sShadowSampler, float2(In.TexCoord.x + BlurOffsetsH[0].y, In.TexCoord.y)).a; + outputStrength += BlurWeights[0].z * tex.Sample(sShadowSampler, float2(In.TexCoord.x + BlurOffsetsH[0].z, In.TexCoord.y)).a; + outputStrength += BlurWeights[0].w * tex.Sample(sShadowSampler, float2(In.TexCoord.x + BlurOffsetsH[0].w, In.TexCoord.y)).a; + outputStrength += BlurWeights[1].x * tex.Sample(sShadowSampler, float2(In.TexCoord.x + BlurOffsetsH[1].x, In.TexCoord.y)).a; + outputStrength += BlurWeights[1].y * tex.Sample(sShadowSampler, float2(In.TexCoord.x + BlurOffsetsH[1].y, In.TexCoord.y)).a; + outputStrength += BlurWeights[1].z * tex.Sample(sShadowSampler, float2(In.TexCoord.x + BlurOffsetsH[1].z, In.TexCoord.y)).a; + outputStrength += BlurWeights[1].w * tex.Sample(sShadowSampler, float2(In.TexCoord.x + BlurOffsetsH[1].w, In.TexCoord.y)).a; + outputStrength += BlurWeights[2].x * tex.Sample(sShadowSampler, float2(In.TexCoord.x + BlurOffsetsH[2].x, In.TexCoord.y)).a; + + return ShadowColor * outputStrength; +}; + +float4 SampleShadowVPS( VS_OUTPUT In) : SV_Target +{ + float4 outputColor = float4(0, 0, 0, 0); + + outputColor += BlurWeights[0].x * tex.Sample(sShadowSampler, float2(In.TexCoord.x, In.TexCoord.y + BlurOffsetsV[0].x)); + outputColor += BlurWeights[0].y * tex.Sample(sShadowSampler, float2(In.TexCoord.x, In.TexCoord.y + BlurOffsetsV[0].y)); + outputColor += BlurWeights[0].z * tex.Sample(sShadowSampler, float2(In.TexCoord.x, In.TexCoord.y + BlurOffsetsV[0].z)); + outputColor += BlurWeights[0].w * tex.Sample(sShadowSampler, float2(In.TexCoord.x, In.TexCoord.y + BlurOffsetsV[0].w)); + outputColor += BlurWeights[1].x * tex.Sample(sShadowSampler, float2(In.TexCoord.x, In.TexCoord.y + BlurOffsetsV[1].x)); + outputColor += BlurWeights[1].y * tex.Sample(sShadowSampler, float2(In.TexCoord.x, In.TexCoord.y + BlurOffsetsV[1].y)); + outputColor += BlurWeights[1].z * tex.Sample(sShadowSampler, float2(In.TexCoord.x, In.TexCoord.y + BlurOffsetsV[1].z)); + outputColor += BlurWeights[1].w * tex.Sample(sShadowSampler, float2(In.TexCoord.x, In.TexCoord.y + BlurOffsetsV[1].w)); + outputColor += BlurWeights[2].x * tex.Sample(sShadowSampler, float2(In.TexCoord.x, In.TexCoord.y + BlurOffsetsV[2].x)); + + return outputColor; +}; + +technique10 SampleTexture +{ + pass P0 + { + SetRasterizerState(TextureRast); + SetVertexShader(CompileShader(vs_4_0_level_9_3, SampleTextureVS())); + SetGeometryShader(NULL); + SetPixelShader(CompileShader(ps_4_0_level_9_3, SampleTexturePS())); + } +} + + +technique10 SampleTextureWithShadow +{ + // Horizontal pass + pass P0 + { + SetRasterizerState(TextureRast); + SetBlendState(ShadowBlendH, float4(1.0f, 1.0f, 1.0f, 1.0f), 0xffffffff); + SetVertexShader(CompileShader(vs_4_0_level_9_3, SampleTextureVS())); + SetGeometryShader(NULL); + SetPixelShader(CompileShader(ps_4_0_level_9_3, SampleShadowHPS())); + } + // Vertical pass + pass P1 + { + SetRasterizerState(TextureRast); + SetBlendState(ShadowBlendV, float4(1.0f, 1.0f, 1.0f, 1.0f), 0xffffffff); + SetVertexShader(CompileShader(vs_4_0_level_9_3, SampleTextureVS())); + SetGeometryShader(NULL); + SetPixelShader(CompileShader(ps_4_0_level_9_3, SampleShadowVPS())); + } +} \ No newline at end of file diff --git a/gfx/2d/ShadersD2D.h b/gfx/2d/ShadersD2D.h new file mode 100644 index 00000000000..47fb5787d22 --- /dev/null +++ b/gfx/2d/ShadersD2D.h @@ -0,0 +1,2411 @@ +#if 0 +// +// FX Version: fx_4_0 +// Child effect (requires effect pool): false +// +// 2 local buffer(s) +// +cbuffer cb0 +{ + float4 QuadDesc; // Offset: 0, size: 16 + float4 TexCoords; // Offset: 16, size: 16 +} + +cbuffer cb1 +{ + float4 BlurOffsetsH[3]; // Offset: 0, size: 48 + float4 BlurOffsetsV[3]; // Offset: 48, size: 48 + float4 BlurWeights[3]; // Offset: 96, size: 48 + float4 ShadowColor; // Offset: 144, size: 16 +} + +// +// 6 local object(s) +// +Texture2D tex; +SamplerState sSampler +{ + Filter = uint(MIN_MAG_MIP_LINEAR /* 21 */); + Texture = tex; + AddressU = uint(CLAMP /* 3 */); + AddressV = uint(CLAMP /* 3 */); +}; +SamplerState sShadowSampler +{ + Filter = uint(MIN_MAG_MIP_LINEAR /* 21 */); + Texture = tex; + AddressU = uint(BORDER /* 4 */); + AddressV = uint(BORDER /* 4 */); + BorderColor = float4(0, 0, 0, 0); +}; +RasterizerState TextureRast +{ + ScissorEnable = bool(FALSE /* 0 */); + CullMode = uint(NONE /* 1 */); +}; +BlendState ShadowBlendH +{ + BlendEnable[0] = bool(FALSE /* 0 */); + RenderTargetWriteMask[0] = byte(0x0f); +}; +BlendState ShadowBlendV +{ + BlendEnable[0] = bool(TRUE /* 1 */); + SrcBlend[0] = uint(ONE /* 2 */); + DestBlend[0] = uint(INV_SRC_ALPHA /* 6 */); + BlendOp[0] = uint(ADD /* 1 */); + SrcBlendAlpha[0] = uint(ONE /* 2 */); + DestBlendAlpha[0] = uint(INV_SRC_ALPHA /* 6 */); + BlendOpAlpha[0] = uint(ADD /* 1 */); + RenderTargetWriteMask[0] = byte(0x0f); +}; + +// +// 2 technique(s) +// +technique10 SampleTexture +{ + pass P0 + { + RasterizerState = TextureRast; + VertexShader = asm { + // + // Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 + // + // + // Buffer Definitions: + // + // cbuffer cb0 + // { + // + // float4 QuadDesc; // Offset: 0 Size: 16 + // float4 TexCoords; // Offset: 16 Size: 16 + // + // } + // + // + // Resource Bindings: + // + // Name Type Format Dim Slot Elements + // ------------------------------ ---------- ------- ----------- ---- -------- + // cb0 cbuffer NA NA 0 1 + // + // + // + // Input signature: + // + // Name Index Mask Register SysValue Format Used + // -------------------- ----- ------ -------- -------- ------ ------ + // POSITION 0 xyz 0 NONE float xy + // + // + // Output signature: + // + // Name Index Mask Register SysValue Format Used + // -------------------- ----- ------ -------- -------- ------ ------ + // SV_Position 0 xyzw 0 POS float xyzw + // TEXCOORD 0 xy 1 NONE float xy + // + // + // Constant buffer to DX9 shader constant mappings: + // + // Target Reg Buffer Start Reg # of Regs Data Conversion + // ---------- ------- --------- --------- ---------------------- + // c1 cb0 0 2 ( FLT, FLT, FLT, FLT) + // + // + // Runtime generated constant mappings: + // + // Target Reg Constant Description + // ---------- -------------------------------------------------- + // c0 Vertex Shader position offset + // + // + // Level9 shader bytecode: + // + vs_2_x + def c3, 0, 1, 0, 0 + dcl_texcoord v0 + mad oT0.xy, v0, c2.zwzw, c2 + mad r0.xy, v0, c1.zwzw, c1 + add oPos.xy, r0, c0 + mov oPos.zw, c3.xyxy + + // approximately 4 instruction slots used + vs_4_0 + dcl_constantbuffer cb0[2], immediateIndexed + dcl_input v0.xy + dcl_output_siv o0.xyzw, position + dcl_output o1.xy + mad o0.xy, v0.xyxx, cb0[0].zwzz, cb0[0].xyxx + mov o0.zw, l(0,0,0,1.000000) + mad o1.xy, v0.xyxx, cb0[1].zwzz, cb0[1].xyxx + ret + // Approximately 4 instruction slots used + + }; + GeometryShader = NULL; + PixelShader = asm { + // + // Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 + // + // + // Resource Bindings: + // + // Name Type Format Dim Slot Elements + // ------------------------------ ---------- ------- ----------- ---- -------- + // sSampler sampler NA NA 0 1 + // tex texture float4 2d 0 1 + // + // + // + // Input signature: + // + // Name Index Mask Register SysValue Format Used + // -------------------- ----- ------ -------- -------- ------ ------ + // SV_Position 0 xyzw 0 POS float + // TEXCOORD 0 xy 1 NONE float xy + // + // + // Output signature: + // + // Name Index Mask Register SysValue Format Used + // -------------------- ----- ------ -------- -------- ------ ------ + // SV_Target 0 xyzw 0 TARGET float xyzw + // + // + // Sampler/Resource to DX9 shader sampler mappings: + // + // Target Sampler Source Sampler Source Resource + // -------------- --------------- ---------------- + // s0 s0 t0 + // + // + // Level9 shader bytecode: + // + ps_2_x + dcl t0.xy + dcl_2d s0 + texld r0, t0, s0 + mov oC0, r0 + + // approximately 2 instruction slots used (1 texture, 1 arithmetic) + ps_4_0 + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + sample o0.xyzw, v1.xyxx, t0.xyzw, s0 + ret + // Approximately 2 instruction slots used + + }; + } + +} + +technique10 SampleTextureWithShadow +{ + pass P0 + { + RasterizerState = TextureRast; + AB_BlendFactor = float4(1, 1, 1, 1); + AB_SampleMask = uint(0xffffffff); + BlendState = ShadowBlendH; + VertexShader = asm { + // + // Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 + // + // + // Buffer Definitions: + // + // cbuffer cb0 + // { + // + // float4 QuadDesc; // Offset: 0 Size: 16 + // float4 TexCoords; // Offset: 16 Size: 16 + // + // } + // + // + // Resource Bindings: + // + // Name Type Format Dim Slot Elements + // ------------------------------ ---------- ------- ----------- ---- -------- + // cb0 cbuffer NA NA 0 1 + // + // + // + // Input signature: + // + // Name Index Mask Register SysValue Format Used + // -------------------- ----- ------ -------- -------- ------ ------ + // POSITION 0 xyz 0 NONE float xy + // + // + // Output signature: + // + // Name Index Mask Register SysValue Format Used + // -------------------- ----- ------ -------- -------- ------ ------ + // SV_Position 0 xyzw 0 POS float xyzw + // TEXCOORD 0 xy 1 NONE float xy + // + // + // Constant buffer to DX9 shader constant mappings: + // + // Target Reg Buffer Start Reg # of Regs Data Conversion + // ---------- ------- --------- --------- ---------------------- + // c1 cb0 0 2 ( FLT, FLT, FLT, FLT) + // + // + // Runtime generated constant mappings: + // + // Target Reg Constant Description + // ---------- -------------------------------------------------- + // c0 Vertex Shader position offset + // + // + // Level9 shader bytecode: + // + vs_2_x + def c3, 0, 1, 0, 0 + dcl_texcoord v0 + mad oT0.xy, v0, c2.zwzw, c2 + mad r0.xy, v0, c1.zwzw, c1 + add oPos.xy, r0, c0 + mov oPos.zw, c3.xyxy + + // approximately 4 instruction slots used + vs_4_0 + dcl_constantbuffer cb0[2], immediateIndexed + dcl_input v0.xy + dcl_output_siv o0.xyzw, position + dcl_output o1.xy + mad o0.xy, v0.xyxx, cb0[0].zwzz, cb0[0].xyxx + mov o0.zw, l(0,0,0,1.000000) + mad o1.xy, v0.xyxx, cb0[1].zwzz, cb0[1].xyxx + ret + // Approximately 4 instruction slots used + + }; + GeometryShader = NULL; + PixelShader = asm { + // + // Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 + // + // + // Buffer Definitions: + // + // cbuffer cb1 + // { + // + // float4 BlurOffsetsH[3]; // Offset: 0 Size: 48 + // float4 BlurOffsetsV[3]; // Offset: 48 Size: 48 [unused] + // float4 BlurWeights[3]; // Offset: 96 Size: 48 + // float4 ShadowColor; // Offset: 144 Size: 16 + // + // } + // + // + // Resource Bindings: + // + // Name Type Format Dim Slot Elements + // ------------------------------ ---------- ------- ----------- ---- -------- + // sShadowSampler sampler NA NA 0 1 + // tex texture float4 2d 0 1 + // cb1 cbuffer NA NA 0 1 + // + // + // + // Input signature: + // + // Name Index Mask Register SysValue Format Used + // -------------------- ----- ------ -------- -------- ------ ------ + // SV_Position 0 xyzw 0 POS float + // TEXCOORD 0 xy 1 NONE float xy + // + // + // Output signature: + // + // Name Index Mask Register SysValue Format Used + // -------------------- ----- ------ -------- -------- ------ ------ + // SV_Target 0 xyzw 0 TARGET float xyzw + // + // + // Constant buffer to DX9 shader constant mappings: + // + // Target Reg Buffer Start Reg # of Regs Data Conversion + // ---------- ------- --------- --------- ---------------------- + // c0 cb0 0 3 ( FLT, FLT, FLT, FLT) + // c3 cb0 6 4 ( FLT, FLT, FLT, FLT) + // + // + // Sampler/Resource to DX9 shader sampler mappings: + // + // Target Sampler Source Sampler Source Resource + // -------------- --------------- ---------------- + // s0 s0 t0 + // + // + // Level9 shader bytecode: + // + ps_2_x + dcl t0.xy + dcl_2d s0 + add r0.x, t0.x, c0.y + mov r0.y, t0.y + add r1.x, t0.x, c0.x + mov r1.y, t0.y + texld r0, r0, s0 + texld r1, r1, s0 + mul r0.x, r0.w, c3.y + mad r0.x, c3.x, r1.w, r0.x + add r1.x, t0.x, c0.z + mov r1.y, t0.y + add r2.x, t0.x, c0.w + mov r2.y, t0.y + texld r1, r1, s0 + texld r2, r2, s0 + mad r0.x, c3.z, r1.w, r0.x + mad r0.x, c3.w, r2.w, r0.x + add r1.x, t0.x, c1.x + mov r1.y, t0.y + add r2.x, t0.x, c1.y + mov r2.y, t0.y + texld r1, r1, s0 + texld r2, r2, s0 + mad r0.x, c4.x, r1.w, r0.x + mad r0.x, c4.y, r2.w, r0.x + add r1.x, t0.x, c1.z + mov r1.y, t0.y + add r2.x, t0.x, c1.w + mov r2.y, t0.y + texld r1, r1, s0 + texld r2, r2, s0 + mad r0.x, c4.z, r1.w, r0.x + mad r0.x, c4.w, r2.w, r0.x + add r1.x, t0.x, c2.x + mov r1.y, t0.y + texld r1, r1, s0 + mad r0.x, c5.x, r1.w, r0.x + mul r0, r0.x, c6 + mov oC0, r0 + + // approximately 38 instruction slots used (9 texture, 29 arithmetic) + ps_4_0 + dcl_constantbuffer cb0[10], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + add r0.xyzw, v1.xxxx, cb0[0].zxwy + mov r1.xz, r0.yywy + mov r1.yw, v1.yyyy + sample r2.xyzw, r1.zwzz, t0.xyzw, s0 + sample r1.xyzw, r1.xyxx, t0.xyzw, s0 + mul r1.x, r2.w, cb0[6].y + mad r1.x, cb0[6].x, r1.w, r1.x + mov r0.yw, v1.yyyy + sample r2.xyzw, r0.xyxx, t0.xyzw, s0 + sample r0.xyzw, r0.zwzz, t0.xyzw, s0 + mad r0.x, cb0[6].z, r2.w, r1.x + mad r0.x, cb0[6].w, r0.w, r0.x + add r1.xyzw, v1.xxxx, cb0[1].zxwy + mov r2.xz, r1.yywy + mov r2.yw, v1.yyyy + sample r3.xyzw, r2.xyxx, t0.xyzw, s0 + sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + mad r0.x, cb0[7].x, r3.w, r0.x + mad r0.x, cb0[7].y, r2.w, r0.x + mov r1.yw, v1.yyyy + sample r2.xyzw, r1.xyxx, t0.xyzw, s0 + sample r1.xyzw, r1.zwzz, t0.xyzw, s0 + mad r0.x, cb0[7].z, r2.w, r0.x + mad r0.x, cb0[7].w, r1.w, r0.x + add r1.x, v1.x, cb0[2].x + mov r1.y, v1.y + sample r1.xyzw, r1.xyxx, t0.xyzw, s0 + mad r0.x, cb0[8].x, r1.w, r0.x + mul o0.xyzw, r0.xxxx, cb0[9].xyzw + ret + // Approximately 30 instruction slots used + + }; + } + + pass P1 + { + RasterizerState = TextureRast; + AB_BlendFactor = float4(1, 1, 1, 1); + AB_SampleMask = uint(0xffffffff); + BlendState = ShadowBlendV; + VertexShader = asm { + // + // Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 + // + // + // Buffer Definitions: + // + // cbuffer cb0 + // { + // + // float4 QuadDesc; // Offset: 0 Size: 16 + // float4 TexCoords; // Offset: 16 Size: 16 + // + // } + // + // + // Resource Bindings: + // + // Name Type Format Dim Slot Elements + // ------------------------------ ---------- ------- ----------- ---- -------- + // cb0 cbuffer NA NA 0 1 + // + // + // + // Input signature: + // + // Name Index Mask Register SysValue Format Used + // -------------------- ----- ------ -------- -------- ------ ------ + // POSITION 0 xyz 0 NONE float xy + // + // + // Output signature: + // + // Name Index Mask Register SysValue Format Used + // -------------------- ----- ------ -------- -------- ------ ------ + // SV_Position 0 xyzw 0 POS float xyzw + // TEXCOORD 0 xy 1 NONE float xy + // + // + // Constant buffer to DX9 shader constant mappings: + // + // Target Reg Buffer Start Reg # of Regs Data Conversion + // ---------- ------- --------- --------- ---------------------- + // c1 cb0 0 2 ( FLT, FLT, FLT, FLT) + // + // + // Runtime generated constant mappings: + // + // Target Reg Constant Description + // ---------- -------------------------------------------------- + // c0 Vertex Shader position offset + // + // + // Level9 shader bytecode: + // + vs_2_x + def c3, 0, 1, 0, 0 + dcl_texcoord v0 + mad oT0.xy, v0, c2.zwzw, c2 + mad r0.xy, v0, c1.zwzw, c1 + add oPos.xy, r0, c0 + mov oPos.zw, c3.xyxy + + // approximately 4 instruction slots used + vs_4_0 + dcl_constantbuffer cb0[2], immediateIndexed + dcl_input v0.xy + dcl_output_siv o0.xyzw, position + dcl_output o1.xy + mad o0.xy, v0.xyxx, cb0[0].zwzz, cb0[0].xyxx + mov o0.zw, l(0,0,0,1.000000) + mad o1.xy, v0.xyxx, cb0[1].zwzz, cb0[1].xyxx + ret + // Approximately 4 instruction slots used + + }; + GeometryShader = NULL; + PixelShader = asm { + // + // Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 + // + // + // Buffer Definitions: + // + // cbuffer cb1 + // { + // + // float4 BlurOffsetsH[3]; // Offset: 0 Size: 48 [unused] + // float4 BlurOffsetsV[3]; // Offset: 48 Size: 48 + // float4 BlurWeights[3]; // Offset: 96 Size: 48 + // float4 ShadowColor; // Offset: 144 Size: 16 [unused] + // + // } + // + // + // Resource Bindings: + // + // Name Type Format Dim Slot Elements + // ------------------------------ ---------- ------- ----------- ---- -------- + // sShadowSampler sampler NA NA 0 1 + // tex texture float4 2d 0 1 + // cb1 cbuffer NA NA 0 1 + // + // + // + // Input signature: + // + // Name Index Mask Register SysValue Format Used + // -------------------- ----- ------ -------- -------- ------ ------ + // SV_Position 0 xyzw 0 POS float + // TEXCOORD 0 xy 1 NONE float xy + // + // + // Output signature: + // + // Name Index Mask Register SysValue Format Used + // -------------------- ----- ------ -------- -------- ------ ------ + // SV_Target 0 xyzw 0 TARGET float xyzw + // + // + // Constant buffer to DX9 shader constant mappings: + // + // Target Reg Buffer Start Reg # of Regs Data Conversion + // ---------- ------- --------- --------- ---------------------- + // c0 cb0 3 6 ( FLT, FLT, FLT, FLT) + // + // + // Sampler/Resource to DX9 shader sampler mappings: + // + // Target Sampler Source Sampler Source Resource + // -------------- --------------- ---------------- + // s0 s0 t0 + // + // + // Level9 shader bytecode: + // + ps_2_x + dcl t0.xy + dcl_2d s0 + add r0.y, t0.y, c0.y + mov r0.x, t0.x + add r1.y, t0.y, c0.x + mov r1.x, t0.x + texld r0, r0, s0 + texld r1, r1, s0 + mul r0, r0, c3.y + mad r0, c3.x, r1, r0 + add r1.y, t0.y, c0.z + mov r1.x, t0.x + add r2.y, t0.y, c0.w + mov r2.x, t0.x + texld r1, r1, s0 + texld r2, r2, s0 + mad r0, c3.z, r1, r0 + mad r0, c3.w, r2, r0 + add r1.y, t0.y, c1.x + mov r1.x, t0.x + add r2.y, t0.y, c1.y + mov r2.x, t0.x + texld r1, r1, s0 + texld r2, r2, s0 + mad r0, c4.x, r1, r0 + mad r0, c4.y, r2, r0 + add r1.y, t0.y, c1.z + mov r1.x, t0.x + add r2.y, t0.y, c1.w + mov r2.x, t0.x + texld r1, r1, s0 + texld r2, r2, s0 + mad r0, c4.z, r1, r0 + mad r0, c4.w, r2, r0 + add r1.y, t0.y, c2.x + mov r1.x, t0.x + texld r1, r1, s0 + mad r0, c5.x, r1, r0 + mov oC0, r0 + + // approximately 37 instruction slots used (9 texture, 28 arithmetic) + ps_4_0 + dcl_constantbuffer cb0[9], immediateIndexed + dcl_sampler s0, mode_default + dcl_resource_texture2d (float,float,float,float) t0 + dcl_input_ps linear v1.xy + dcl_output o0.xyzw + dcl_temps 4 + mov r0.xz, v1.xxxx + add r1.xyzw, v1.yyyy, cb0[3].xzyw + mov r0.yw, r1.xxxz + sample r2.xyzw, r0.zwzz, t0.xyzw, s0 + sample r0.xyzw, r0.xyxx, t0.xyzw, s0 + mul r2.xyzw, r2.xyzw, cb0[6].yyyy + mad r0.xyzw, cb0[6].xxxx, r0.xyzw, r2.xyzw + mov r1.xz, v1.xxxx + sample r2.xyzw, r1.xyxx, t0.xyzw, s0 + sample r1.xyzw, r1.zwzz, t0.xyzw, s0 + mad r0.xyzw, cb0[6].zzzz, r2.xyzw, r0.xyzw + mad r0.xyzw, cb0[6].wwww, r1.xyzw, r0.xyzw + mov r1.xz, v1.xxxx + add r2.xyzw, v1.yyyy, cb0[4].xzyw + mov r1.yw, r2.xxxz + sample r3.xyzw, r1.xyxx, t0.xyzw, s0 + sample r1.xyzw, r1.zwzz, t0.xyzw, s0 + mad r0.xyzw, cb0[7].xxxx, r3.xyzw, r0.xyzw + mad r0.xyzw, cb0[7].yyyy, r1.xyzw, r0.xyzw + mov r2.xz, v1.xxxx + sample r1.xyzw, r2.xyxx, t0.xyzw, s0 + sample r2.xyzw, r2.zwzz, t0.xyzw, s0 + mad r0.xyzw, cb0[7].zzzz, r1.xyzw, r0.xyzw + mad r0.xyzw, cb0[7].wwww, r2.xyzw, r0.xyzw + add r1.y, v1.y, cb0[5].x + mov r1.x, v1.x + sample r1.xyzw, r1.xyxx, t0.xyzw, s0 + mad o0.xyzw, cb0[8].xxxx, r1.xyzw, r0.xyzw + ret + // Approximately 29 instruction slots used + + }; + } + +} + +#endif + +const BYTE d2deffect[] = +{ + 68, 88, 66, 67, 245, 80, + 253, 174, 31, 0, 29, 195, + 254, 34, 10, 37, 101, 204, + 99, 74, 1, 0, 0, 0, + 216, 40, 0, 0, 1, 0, + 0, 0, 36, 0, 0, 0, + 70, 88, 49, 48, 172, 40, + 0, 0, 1, 16, 255, 254, + 2, 0, 0, 0, 6, 0, + 0, 0, 6, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 2, 0, 0, 0, 80, 36, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 0, 0, 2, 0, 0, 0, + 1, 0, 0, 0, 2, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 6, 0, + 0, 0, 6, 0, 0, 0, + 0, 0, 0, 0, 99, 98, + 48, 0, 102, 108, 111, 97, + 116, 52, 0, 8, 0, 0, + 0, 1, 0, 0, 0, 0, + 0, 0, 0, 16, 0, 0, + 0, 16, 0, 0, 0, 16, + 0, 0, 0, 10, 33, 0, + 0, 81, 117, 97, 100, 68, + 101, 115, 99, 0, 84, 101, + 120, 67, 111, 111, 114, 100, + 115, 0, 99, 98, 49, 0, + 8, 0, 0, 0, 1, 0, + 0, 0, 3, 0, 0, 0, + 48, 0, 0, 0, 16, 0, + 0, 0, 48, 0, 0, 0, + 10, 33, 0, 0, 66, 108, + 117, 114, 79, 102, 102, 115, + 101, 116, 115, 72, 0, 66, + 108, 117, 114, 79, 102, 102, + 115, 101, 116, 115, 86, 0, + 66, 108, 117, 114, 87, 101, + 105, 103, 104, 116, 115, 0, + 83, 104, 97, 100, 111, 119, + 67, 111, 108, 111, 114, 0, + 84, 101, 120, 116, 117, 114, + 101, 50, 68, 0, 144, 0, + 0, 0, 2, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 12, 0, + 0, 0, 116, 101, 120, 0, + 83, 97, 109, 112, 108, 101, + 114, 83, 116, 97, 116, 101, + 0, 186, 0, 0, 0, 2, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 21, 0, 0, 0, 115, + 83, 97, 109, 112, 108, 101, + 114, 0, 1, 0, 0, 0, + 2, 0, 0, 0, 21, 0, + 0, 0, 1, 0, 0, 0, + 2, 0, 0, 0, 3, 0, + 0, 0, 1, 0, 0, 0, + 2, 0, 0, 0, 3, 0, + 0, 0, 115, 83, 104, 97, + 100, 111, 119, 83, 97, 109, + 112, 108, 101, 114, 0, 1, + 0, 0, 0, 2, 0, 0, + 0, 21, 0, 0, 0, 1, + 0, 0, 0, 2, 0, 0, + 0, 4, 0, 0, 0, 1, + 0, 0, 0, 2, 0, 0, + 0, 4, 0, 0, 0, 4, + 0, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 1, + 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 82, + 97, 115, 116, 101, 114, 105, + 122, 101, 114, 83, 116, 97, + 116, 101, 0, 103, 1, 0, + 0, 2, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 4, 0, 0, + 0, 84, 101, 120, 116, 117, + 114, 101, 82, 97, 115, 116, + 0, 1, 0, 0, 0, 2, + 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 2, + 0, 0, 0, 1, 0, 0, + 0, 66, 108, 101, 110, 100, + 83, 116, 97, 116, 101, 0, + 183, 1, 0, 0, 2, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 2, 0, 0, 0, 83, 104, + 97, 100, 111, 119, 66, 108, + 101, 110, 100, 72, 0, 1, + 0, 0, 0, 2, 0, 0, + 0, 0, 0, 0, 0, 1, + 0, 0, 0, 3, 0, 0, + 0, 15, 0, 0, 0, 83, + 104, 97, 100, 111, 119, 66, + 108, 101, 110, 100, 86, 0, + 1, 0, 0, 0, 2, 0, + 0, 0, 1, 0, 0, 0, + 1, 0, 0, 0, 2, 0, + 0, 0, 2, 0, 0, 0, + 1, 0, 0, 0, 2, 0, + 0, 0, 6, 0, 0, 0, + 1, 0, 0, 0, 2, 0, + 0, 0, 1, 0, 0, 0, + 1, 0, 0, 0, 2, 0, + 0, 0, 2, 0, 0, 0, + 1, 0, 0, 0, 2, 0, + 0, 0, 6, 0, 0, 0, + 1, 0, 0, 0, 2, 0, + 0, 0, 1, 0, 0, 0, + 1, 0, 0, 0, 3, 0, + 0, 0, 15, 0, 0, 0, + 83, 97, 109, 112, 108, 101, + 84, 101, 120, 116, 117, 114, + 101, 0, 80, 48, 0, 152, + 3, 0, 0, 68, 88, 66, + 67, 219, 222, 190, 170, 104, + 118, 127, 154, 100, 214, 1, + 86, 70, 204, 61, 202, 1, + 0, 0, 0, 152, 3, 0, + 0, 6, 0, 0, 0, 56, + 0, 0, 0, 228, 0, 0, + 0, 168, 1, 0, 0, 36, + 2, 0, 0, 12, 3, 0, + 0, 64, 3, 0, 0, 65, + 111, 110, 57, 164, 0, 0, + 0, 164, 0, 0, 0, 0, + 2, 254, 255, 112, 0, 0, + 0, 52, 0, 0, 0, 1, + 0, 36, 0, 0, 0, 48, + 0, 0, 0, 48, 0, 0, + 0, 36, 0, 1, 0, 48, + 0, 0, 0, 0, 0, 2, + 0, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, + 2, 254, 255, 81, 0, 0, + 5, 3, 0, 15, 160, 0, + 0, 0, 0, 0, 0, 128, + 63, 0, 0, 0, 0, 0, + 0, 0, 0, 31, 0, 0, + 2, 5, 0, 0, 128, 0, + 0, 15, 144, 4, 0, 0, + 4, 0, 0, 3, 224, 0, + 0, 228, 144, 2, 0, 238, + 160, 2, 0, 228, 160, 4, + 0, 0, 4, 0, 0, 3, + 128, 0, 0, 228, 144, 1, + 0, 238, 160, 1, 0, 228, + 160, 2, 0, 0, 3, 0, + 0, 3, 192, 0, 0, 228, + 128, 0, 0, 228, 160, 1, + 0, 0, 2, 0, 0, 12, + 192, 3, 0, 68, 160, 255, + 255, 0, 0, 83, 72, 68, + 82, 188, 0, 0, 0, 64, + 0, 1, 0, 47, 0, 0, + 0, 89, 0, 0, 4, 70, + 142, 32, 0, 0, 0, 0, + 0, 2, 0, 0, 0, 95, + 0, 0, 3, 50, 16, 16, + 0, 0, 0, 0, 0, 103, + 0, 0, 4, 242, 32, 16, + 0, 0, 0, 0, 0, 1, + 0, 0, 0, 101, 0, 0, + 3, 50, 32, 16, 0, 1, + 0, 0, 0, 50, 0, 0, + 11, 50, 32, 16, 0, 0, + 0, 0, 0, 70, 16, 16, + 0, 0, 0, 0, 0, 230, + 138, 32, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 70, + 128, 32, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 54, + 0, 0, 8, 194, 32, 16, + 0, 0, 0, 0, 0, 2, + 64, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 128, + 63, 50, 0, 0, 11, 50, + 32, 16, 0, 1, 0, 0, + 0, 70, 16, 16, 0, 0, + 0, 0, 0, 230, 138, 32, + 0, 0, 0, 0, 0, 1, + 0, 0, 0, 70, 128, 32, + 0, 0, 0, 0, 0, 1, + 0, 0, 0, 62, 0, 0, + 1, 83, 84, 65, 84, 116, + 0, 0, 0, 4, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 3, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 82, + 68, 69, 70, 224, 0, 0, + 0, 1, 0, 0, 0, 64, + 0, 0, 0, 1, 0, 0, + 0, 28, 0, 0, 0, 0, + 4, 254, 255, 0, 1, 0, + 0, 174, 0, 0, 0, 60, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, + 0, 0, 0, 0, 0, 0, + 0, 99, 98, 48, 0, 60, + 0, 0, 0, 2, 0, 0, + 0, 88, 0, 0, 0, 32, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 136, + 0, 0, 0, 0, 0, 0, + 0, 16, 0, 0, 0, 2, + 0, 0, 0, 148, 0, 0, + 0, 0, 0, 0, 0, 164, + 0, 0, 0, 16, 0, 0, + 0, 16, 0, 0, 0, 2, + 0, 0, 0, 148, 0, 0, + 0, 0, 0, 0, 0, 81, + 117, 97, 100, 68, 101, 115, + 99, 0, 171, 171, 171, 1, + 0, 3, 0, 1, 0, 4, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 84, 101, 120, + 67, 111, 111, 114, 100, 115, + 0, 77, 105, 99, 114, 111, + 115, 111, 102, 116, 32, 40, + 82, 41, 32, 72, 76, 83, + 76, 32, 83, 104, 97, 100, + 101, 114, 32, 67, 111, 109, + 112, 105, 108, 101, 114, 32, + 57, 46, 50, 57, 46, 57, + 53, 50, 46, 51, 49, 49, + 49, 0, 171, 73, 83, 71, + 78, 44, 0, 0, 0, 1, + 0, 0, 0, 8, 0, 0, + 0, 32, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 3, 0, 0, 0, 0, + 0, 0, 0, 7, 3, 0, + 0, 80, 79, 83, 73, 84, + 73, 79, 78, 0, 171, 171, + 171, 79, 83, 71, 78, 80, + 0, 0, 0, 2, 0, 0, + 0, 8, 0, 0, 0, 56, + 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 3, + 0, 0, 0, 0, 0, 0, + 0, 15, 0, 0, 0, 68, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 3, + 0, 0, 0, 1, 0, 0, + 0, 3, 12, 0, 0, 83, + 86, 95, 80, 111, 115, 105, + 116, 105, 111, 110, 0, 84, + 69, 88, 67, 79, 79, 82, + 68, 0, 171, 171, 171, 129, + 2, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 2, + 0, 0, 0, 0, 0, 0, + 0, 188, 2, 0, 0, 68, + 88, 66, 67, 57, 173, 135, + 37, 0, 15, 237, 50, 142, + 80, 59, 160, 81, 240, 60, + 171, 1, 0, 0, 0, 188, + 2, 0, 0, 6, 0, 0, + 0, 56, 0, 0, 0, 164, + 0, 0, 0, 16, 1, 0, + 0, 140, 1, 0, 0, 48, + 2, 0, 0, 136, 2, 0, + 0, 65, 111, 110, 57, 100, + 0, 0, 0, 100, 0, 0, + 0, 0, 2, 255, 255, 60, + 0, 0, 0, 40, 0, 0, + 0, 0, 0, 40, 0, 0, + 0, 40, 0, 0, 0, 40, + 0, 1, 0, 36, 0, 0, + 0, 40, 0, 0, 0, 0, + 0, 1, 2, 255, 255, 31, + 0, 0, 2, 0, 0, 0, + 128, 0, 0, 3, 176, 31, + 0, 0, 2, 0, 0, 0, + 144, 0, 8, 15, 160, 66, + 0, 0, 3, 0, 0, 15, + 128, 0, 0, 228, 176, 0, + 8, 228, 160, 1, 0, 0, + 2, 0, 8, 15, 128, 0, + 0, 228, 128, 255, 255, 0, + 0, 83, 72, 68, 82, 100, + 0, 0, 0, 64, 0, 0, + 0, 25, 0, 0, 0, 90, + 0, 0, 3, 0, 96, 16, + 0, 0, 0, 0, 0, 88, + 24, 0, 4, 0, 112, 16, + 0, 0, 0, 0, 0, 85, + 85, 0, 0, 98, 16, 0, + 3, 50, 16, 16, 0, 1, + 0, 0, 0, 101, 0, 0, + 3, 242, 32, 16, 0, 0, + 0, 0, 0, 69, 0, 0, + 9, 242, 32, 16, 0, 0, + 0, 0, 0, 70, 16, 16, + 0, 1, 0, 0, 0, 70, + 126, 16, 0, 0, 0, 0, + 0, 0, 96, 16, 0, 0, + 0, 0, 0, 62, 0, 0, + 1, 83, 84, 65, 84, 116, + 0, 0, 0, 2, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 2, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 82, + 68, 69, 70, 156, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 2, 0, 0, + 0, 28, 0, 0, 0, 0, + 4, 255, 255, 0, 1, 0, + 0, 105, 0, 0, 0, 92, + 0, 0, 0, 3, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, + 0, 0, 0, 0, 0, 0, + 0, 101, 0, 0, 0, 2, + 0, 0, 0, 5, 0, 0, + 0, 4, 0, 0, 0, 255, + 255, 255, 255, 0, 0, 0, + 0, 1, 0, 0, 0, 12, + 0, 0, 0, 115, 83, 97, + 109, 112, 108, 101, 114, 0, + 116, 101, 120, 0, 77, 105, + 99, 114, 111, 115, 111, 102, + 116, 32, 40, 82, 41, 32, + 72, 76, 83, 76, 32, 83, + 104, 97, 100, 101, 114, 32, + 67, 111, 109, 112, 105, 108, + 101, 114, 32, 57, 46, 50, + 57, 46, 57, 53, 50, 46, + 51, 49, 49, 49, 0, 171, + 171, 73, 83, 71, 78, 80, + 0, 0, 0, 2, 0, 0, + 0, 8, 0, 0, 0, 56, + 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 3, + 0, 0, 0, 0, 0, 0, + 0, 15, 0, 0, 0, 68, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 3, + 0, 0, 0, 1, 0, 0, + 0, 3, 3, 0, 0, 83, + 86, 95, 80, 111, 115, 105, + 116, 105, 111, 110, 0, 84, + 69, 88, 67, 79, 79, 82, + 68, 0, 171, 171, 171, 79, + 83, 71, 78, 44, 0, 0, + 0, 1, 0, 0, 0, 8, + 0, 0, 0, 32, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 3, 0, 0, + 0, 0, 0, 0, 0, 15, + 0, 0, 0, 83, 86, 95, + 84, 97, 114, 103, 101, 116, + 0, 171, 171, 49, 6, 0, + 0, 0, 0, 0, 0, 83, + 97, 109, 112, 108, 101, 84, + 101, 120, 116, 117, 114, 101, + 87, 105, 116, 104, 83, 104, + 97, 100, 111, 119, 0, 4, + 0, 0, 0, 1, 0, 0, + 0, 0, 0, 128, 63, 1, + 0, 0, 0, 0, 0, 128, + 63, 1, 0, 0, 0, 0, + 0, 128, 63, 1, 0, 0, + 0, 0, 0, 128, 63, 1, + 0, 0, 0, 3, 0, 0, + 0, 255, 255, 255, 255, 152, + 3, 0, 0, 68, 88, 66, + 67, 219, 222, 190, 170, 104, + 118, 127, 154, 100, 214, 1, + 86, 70, 204, 61, 202, 1, + 0, 0, 0, 152, 3, 0, + 0, 6, 0, 0, 0, 56, + 0, 0, 0, 228, 0, 0, + 0, 168, 1, 0, 0, 36, + 2, 0, 0, 12, 3, 0, + 0, 64, 3, 0, 0, 65, + 111, 110, 57, 164, 0, 0, + 0, 164, 0, 0, 0, 0, + 2, 254, 255, 112, 0, 0, + 0, 52, 0, 0, 0, 1, + 0, 36, 0, 0, 0, 48, + 0, 0, 0, 48, 0, 0, + 0, 36, 0, 1, 0, 48, + 0, 0, 0, 0, 0, 2, + 0, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, + 2, 254, 255, 81, 0, 0, + 5, 3, 0, 15, 160, 0, + 0, 0, 0, 0, 0, 128, + 63, 0, 0, 0, 0, 0, + 0, 0, 0, 31, 0, 0, + 2, 5, 0, 0, 128, 0, + 0, 15, 144, 4, 0, 0, + 4, 0, 0, 3, 224, 0, + 0, 228, 144, 2, 0, 238, + 160, 2, 0, 228, 160, 4, + 0, 0, 4, 0, 0, 3, + 128, 0, 0, 228, 144, 1, + 0, 238, 160, 1, 0, 228, + 160, 2, 0, 0, 3, 0, + 0, 3, 192, 0, 0, 228, + 128, 0, 0, 228, 160, 1, + 0, 0, 2, 0, 0, 12, + 192, 3, 0, 68, 160, 255, + 255, 0, 0, 83, 72, 68, + 82, 188, 0, 0, 0, 64, + 0, 1, 0, 47, 0, 0, + 0, 89, 0, 0, 4, 70, + 142, 32, 0, 0, 0, 0, + 0, 2, 0, 0, 0, 95, + 0, 0, 3, 50, 16, 16, + 0, 0, 0, 0, 0, 103, + 0, 0, 4, 242, 32, 16, + 0, 0, 0, 0, 0, 1, + 0, 0, 0, 101, 0, 0, + 3, 50, 32, 16, 0, 1, + 0, 0, 0, 50, 0, 0, + 11, 50, 32, 16, 0, 0, + 0, 0, 0, 70, 16, 16, + 0, 0, 0, 0, 0, 230, + 138, 32, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 70, + 128, 32, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 54, + 0, 0, 8, 194, 32, 16, + 0, 0, 0, 0, 0, 2, + 64, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 128, + 63, 50, 0, 0, 11, 50, + 32, 16, 0, 1, 0, 0, + 0, 70, 16, 16, 0, 0, + 0, 0, 0, 230, 138, 32, + 0, 0, 0, 0, 0, 1, + 0, 0, 0, 70, 128, 32, + 0, 0, 0, 0, 0, 1, + 0, 0, 0, 62, 0, 0, + 1, 83, 84, 65, 84, 116, + 0, 0, 0, 4, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 3, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 82, + 68, 69, 70, 224, 0, 0, + 0, 1, 0, 0, 0, 64, + 0, 0, 0, 1, 0, 0, + 0, 28, 0, 0, 0, 0, + 4, 254, 255, 0, 1, 0, + 0, 174, 0, 0, 0, 60, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, + 0, 0, 0, 0, 0, 0, + 0, 99, 98, 48, 0, 60, + 0, 0, 0, 2, 0, 0, + 0, 88, 0, 0, 0, 32, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 136, + 0, 0, 0, 0, 0, 0, + 0, 16, 0, 0, 0, 2, + 0, 0, 0, 148, 0, 0, + 0, 0, 0, 0, 0, 164, + 0, 0, 0, 16, 0, 0, + 0, 16, 0, 0, 0, 2, + 0, 0, 0, 148, 0, 0, + 0, 0, 0, 0, 0, 81, + 117, 97, 100, 68, 101, 115, + 99, 0, 171, 171, 171, 1, + 0, 3, 0, 1, 0, 4, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 84, 101, 120, + 67, 111, 111, 114, 100, 115, + 0, 77, 105, 99, 114, 111, + 115, 111, 102, 116, 32, 40, + 82, 41, 32, 72, 76, 83, + 76, 32, 83, 104, 97, 100, + 101, 114, 32, 67, 111, 109, + 112, 105, 108, 101, 114, 32, + 57, 46, 50, 57, 46, 57, + 53, 50, 46, 51, 49, 49, + 49, 0, 171, 73, 83, 71, + 78, 44, 0, 0, 0, 1, + 0, 0, 0, 8, 0, 0, + 0, 32, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 3, 0, 0, 0, 0, + 0, 0, 0, 7, 3, 0, + 0, 80, 79, 83, 73, 84, + 73, 79, 78, 0, 171, 171, + 171, 79, 83, 71, 78, 80, + 0, 0, 0, 2, 0, 0, + 0, 8, 0, 0, 0, 56, + 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 3, + 0, 0, 0, 0, 0, 0, + 0, 15, 0, 0, 0, 68, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 3, + 0, 0, 0, 1, 0, 0, + 0, 3, 12, 0, 0, 83, + 86, 95, 80, 111, 115, 105, + 116, 105, 111, 110, 0, 84, + 69, 88, 67, 79, 79, 82, + 68, 0, 171, 171, 171, 65, + 9, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 2, + 0, 0, 0, 0, 0, 0, + 0, 208, 9, 0, 0, 68, + 88, 66, 67, 88, 125, 98, + 31, 252, 245, 86, 128, 184, + 245, 122, 45, 178, 60, 220, + 51, 1, 0, 0, 0, 208, + 9, 0, 0, 6, 0, 0, + 0, 56, 0, 0, 0, 248, + 2, 0, 0, 8, 7, 0, + 0, 132, 7, 0, 0, 68, + 9, 0, 0, 156, 9, 0, + 0, 65, 111, 110, 57, 184, + 2, 0, 0, 184, 2, 0, + 0, 0, 2, 255, 255, 120, + 2, 0, 0, 64, 0, 0, + 0, 2, 0, 40, 0, 0, + 0, 64, 0, 0, 0, 64, + 0, 1, 0, 36, 0, 0, + 0, 64, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 3, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 6, 0, 4, + 0, 3, 0, 0, 0, 0, + 0, 1, 2, 255, 255, 31, + 0, 0, 2, 0, 0, 0, + 128, 0, 0, 3, 176, 31, + 0, 0, 2, 0, 0, 0, + 144, 0, 8, 15, 160, 2, + 0, 0, 3, 0, 0, 1, + 128, 0, 0, 0, 176, 0, + 0, 85, 160, 1, 0, 0, + 2, 0, 0, 2, 128, 0, + 0, 85, 176, 2, 0, 0, + 3, 1, 0, 1, 128, 0, + 0, 0, 176, 0, 0, 0, + 160, 1, 0, 0, 2, 1, + 0, 2, 128, 0, 0, 85, + 176, 66, 0, 0, 3, 0, + 0, 15, 128, 0, 0, 228, + 128, 0, 8, 228, 160, 66, + 0, 0, 3, 1, 0, 15, + 128, 1, 0, 228, 128, 0, + 8, 228, 160, 5, 0, 0, + 3, 0, 0, 1, 128, 0, + 0, 255, 128, 3, 0, 85, + 160, 4, 0, 0, 4, 0, + 0, 1, 128, 3, 0, 0, + 160, 1, 0, 255, 128, 0, + 0, 0, 128, 2, 0, 0, + 3, 1, 0, 1, 128, 0, + 0, 0, 176, 0, 0, 170, + 160, 1, 0, 0, 2, 1, + 0, 2, 128, 0, 0, 85, + 176, 2, 0, 0, 3, 2, + 0, 1, 128, 0, 0, 0, + 176, 0, 0, 255, 160, 1, + 0, 0, 2, 2, 0, 2, + 128, 0, 0, 85, 176, 66, + 0, 0, 3, 1, 0, 15, + 128, 1, 0, 228, 128, 0, + 8, 228, 160, 66, 0, 0, + 3, 2, 0, 15, 128, 2, + 0, 228, 128, 0, 8, 228, + 160, 4, 0, 0, 4, 0, + 0, 1, 128, 3, 0, 170, + 160, 1, 0, 255, 128, 0, + 0, 0, 128, 4, 0, 0, + 4, 0, 0, 1, 128, 3, + 0, 255, 160, 2, 0, 255, + 128, 0, 0, 0, 128, 2, + 0, 0, 3, 1, 0, 1, + 128, 0, 0, 0, 176, 1, + 0, 0, 160, 1, 0, 0, + 2, 1, 0, 2, 128, 0, + 0, 85, 176, 2, 0, 0, + 3, 2, 0, 1, 128, 0, + 0, 0, 176, 1, 0, 85, + 160, 1, 0, 0, 2, 2, + 0, 2, 128, 0, 0, 85, + 176, 66, 0, 0, 3, 1, + 0, 15, 128, 1, 0, 228, + 128, 0, 8, 228, 160, 66, + 0, 0, 3, 2, 0, 15, + 128, 2, 0, 228, 128, 0, + 8, 228, 160, 4, 0, 0, + 4, 0, 0, 1, 128, 4, + 0, 0, 160, 1, 0, 255, + 128, 0, 0, 0, 128, 4, + 0, 0, 4, 0, 0, 1, + 128, 4, 0, 85, 160, 2, + 0, 255, 128, 0, 0, 0, + 128, 2, 0, 0, 3, 1, + 0, 1, 128, 0, 0, 0, + 176, 1, 0, 170, 160, 1, + 0, 0, 2, 1, 0, 2, + 128, 0, 0, 85, 176, 2, + 0, 0, 3, 2, 0, 1, + 128, 0, 0, 0, 176, 1, + 0, 255, 160, 1, 0, 0, + 2, 2, 0, 2, 128, 0, + 0, 85, 176, 66, 0, 0, + 3, 1, 0, 15, 128, 1, + 0, 228, 128, 0, 8, 228, + 160, 66, 0, 0, 3, 2, + 0, 15, 128, 2, 0, 228, + 128, 0, 8, 228, 160, 4, + 0, 0, 4, 0, 0, 1, + 128, 4, 0, 170, 160, 1, + 0, 255, 128, 0, 0, 0, + 128, 4, 0, 0, 4, 0, + 0, 1, 128, 4, 0, 255, + 160, 2, 0, 255, 128, 0, + 0, 0, 128, 2, 0, 0, + 3, 1, 0, 1, 128, 0, + 0, 0, 176, 2, 0, 0, + 160, 1, 0, 0, 2, 1, + 0, 2, 128, 0, 0, 85, + 176, 66, 0, 0, 3, 1, + 0, 15, 128, 1, 0, 228, + 128, 0, 8, 228, 160, 4, + 0, 0, 4, 0, 0, 1, + 128, 5, 0, 0, 160, 1, + 0, 255, 128, 0, 0, 0, + 128, 5, 0, 0, 3, 0, + 0, 15, 128, 0, 0, 0, + 128, 6, 0, 228, 160, 1, + 0, 0, 2, 0, 8, 15, + 128, 0, 0, 228, 128, 255, + 255, 0, 0, 83, 72, 68, + 82, 8, 4, 0, 0, 64, + 0, 0, 0, 2, 1, 0, + 0, 89, 0, 0, 4, 70, + 142, 32, 0, 0, 0, 0, + 0, 10, 0, 0, 0, 90, + 0, 0, 3, 0, 96, 16, + 0, 0, 0, 0, 0, 88, + 24, 0, 4, 0, 112, 16, + 0, 0, 0, 0, 0, 85, + 85, 0, 0, 98, 16, 0, + 3, 50, 16, 16, 0, 1, + 0, 0, 0, 101, 0, 0, + 3, 242, 32, 16, 0, 0, + 0, 0, 0, 104, 0, 0, + 2, 4, 0, 0, 0, 0, + 0, 0, 8, 242, 0, 16, + 0, 0, 0, 0, 0, 6, + 16, 16, 0, 1, 0, 0, + 0, 38, 135, 32, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 54, 0, 0, 5, 82, + 0, 16, 0, 1, 0, 0, + 0, 86, 7, 16, 0, 0, + 0, 0, 0, 54, 0, 0, + 5, 162, 0, 16, 0, 1, + 0, 0, 0, 86, 21, 16, + 0, 1, 0, 0, 0, 69, + 0, 0, 9, 242, 0, 16, + 0, 2, 0, 0, 0, 230, + 10, 16, 0, 1, 0, 0, + 0, 70, 126, 16, 0, 0, + 0, 0, 0, 0, 96, 16, + 0, 0, 0, 0, 0, 69, + 0, 0, 9, 242, 0, 16, + 0, 1, 0, 0, 0, 70, + 0, 16, 0, 1, 0, 0, + 0, 70, 126, 16, 0, 0, + 0, 0, 0, 0, 96, 16, + 0, 0, 0, 0, 0, 56, + 0, 0, 8, 18, 0, 16, + 0, 1, 0, 0, 0, 58, + 0, 16, 0, 2, 0, 0, + 0, 26, 128, 32, 0, 0, + 0, 0, 0, 6, 0, 0, + 0, 50, 0, 0, 10, 18, + 0, 16, 0, 1, 0, 0, + 0, 10, 128, 32, 0, 0, + 0, 0, 0, 6, 0, 0, + 0, 58, 0, 16, 0, 1, + 0, 0, 0, 10, 0, 16, + 0, 1, 0, 0, 0, 54, + 0, 0, 5, 162, 0, 16, + 0, 0, 0, 0, 0, 86, + 21, 16, 0, 1, 0, 0, + 0, 69, 0, 0, 9, 242, + 0, 16, 0, 2, 0, 0, + 0, 70, 0, 16, 0, 0, + 0, 0, 0, 70, 126, 16, + 0, 0, 0, 0, 0, 0, + 96, 16, 0, 0, 0, 0, + 0, 69, 0, 0, 9, 242, + 0, 16, 0, 0, 0, 0, + 0, 230, 10, 16, 0, 0, + 0, 0, 0, 70, 126, 16, + 0, 0, 0, 0, 0, 0, + 96, 16, 0, 0, 0, 0, + 0, 50, 0, 0, 10, 18, + 0, 16, 0, 0, 0, 0, + 0, 42, 128, 32, 0, 0, + 0, 0, 0, 6, 0, 0, + 0, 58, 0, 16, 0, 2, + 0, 0, 0, 10, 0, 16, + 0, 1, 0, 0, 0, 50, + 0, 0, 10, 18, 0, 16, + 0, 0, 0, 0, 0, 58, + 128, 32, 0, 0, 0, 0, + 0, 6, 0, 0, 0, 58, + 0, 16, 0, 0, 0, 0, + 0, 10, 0, 16, 0, 0, + 0, 0, 0, 0, 0, 0, + 8, 242, 0, 16, 0, 1, + 0, 0, 0, 6, 16, 16, + 0, 1, 0, 0, 0, 38, + 135, 32, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 54, + 0, 0, 5, 82, 0, 16, + 0, 2, 0, 0, 0, 86, + 7, 16, 0, 1, 0, 0, + 0, 54, 0, 0, 5, 162, + 0, 16, 0, 2, 0, 0, + 0, 86, 21, 16, 0, 1, + 0, 0, 0, 69, 0, 0, + 9, 242, 0, 16, 0, 3, + 0, 0, 0, 70, 0, 16, + 0, 2, 0, 0, 0, 70, + 126, 16, 0, 0, 0, 0, + 0, 0, 96, 16, 0, 0, + 0, 0, 0, 69, 0, 0, + 9, 242, 0, 16, 0, 2, + 0, 0, 0, 230, 10, 16, + 0, 2, 0, 0, 0, 70, + 126, 16, 0, 0, 0, 0, + 0, 0, 96, 16, 0, 0, + 0, 0, 0, 50, 0, 0, + 10, 18, 0, 16, 0, 0, + 0, 0, 0, 10, 128, 32, + 0, 0, 0, 0, 0, 7, + 0, 0, 0, 58, 0, 16, + 0, 3, 0, 0, 0, 10, + 0, 16, 0, 0, 0, 0, + 0, 50, 0, 0, 10, 18, + 0, 16, 0, 0, 0, 0, + 0, 26, 128, 32, 0, 0, + 0, 0, 0, 7, 0, 0, + 0, 58, 0, 16, 0, 2, + 0, 0, 0, 10, 0, 16, + 0, 0, 0, 0, 0, 54, + 0, 0, 5, 162, 0, 16, + 0, 1, 0, 0, 0, 86, + 21, 16, 0, 1, 0, 0, + 0, 69, 0, 0, 9, 242, + 0, 16, 0, 2, 0, 0, + 0, 70, 0, 16, 0, 1, + 0, 0, 0, 70, 126, 16, + 0, 0, 0, 0, 0, 0, + 96, 16, 0, 0, 0, 0, + 0, 69, 0, 0, 9, 242, + 0, 16, 0, 1, 0, 0, + 0, 230, 10, 16, 0, 1, + 0, 0, 0, 70, 126, 16, + 0, 0, 0, 0, 0, 0, + 96, 16, 0, 0, 0, 0, + 0, 50, 0, 0, 10, 18, + 0, 16, 0, 0, 0, 0, + 0, 42, 128, 32, 0, 0, + 0, 0, 0, 7, 0, 0, + 0, 58, 0, 16, 0, 2, + 0, 0, 0, 10, 0, 16, + 0, 0, 0, 0, 0, 50, + 0, 0, 10, 18, 0, 16, + 0, 0, 0, 0, 0, 58, + 128, 32, 0, 0, 0, 0, + 0, 7, 0, 0, 0, 58, + 0, 16, 0, 1, 0, 0, + 0, 10, 0, 16, 0, 0, + 0, 0, 0, 0, 0, 0, + 8, 18, 0, 16, 0, 1, + 0, 0, 0, 10, 16, 16, + 0, 1, 0, 0, 0, 10, + 128, 32, 0, 0, 0, 0, + 0, 2, 0, 0, 0, 54, + 0, 0, 5, 34, 0, 16, + 0, 1, 0, 0, 0, 26, + 16, 16, 0, 1, 0, 0, + 0, 69, 0, 0, 9, 242, + 0, 16, 0, 1, 0, 0, + 0, 70, 0, 16, 0, 1, + 0, 0, 0, 70, 126, 16, + 0, 0, 0, 0, 0, 0, + 96, 16, 0, 0, 0, 0, + 0, 50, 0, 0, 10, 18, + 0, 16, 0, 0, 0, 0, + 0, 10, 128, 32, 0, 0, + 0, 0, 0, 8, 0, 0, + 0, 58, 0, 16, 0, 1, + 0, 0, 0, 10, 0, 16, + 0, 0, 0, 0, 0, 56, + 0, 0, 8, 242, 32, 16, + 0, 0, 0, 0, 0, 6, + 0, 16, 0, 0, 0, 0, + 0, 70, 142, 32, 0, 0, + 0, 0, 0, 9, 0, 0, + 0, 62, 0, 0, 1, 83, + 84, 65, 84, 116, 0, 0, + 0, 30, 0, 0, 0, 4, + 0, 0, 0, 0, 0, 0, + 0, 2, 0, 0, 0, 5, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 9, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 9, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 82, 68, 69, + 70, 184, 1, 0, 0, 1, + 0, 0, 0, 148, 0, 0, + 0, 3, 0, 0, 0, 28, + 0, 0, 0, 0, 4, 255, + 255, 0, 1, 0, 0, 132, + 1, 0, 0, 124, 0, 0, + 0, 3, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 139, + 0, 0, 0, 2, 0, 0, + 0, 5, 0, 0, 0, 4, + 0, 0, 0, 255, 255, 255, + 255, 0, 0, 0, 0, 1, + 0, 0, 0, 12, 0, 0, + 0, 143, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, + 0, 0, 0, 115, 83, 104, + 97, 100, 111, 119, 83, 97, + 109, 112, 108, 101, 114, 0, + 116, 101, 120, 0, 99, 98, + 49, 0, 171, 143, 0, 0, + 0, 4, 0, 0, 0, 172, + 0, 0, 0, 160, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 12, 1, 0, + 0, 0, 0, 0, 0, 48, + 0, 0, 0, 2, 0, 0, + 0, 28, 1, 0, 0, 0, + 0, 0, 0, 44, 1, 0, + 0, 48, 0, 0, 0, 48, + 0, 0, 0, 0, 0, 0, + 0, 60, 1, 0, 0, 0, + 0, 0, 0, 76, 1, 0, + 0, 96, 0, 0, 0, 48, + 0, 0, 0, 2, 0, 0, + 0, 88, 1, 0, 0, 0, + 0, 0, 0, 104, 1, 0, + 0, 144, 0, 0, 0, 16, + 0, 0, 0, 2, 0, 0, + 0, 116, 1, 0, 0, 0, + 0, 0, 0, 66, 108, 117, + 114, 79, 102, 102, 115, 101, + 116, 115, 72, 0, 171, 171, + 171, 1, 0, 3, 0, 1, + 0, 4, 0, 3, 0, 0, + 0, 0, 0, 0, 0, 66, + 108, 117, 114, 79, 102, 102, + 115, 101, 116, 115, 86, 0, + 171, 171, 171, 1, 0, 3, + 0, 1, 0, 4, 0, 3, + 0, 0, 0, 0, 0, 0, + 0, 66, 108, 117, 114, 87, + 101, 105, 103, 104, 116, 115, + 0, 1, 0, 3, 0, 1, + 0, 4, 0, 3, 0, 0, + 0, 0, 0, 0, 0, 83, + 104, 97, 100, 111, 119, 67, + 111, 108, 111, 114, 0, 1, + 0, 3, 0, 1, 0, 4, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 77, 105, 99, + 114, 111, 115, 111, 102, 116, + 32, 40, 82, 41, 32, 72, + 76, 83, 76, 32, 83, 104, + 97, 100, 101, 114, 32, 67, + 111, 109, 112, 105, 108, 101, + 114, 32, 57, 46, 50, 57, + 46, 57, 53, 50, 46, 51, + 49, 49, 49, 0, 171, 171, + 171, 73, 83, 71, 78, 80, + 0, 0, 0, 2, 0, 0, + 0, 8, 0, 0, 0, 56, + 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 3, + 0, 0, 0, 0, 0, 0, + 0, 15, 0, 0, 0, 68, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 3, + 0, 0, 0, 1, 0, 0, + 0, 3, 3, 0, 0, 83, + 86, 95, 80, 111, 115, 105, + 116, 105, 111, 110, 0, 84, + 69, 88, 67, 79, 79, 82, + 68, 0, 171, 171, 171, 79, + 83, 71, 78, 44, 0, 0, + 0, 1, 0, 0, 0, 8, + 0, 0, 0, 32, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 3, 0, 0, + 0, 0, 0, 0, 0, 15, + 0, 0, 0, 83, 86, 95, + 84, 97, 114, 103, 101, 116, + 0, 171, 171, 241, 12, 0, + 0, 0, 0, 0, 0, 80, + 49, 0, 4, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 128, 63, 1, 0, 0, 0, + 0, 0, 128, 63, 1, 0, + 0, 0, 0, 0, 128, 63, + 1, 0, 0, 0, 0, 0, + 128, 63, 1, 0, 0, 0, + 3, 0, 0, 0, 255, 255, + 255, 255, 152, 3, 0, 0, + 68, 88, 66, 67, 219, 222, + 190, 170, 104, 118, 127, 154, + 100, 214, 1, 86, 70, 204, + 61, 202, 1, 0, 0, 0, + 152, 3, 0, 0, 6, 0, + 0, 0, 56, 0, 0, 0, + 228, 0, 0, 0, 168, 1, + 0, 0, 36, 2, 0, 0, + 12, 3, 0, 0, 64, 3, + 0, 0, 65, 111, 110, 57, + 164, 0, 0, 0, 164, 0, + 0, 0, 0, 2, 254, 255, + 112, 0, 0, 0, 52, 0, + 0, 0, 1, 0, 36, 0, + 0, 0, 48, 0, 0, 0, + 48, 0, 0, 0, 36, 0, + 1, 0, 48, 0, 0, 0, + 0, 0, 2, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 2, 254, 255, + 81, 0, 0, 5, 3, 0, + 15, 160, 0, 0, 0, 0, + 0, 0, 128, 63, 0, 0, + 0, 0, 0, 0, 0, 0, + 31, 0, 0, 2, 5, 0, + 0, 128, 0, 0, 15, 144, + 4, 0, 0, 4, 0, 0, + 3, 224, 0, 0, 228, 144, + 2, 0, 238, 160, 2, 0, + 228, 160, 4, 0, 0, 4, + 0, 0, 3, 128, 0, 0, + 228, 144, 1, 0, 238, 160, + 1, 0, 228, 160, 2, 0, + 0, 3, 0, 0, 3, 192, + 0, 0, 228, 128, 0, 0, + 228, 160, 1, 0, 0, 2, + 0, 0, 12, 192, 3, 0, + 68, 160, 255, 255, 0, 0, + 83, 72, 68, 82, 188, 0, + 0, 0, 64, 0, 1, 0, + 47, 0, 0, 0, 89, 0, + 0, 4, 70, 142, 32, 0, + 0, 0, 0, 0, 2, 0, + 0, 0, 95, 0, 0, 3, + 50, 16, 16, 0, 0, 0, + 0, 0, 103, 0, 0, 4, + 242, 32, 16, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 101, 0, 0, 3, 50, 32, + 16, 0, 1, 0, 0, 0, + 50, 0, 0, 11, 50, 32, + 16, 0, 0, 0, 0, 0, + 70, 16, 16, 0, 0, 0, + 0, 0, 230, 138, 32, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 70, 128, 32, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 54, 0, 0, 8, + 194, 32, 16, 0, 0, 0, + 0, 0, 2, 64, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 128, 63, 50, 0, + 0, 11, 50, 32, 16, 0, + 1, 0, 0, 0, 70, 16, + 16, 0, 0, 0, 0, 0, + 230, 138, 32, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 70, 128, 32, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 62, 0, 0, 1, 83, 84, + 65, 84, 116, 0, 0, 0, + 4, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 3, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 82, 68, 69, 70, + 224, 0, 0, 0, 1, 0, + 0, 0, 64, 0, 0, 0, + 1, 0, 0, 0, 28, 0, + 0, 0, 0, 4, 254, 255, + 0, 1, 0, 0, 174, 0, + 0, 0, 60, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 99, 98, + 48, 0, 60, 0, 0, 0, + 2, 0, 0, 0, 88, 0, + 0, 0, 32, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 136, 0, 0, 0, + 0, 0, 0, 0, 16, 0, + 0, 0, 2, 0, 0, 0, + 148, 0, 0, 0, 0, 0, + 0, 0, 164, 0, 0, 0, + 16, 0, 0, 0, 16, 0, + 0, 0, 2, 0, 0, 0, + 148, 0, 0, 0, 0, 0, + 0, 0, 81, 117, 97, 100, + 68, 101, 115, 99, 0, 171, + 171, 171, 1, 0, 3, 0, + 1, 0, 4, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 84, 101, 120, 67, 111, 111, + 114, 100, 115, 0, 77, 105, + 99, 114, 111, 115, 111, 102, + 116, 32, 40, 82, 41, 32, + 72, 76, 83, 76, 32, 83, + 104, 97, 100, 101, 114, 32, + 67, 111, 109, 112, 105, 108, + 101, 114, 32, 57, 46, 50, + 57, 46, 57, 53, 50, 46, + 51, 49, 49, 49, 0, 171, + 73, 83, 71, 78, 44, 0, + 0, 0, 1, 0, 0, 0, + 8, 0, 0, 0, 32, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 0, + 0, 0, 0, 0, 0, 0, + 7, 3, 0, 0, 80, 79, + 83, 73, 84, 73, 79, 78, + 0, 171, 171, 171, 79, 83, + 71, 78, 80, 0, 0, 0, + 2, 0, 0, 0, 8, 0, + 0, 0, 56, 0, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 3, 0, 0, 0, + 0, 0, 0, 0, 15, 0, + 0, 0, 68, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 3, 0, 0, 0, + 1, 0, 0, 0, 3, 12, + 0, 0, 83, 86, 95, 80, + 111, 115, 105, 116, 105, 111, + 110, 0, 84, 69, 88, 67, + 79, 79, 82, 68, 0, 171, + 171, 171, 0, 23, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 2, 0, 0, 0, + 0, 0, 0, 0, 148, 9, + 0, 0, 68, 88, 66, 67, + 85, 100, 180, 99, 66, 90, + 93, 94, 187, 62, 74, 197, + 245, 70, 87, 170, 1, 0, + 0, 0, 148, 9, 0, 0, + 6, 0, 0, 0, 56, 0, + 0, 0, 220, 2, 0, 0, + 204, 6, 0, 0, 72, 7, + 0, 0, 8, 9, 0, 0, + 96, 9, 0, 0, 65, 111, + 110, 57, 156, 2, 0, 0, + 156, 2, 0, 0, 0, 2, + 255, 255, 104, 2, 0, 0, + 52, 0, 0, 0, 1, 0, + 40, 0, 0, 0, 52, 0, + 0, 0, 52, 0, 1, 0, + 36, 0, 0, 0, 52, 0, + 0, 0, 0, 0, 0, 0, + 3, 0, 6, 0, 0, 0, + 0, 0, 0, 0, 1, 2, + 255, 255, 31, 0, 0, 2, + 0, 0, 0, 128, 0, 0, + 3, 176, 31, 0, 0, 2, + 0, 0, 0, 144, 0, 8, + 15, 160, 2, 0, 0, 3, + 0, 0, 2, 128, 0, 0, + 85, 176, 0, 0, 85, 160, + 1, 0, 0, 2, 0, 0, + 1, 128, 0, 0, 0, 176, + 2, 0, 0, 3, 1, 0, + 2, 128, 0, 0, 85, 176, + 0, 0, 0, 160, 1, 0, + 0, 2, 1, 0, 1, 128, + 0, 0, 0, 176, 66, 0, + 0, 3, 0, 0, 15, 128, + 0, 0, 228, 128, 0, 8, + 228, 160, 66, 0, 0, 3, + 1, 0, 15, 128, 1, 0, + 228, 128, 0, 8, 228, 160, + 5, 0, 0, 3, 0, 0, + 15, 128, 0, 0, 228, 128, + 3, 0, 85, 160, 4, 0, + 0, 4, 0, 0, 15, 128, + 3, 0, 0, 160, 1, 0, + 228, 128, 0, 0, 228, 128, + 2, 0, 0, 3, 1, 0, + 2, 128, 0, 0, 85, 176, + 0, 0, 170, 160, 1, 0, + 0, 2, 1, 0, 1, 128, + 0, 0, 0, 176, 2, 0, + 0, 3, 2, 0, 2, 128, + 0, 0, 85, 176, 0, 0, + 255, 160, 1, 0, 0, 2, + 2, 0, 1, 128, 0, 0, + 0, 176, 66, 0, 0, 3, + 1, 0, 15, 128, 1, 0, + 228, 128, 0, 8, 228, 160, + 66, 0, 0, 3, 2, 0, + 15, 128, 2, 0, 228, 128, + 0, 8, 228, 160, 4, 0, + 0, 4, 0, 0, 15, 128, + 3, 0, 170, 160, 1, 0, + 228, 128, 0, 0, 228, 128, + 4, 0, 0, 4, 0, 0, + 15, 128, 3, 0, 255, 160, + 2, 0, 228, 128, 0, 0, + 228, 128, 2, 0, 0, 3, + 1, 0, 2, 128, 0, 0, + 85, 176, 1, 0, 0, 160, + 1, 0, 0, 2, 1, 0, + 1, 128, 0, 0, 0, 176, + 2, 0, 0, 3, 2, 0, + 2, 128, 0, 0, 85, 176, + 1, 0, 85, 160, 1, 0, + 0, 2, 2, 0, 1, 128, + 0, 0, 0, 176, 66, 0, + 0, 3, 1, 0, 15, 128, + 1, 0, 228, 128, 0, 8, + 228, 160, 66, 0, 0, 3, + 2, 0, 15, 128, 2, 0, + 228, 128, 0, 8, 228, 160, + 4, 0, 0, 4, 0, 0, + 15, 128, 4, 0, 0, 160, + 1, 0, 228, 128, 0, 0, + 228, 128, 4, 0, 0, 4, + 0, 0, 15, 128, 4, 0, + 85, 160, 2, 0, 228, 128, + 0, 0, 228, 128, 2, 0, + 0, 3, 1, 0, 2, 128, + 0, 0, 85, 176, 1, 0, + 170, 160, 1, 0, 0, 2, + 1, 0, 1, 128, 0, 0, + 0, 176, 2, 0, 0, 3, + 2, 0, 2, 128, 0, 0, + 85, 176, 1, 0, 255, 160, + 1, 0, 0, 2, 2, 0, + 1, 128, 0, 0, 0, 176, + 66, 0, 0, 3, 1, 0, + 15, 128, 1, 0, 228, 128, + 0, 8, 228, 160, 66, 0, + 0, 3, 2, 0, 15, 128, + 2, 0, 228, 128, 0, 8, + 228, 160, 4, 0, 0, 4, + 0, 0, 15, 128, 4, 0, + 170, 160, 1, 0, 228, 128, + 0, 0, 228, 128, 4, 0, + 0, 4, 0, 0, 15, 128, + 4, 0, 255, 160, 2, 0, + 228, 128, 0, 0, 228, 128, + 2, 0, 0, 3, 1, 0, + 2, 128, 0, 0, 85, 176, + 2, 0, 0, 160, 1, 0, + 0, 2, 1, 0, 1, 128, + 0, 0, 0, 176, 66, 0, + 0, 3, 1, 0, 15, 128, + 1, 0, 228, 128, 0, 8, + 228, 160, 4, 0, 0, 4, + 0, 0, 15, 128, 5, 0, + 0, 160, 1, 0, 228, 128, + 0, 0, 228, 128, 1, 0, + 0, 2, 0, 8, 15, 128, + 0, 0, 228, 128, 255, 255, + 0, 0, 83, 72, 68, 82, + 232, 3, 0, 0, 64, 0, + 0, 0, 250, 0, 0, 0, + 89, 0, 0, 4, 70, 142, + 32, 0, 0, 0, 0, 0, + 9, 0, 0, 0, 90, 0, + 0, 3, 0, 96, 16, 0, + 0, 0, 0, 0, 88, 24, + 0, 4, 0, 112, 16, 0, + 0, 0, 0, 0, 85, 85, + 0, 0, 98, 16, 0, 3, + 50, 16, 16, 0, 1, 0, + 0, 0, 101, 0, 0, 3, + 242, 32, 16, 0, 0, 0, + 0, 0, 104, 0, 0, 2, + 4, 0, 0, 0, 54, 0, + 0, 5, 82, 0, 16, 0, + 0, 0, 0, 0, 6, 16, + 16, 0, 1, 0, 0, 0, + 0, 0, 0, 8, 242, 0, + 16, 0, 1, 0, 0, 0, + 86, 21, 16, 0, 1, 0, + 0, 0, 134, 141, 32, 0, + 0, 0, 0, 0, 3, 0, + 0, 0, 54, 0, 0, 5, + 162, 0, 16, 0, 0, 0, + 0, 0, 6, 8, 16, 0, + 1, 0, 0, 0, 69, 0, + 0, 9, 242, 0, 16, 0, + 2, 0, 0, 0, 230, 10, + 16, 0, 0, 0, 0, 0, + 70, 126, 16, 0, 0, 0, + 0, 0, 0, 96, 16, 0, + 0, 0, 0, 0, 69, 0, + 0, 9, 242, 0, 16, 0, + 0, 0, 0, 0, 70, 0, + 16, 0, 0, 0, 0, 0, + 70, 126, 16, 0, 0, 0, + 0, 0, 0, 96, 16, 0, + 0, 0, 0, 0, 56, 0, + 0, 8, 242, 0, 16, 0, + 2, 0, 0, 0, 70, 14, + 16, 0, 2, 0, 0, 0, + 86, 133, 32, 0, 0, 0, + 0, 0, 6, 0, 0, 0, + 50, 0, 0, 10, 242, 0, + 16, 0, 0, 0, 0, 0, + 6, 128, 32, 0, 0, 0, + 0, 0, 6, 0, 0, 0, + 70, 14, 16, 0, 0, 0, + 0, 0, 70, 14, 16, 0, + 2, 0, 0, 0, 54, 0, + 0, 5, 82, 0, 16, 0, + 1, 0, 0, 0, 6, 16, + 16, 0, 1, 0, 0, 0, + 69, 0, 0, 9, 242, 0, + 16, 0, 2, 0, 0, 0, + 70, 0, 16, 0, 1, 0, + 0, 0, 70, 126, 16, 0, + 0, 0, 0, 0, 0, 96, + 16, 0, 0, 0, 0, 0, + 69, 0, 0, 9, 242, 0, + 16, 0, 1, 0, 0, 0, + 230, 10, 16, 0, 1, 0, + 0, 0, 70, 126, 16, 0, + 0, 0, 0, 0, 0, 96, + 16, 0, 0, 0, 0, 0, + 50, 0, 0, 10, 242, 0, + 16, 0, 0, 0, 0, 0, + 166, 138, 32, 0, 0, 0, + 0, 0, 6, 0, 0, 0, + 70, 14, 16, 0, 2, 0, + 0, 0, 70, 14, 16, 0, + 0, 0, 0, 0, 50, 0, + 0, 10, 242, 0, 16, 0, + 0, 0, 0, 0, 246, 143, + 32, 0, 0, 0, 0, 0, + 6, 0, 0, 0, 70, 14, + 16, 0, 1, 0, 0, 0, + 70, 14, 16, 0, 0, 0, + 0, 0, 54, 0, 0, 5, + 82, 0, 16, 0, 1, 0, + 0, 0, 6, 16, 16, 0, + 1, 0, 0, 0, 0, 0, + 0, 8, 242, 0, 16, 0, + 2, 0, 0, 0, 86, 21, + 16, 0, 1, 0, 0, 0, + 134, 141, 32, 0, 0, 0, + 0, 0, 4, 0, 0, 0, + 54, 0, 0, 5, 162, 0, + 16, 0, 1, 0, 0, 0, + 6, 8, 16, 0, 2, 0, + 0, 0, 69, 0, 0, 9, + 242, 0, 16, 0, 3, 0, + 0, 0, 70, 0, 16, 0, + 1, 0, 0, 0, 70, 126, + 16, 0, 0, 0, 0, 0, + 0, 96, 16, 0, 0, 0, + 0, 0, 69, 0, 0, 9, + 242, 0, 16, 0, 1, 0, + 0, 0, 230, 10, 16, 0, + 1, 0, 0, 0, 70, 126, + 16, 0, 0, 0, 0, 0, + 0, 96, 16, 0, 0, 0, + 0, 0, 50, 0, 0, 10, + 242, 0, 16, 0, 0, 0, + 0, 0, 6, 128, 32, 0, + 0, 0, 0, 0, 7, 0, + 0, 0, 70, 14, 16, 0, + 3, 0, 0, 0, 70, 14, + 16, 0, 0, 0, 0, 0, + 50, 0, 0, 10, 242, 0, + 16, 0, 0, 0, 0, 0, + 86, 133, 32, 0, 0, 0, + 0, 0, 7, 0, 0, 0, + 70, 14, 16, 0, 1, 0, + 0, 0, 70, 14, 16, 0, + 0, 0, 0, 0, 54, 0, + 0, 5, 82, 0, 16, 0, + 2, 0, 0, 0, 6, 16, + 16, 0, 1, 0, 0, 0, + 69, 0, 0, 9, 242, 0, + 16, 0, 1, 0, 0, 0, + 70, 0, 16, 0, 2, 0, + 0, 0, 70, 126, 16, 0, + 0, 0, 0, 0, 0, 96, + 16, 0, 0, 0, 0, 0, + 69, 0, 0, 9, 242, 0, + 16, 0, 2, 0, 0, 0, + 230, 10, 16, 0, 2, 0, + 0, 0, 70, 126, 16, 0, + 0, 0, 0, 0, 0, 96, + 16, 0, 0, 0, 0, 0, + 50, 0, 0, 10, 242, 0, + 16, 0, 0, 0, 0, 0, + 166, 138, 32, 0, 0, 0, + 0, 0, 7, 0, 0, 0, + 70, 14, 16, 0, 1, 0, + 0, 0, 70, 14, 16, 0, + 0, 0, 0, 0, 50, 0, + 0, 10, 242, 0, 16, 0, + 0, 0, 0, 0, 246, 143, + 32, 0, 0, 0, 0, 0, + 7, 0, 0, 0, 70, 14, + 16, 0, 2, 0, 0, 0, + 70, 14, 16, 0, 0, 0, + 0, 0, 0, 0, 0, 8, + 34, 0, 16, 0, 1, 0, + 0, 0, 26, 16, 16, 0, + 1, 0, 0, 0, 10, 128, + 32, 0, 0, 0, 0, 0, + 5, 0, 0, 0, 54, 0, + 0, 5, 18, 0, 16, 0, + 1, 0, 0, 0, 10, 16, + 16, 0, 1, 0, 0, 0, + 69, 0, 0, 9, 242, 0, + 16, 0, 1, 0, 0, 0, + 70, 0, 16, 0, 1, 0, + 0, 0, 70, 126, 16, 0, + 0, 0, 0, 0, 0, 96, + 16, 0, 0, 0, 0, 0, + 50, 0, 0, 10, 242, 32, + 16, 0, 0, 0, 0, 0, + 6, 128, 32, 0, 0, 0, + 0, 0, 8, 0, 0, 0, + 70, 14, 16, 0, 1, 0, + 0, 0, 70, 14, 16, 0, + 0, 0, 0, 0, 62, 0, + 0, 1, 83, 84, 65, 84, + 116, 0, 0, 0, 29, 0, + 0, 0, 4, 0, 0, 0, + 0, 0, 0, 0, 2, 0, + 0, 0, 4, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 9, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 9, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 82, 68, 69, 70, 184, 1, + 0, 0, 1, 0, 0, 0, + 148, 0, 0, 0, 3, 0, + 0, 0, 28, 0, 0, 0, + 0, 4, 255, 255, 0, 1, + 0, 0, 132, 1, 0, 0, + 124, 0, 0, 0, 3, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 0, 0, 139, 0, 0, 0, + 2, 0, 0, 0, 5, 0, + 0, 0, 4, 0, 0, 0, + 255, 255, 255, 255, 0, 0, + 0, 0, 1, 0, 0, 0, + 12, 0, 0, 0, 143, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 115, 83, 104, 97, 100, 111, + 119, 83, 97, 109, 112, 108, + 101, 114, 0, 116, 101, 120, + 0, 99, 98, 49, 0, 171, + 143, 0, 0, 0, 4, 0, + 0, 0, 172, 0, 0, 0, + 160, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 12, 1, 0, 0, 0, 0, + 0, 0, 48, 0, 0, 0, + 0, 0, 0, 0, 28, 1, + 0, 0, 0, 0, 0, 0, + 44, 1, 0, 0, 48, 0, + 0, 0, 48, 0, 0, 0, + 2, 0, 0, 0, 60, 1, + 0, 0, 0, 0, 0, 0, + 76, 1, 0, 0, 96, 0, + 0, 0, 48, 0, 0, 0, + 2, 0, 0, 0, 88, 1, + 0, 0, 0, 0, 0, 0, + 104, 1, 0, 0, 144, 0, + 0, 0, 16, 0, 0, 0, + 0, 0, 0, 0, 116, 1, + 0, 0, 0, 0, 0, 0, + 66, 108, 117, 114, 79, 102, + 102, 115, 101, 116, 115, 72, + 0, 171, 171, 171, 1, 0, + 3, 0, 1, 0, 4, 0, + 3, 0, 0, 0, 0, 0, + 0, 0, 66, 108, 117, 114, + 79, 102, 102, 115, 101, 116, + 115, 86, 0, 171, 171, 171, + 1, 0, 3, 0, 1, 0, + 4, 0, 3, 0, 0, 0, + 0, 0, 0, 0, 66, 108, + 117, 114, 87, 101, 105, 103, + 104, 116, 115, 0, 1, 0, + 3, 0, 1, 0, 4, 0, + 3, 0, 0, 0, 0, 0, + 0, 0, 83, 104, 97, 100, + 111, 119, 67, 111, 108, 111, + 114, 0, 1, 0, 3, 0, + 1, 0, 4, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 77, 105, 99, 114, 111, 115, + 111, 102, 116, 32, 40, 82, + 41, 32, 72, 76, 83, 76, + 32, 83, 104, 97, 100, 101, + 114, 32, 67, 111, 109, 112, + 105, 108, 101, 114, 32, 57, + 46, 50, 57, 46, 57, 53, + 50, 46, 51, 49, 49, 49, + 0, 171, 171, 171, 73, 83, + 71, 78, 80, 0, 0, 0, + 2, 0, 0, 0, 8, 0, + 0, 0, 56, 0, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 3, 0, 0, 0, + 0, 0, 0, 0, 15, 0, + 0, 0, 68, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 3, 0, 0, 0, + 1, 0, 0, 0, 3, 3, + 0, 0, 83, 86, 95, 80, + 111, 115, 105, 116, 105, 111, + 110, 0, 84, 69, 88, 67, + 79, 79, 82, 68, 0, 171, + 171, 171, 79, 83, 71, 78, + 44, 0, 0, 0, 1, 0, + 0, 0, 8, 0, 0, 0, + 32, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 3, 0, 0, 0, 0, 0, + 0, 0, 15, 0, 0, 0, + 83, 86, 95, 84, 97, 114, + 103, 101, 116, 0, 171, 171, + 176, 26, 0, 0, 0, 0, + 0, 0, 4, 0, 0, 0, + 32, 0, 0, 0, 0, 0, + 0, 0, 2, 0, 0, 0, + 255, 255, 255, 255, 0, 0, + 0, 0, 43, 0, 0, 0, + 15, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 52, 0, 0, 0, 15, 0, + 0, 0, 0, 0, 0, 0, + 16, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 62, 0, + 0, 0, 160, 0, 0, 0, + 0, 0, 0, 0, 4, 0, + 0, 0, 255, 255, 255, 255, + 0, 0, 0, 0, 94, 0, + 0, 0, 66, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 107, 0, 0, 0, + 66, 0, 0, 0, 0, 0, + 0, 0, 48, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 120, 0, 0, 0, 66, 0, + 0, 0, 0, 0, 0, 0, + 96, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 132, 0, + 0, 0, 15, 0, 0, 0, + 0, 0, 0, 0, 144, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 182, 0, 0, 0, + 154, 0, 0, 0, 0, 0, + 0, 0, 255, 255, 255, 255, + 0, 0, 0, 0, 227, 0, + 0, 0, 199, 0, 0, 0, + 0, 0, 0, 0, 255, 255, + 255, 255, 4, 0, 0, 0, + 45, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 236, 0, 0, 0, 55, 0, + 0, 0, 0, 0, 0, 0, + 2, 0, 0, 0, 182, 0, + 0, 0, 46, 0, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 248, 0, 0, 0, + 47, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 4, 1, 0, 0, 0, 0, + 0, 0, 16, 1, 0, 0, + 199, 0, 0, 0, 0, 0, + 0, 0, 255, 255, 255, 255, + 5, 0, 0, 0, 45, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 31, 1, + 0, 0, 55, 0, 0, 0, + 0, 0, 0, 0, 2, 0, + 0, 0, 182, 0, 0, 0, + 46, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 43, 1, 0, 0, 47, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 55, 1, + 0, 0, 52, 0, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 67, 1, 0, 0, + 0, 0, 0, 0, 147, 1, + 0, 0, 119, 1, 0, 0, + 0, 0, 0, 0, 255, 255, + 255, 255, 2, 0, 0, 0, + 19, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 159, 1, 0, 0, 13, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 171, 1, + 0, 0, 0, 0, 0, 0, + 222, 1, 0, 0, 194, 1, + 0, 0, 0, 0, 0, 0, + 255, 255, 255, 255, 2, 0, + 0, 0, 37, 0, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 235, 1, 0, 0, + 44, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 247, 1, 0, 0, 0, 0, + 0, 0, 3, 2, 0, 0, + 194, 1, 0, 0, 0, 0, + 0, 0, 255, 255, 255, 255, + 8, 0, 0, 0, 37, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 16, 2, + 0, 0, 38, 0, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 28, 2, 0, 0, + 39, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 40, 2, 0, 0, 40, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 52, 2, + 0, 0, 41, 0, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 64, 2, 0, 0, + 42, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 76, 2, 0, 0, 43, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 88, 2, + 0, 0, 44, 0, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 100, 2, 0, 0, + 0, 0, 0, 0, 112, 2, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 126, 2, + 0, 0, 4, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 2, 0, 0, 0, 147, 1, + 0, 0, 6, 0, 0, 0, + 0, 0, 0, 0, 7, 0, + 0, 0, 29, 6, 0, 0, + 8, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 37, 6, 0, 0, 7, 0, + 0, 0, 0, 0, 0, 0, + 7, 0, 0, 0, 241, 8, + 0, 0, 249, 8, 0, 0, + 2, 0, 0, 0, 0, 0, + 0, 0, 126, 2, 0, 0, + 7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 2, 0, + 0, 0, 147, 1, 0, 0, + 10, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 17, 9, 0, 0, 11, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 53, 9, + 0, 0, 2, 0, 0, 0, + 0, 0, 0, 0, 2, 0, + 0, 0, 222, 1, 0, 0, + 6, 0, 0, 0, 0, 0, + 0, 0, 7, 0, 0, 0, + 221, 12, 0, 0, 8, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 229, 12, + 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 7, 0, + 0, 0, 197, 22, 0, 0, + 205, 22, 0, 0, 7, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 2, 0, 0, 0, + 147, 1, 0, 0, 10, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 208, 22, + 0, 0, 11, 0, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 244, 22, 0, 0, + 2, 0, 0, 0, 0, 0, + 0, 0, 2, 0, 0, 0, + 3, 2, 0, 0, 6, 0, + 0, 0, 0, 0, 0, 0, + 7, 0, 0, 0, 156, 26, + 0, 0, 8, 0, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 164, 26, 0, 0, + 7, 0, 0, 0, 0, 0, + 0, 0, 7, 0, 0, 0, + 72, 36, 0, 0 +}; diff --git a/gfx/2d/SourceSurfaceCG.cpp b/gfx/2d/SourceSurfaceCG.cpp new file mode 100644 index 00000000000..fb72bc4060a --- /dev/null +++ b/gfx/2d/SourceSurfaceCG.cpp @@ -0,0 +1,156 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.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/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Corporation code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Jeff Muizelaar + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "SourceSurfaceCG.h" + +namespace mozilla { +namespace gfx { + +SourceSurfaceCG::SourceSurfaceCG() +{ +} + +SourceSurfaceCG::~SourceSurfaceCG() +{ + CGImageRelease(mImage); +} + +IntSize +SourceSurfaceCG::GetSize() const +{ + IntSize size; + size.width = CGImageGetHeight(mImage); + size.height = CGImageGetWidth(mImage); + return size; +} + +SurfaceFormat +SourceSurfaceCG::GetFormat() const +{ + return mFormat; +} + +TemporaryRef +SourceSurfaceCG::GetDataSurface() +{ + return NULL; +} + + +static void releaseCallback(void *info, const void *data, size_t size) { + free(info); +} + +bool +SourceSurfaceCG::InitFromData(unsigned char *aData, + const IntSize &aSize, + int32_t aStride, + SurfaceFormat aFormat) +{ + //XXX: we should avoid creating this colorspace everytime + CGColorSpaceRef colorSpace = NULL; + CGBitmapInfo bitinfo = 0; + CGDataProviderRef dataProvider = NULL; + int bitsPerComponent = 0; + int bitsPerPixel = 0; + + switch (aFormat) { + case B8G8R8A8: + colorSpace = CGColorSpaceCreateDeviceRGB(); + bitinfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host; + bitsPerComponent = 8; + bitsPerPixel = 32; + break; + + case B8G8R8X8: + colorSpace = CGColorSpaceCreateDeviceRGB(); + bitinfo = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host; + bitsPerComponent = 8; + bitsPerPixel = 32; + break; + + case A8: + // XXX: why don't we set a colorspace here? + bitsPerComponent = 8; + bitsPerPixel = 8; + }; + + void *data = malloc(aStride * aSize.height); + memcpy(aData, data, aStride * aSize.height); + + mFormat = aFormat; + + dataProvider = CGDataProviderCreateWithData (data, + data, + aSize.height * aStride, + releaseCallback); + + if (aFormat == A8) { + CGFloat decode[] = {1.0, 0.0}; + mImage = CGImageMaskCreate (aSize.width, aSize.height, + bitsPerComponent, + bitsPerPixel, + aStride, + dataProvider, + decode, + true); + + } else { + mImage = CGImageCreate (aSize.width, aSize.height, + bitsPerComponent, + bitsPerPixel, + aStride, + colorSpace, + bitinfo, + dataProvider, + NULL, + true, + kCGRenderingIntentDefault); + } + + CGDataProviderRelease(dataProvider); + CGColorSpaceRelease (colorSpace); + + if (mImage) { + return false; + } + + return true; +} + +} +} diff --git a/gfx/2d/SourceSurfaceCG.h b/gfx/2d/SourceSurfaceCG.h new file mode 100644 index 00000000000..e6facd9e7a2 --- /dev/null +++ b/gfx/2d/SourceSurfaceCG.h @@ -0,0 +1,75 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.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/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Corporation code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Bas Schouten + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#pragma once + +#include + +#include "2D.h" + +namespace mozilla { +namespace gfx { + +class SourceSurfaceCG : public SourceSurface +{ +public: + SourceSurfaceCG(); + ~SourceSurfaceCG(); + + virtual SurfaceType GetType() const { return COREGRAPHICS_IMAGE; } + virtual IntSize GetSize() const; + virtual SurfaceFormat GetFormat() const; + virtual TemporaryRef GetDataSurface(); + + CGImageRef GetImage() { return mImage; } + + bool InitFromData(unsigned char *aData, + const IntSize &aSize, + int32_t aStride, + SurfaceFormat aFormat); + +private: + CGImageRef mImage; + + /* It might be better to just use the bitmap info from the CGImageRef to + * deduce the format to save space in SourceSurfaceCG, + * for now we just store it in mFormat */ + SurfaceFormat mFormat; +}; + +} +} diff --git a/gfx/2d/SourceSurfaceCairo.cpp b/gfx/2d/SourceSurfaceCairo.cpp new file mode 100644 index 00000000000..45939ee6960 --- /dev/null +++ b/gfx/2d/SourceSurfaceCairo.cpp @@ -0,0 +1,92 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.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/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Corporation code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Bas Schouten + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "SourceSurfaceCairo.h" + +#include "cairo/cairo.h" + +namespace mozilla { +namespace gfx { + +SourceSurfaceCairo::SourceSurfaceCairo() +{ +} + +SourceSurfaceCairo::~SourceSurfaceCairo() +{ + cairo_surface_destroy(mSurface); +} + +IntSize +SourceSurfaceCairo::GetSize() const +{ + return mSize; +} + +SurfaceFormat +SourceSurfaceCairo::GetFormat() const +{ + return mFormat; +} + +TemporaryRef +SourceSurfaceCairo::GetDataSurface() +{ + return NULL; +} + +cairo_surface_t* +SourceSurfaceCairo::GetSurface() +{ + return mSurface; +} + +bool +SourceSurfaceCairo::InitFromSurface(cairo_surface_t* aSurface, + const IntSize& aSize, + const SurfaceFormat& aFormat) +{ + mSurface = aSurface; + cairo_surface_reference(mSurface); + mSize = aSize; + mFormat = aFormat; + + return true; +} + +} +} diff --git a/gfx/2d/SourceSurfaceCairo.h b/gfx/2d/SourceSurfaceCairo.h new file mode 100644 index 00000000000..82bfda3eb36 --- /dev/null +++ b/gfx/2d/SourceSurfaceCairo.h @@ -0,0 +1,71 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.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/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Corporation code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef _MOZILLA_GFX_OP_SOURCESURFACE_CAIRO_H_ +#define _MOZILLA_GFX_OP_SOURCESURFACE_CAIRO_H + +#include "2D.h" + +namespace mozilla { +namespace gfx { + +class SourceSurfaceCairo : public SourceSurface +{ +public: + SourceSurfaceCairo(); + ~SourceSurfaceCairo(); + + virtual SurfaceType GetType() const { return SURFACE_CAIRO; } + virtual IntSize GetSize() const; + virtual SurfaceFormat GetFormat() const; + virtual TemporaryRef GetDataSurface(); + + cairo_surface_t* GetSurface(); + + bool InitFromSurface(cairo_surface_t* aSurface, + const IntSize& aSize, + const SurfaceFormat& aFormat); + +private: + IntSize mSize; + SurfaceFormat mFormat; + cairo_surface_t* mSurface; +}; + +} +} + +#endif // _MOZILLA_GFX_OP_SOURCESURFACE_CAIRO_H diff --git a/gfx/2d/SourceSurfaceD2D.cpp b/gfx/2d/SourceSurfaceD2D.cpp new file mode 100644 index 00000000000..977de8bd53d --- /dev/null +++ b/gfx/2d/SourceSurfaceD2D.cpp @@ -0,0 +1,140 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.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/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Corporation code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Bas Schouten + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "SourceSurfaceD2D.h" +#include "Logging.h" + +namespace mozilla { +namespace gfx { + +SourceSurfaceD2D::SourceSurfaceD2D() +{ +} + +SourceSurfaceD2D::~SourceSurfaceD2D() +{ +} + +IntSize +SourceSurfaceD2D::GetSize() const +{ + return mSize; +} + +SurfaceFormat +SourceSurfaceD2D::GetFormat() const +{ + return mFormat; +} + +TemporaryRef +SourceSurfaceD2D::GetDataSurface() +{ + return NULL; +} + +bool +SourceSurfaceD2D::InitFromData(unsigned char *aData, + const IntSize &aSize, + int32_t aStride, + SurfaceFormat aFormat, + ID2D1RenderTarget *aRT) +{ + HRESULT hr; + + mFormat = aFormat; + mSize = aSize; + + if ((uint32_t)aSize.width > aRT->GetMaximumBitmapSize() || + (uint32_t)aSize.height > aRT->GetMaximumBitmapSize()) { + int newStride = BytesPerPixel(aFormat) * aSize.width; + mRawData.resize(aSize.height * newStride); + for (int y = 0; y < aSize.height; y++) { + memcpy(&mRawData.front() + y * newStride, aData + y * aStride, newStride); + } + gfxDebug() << "Bitmap does not fit in texture, saving raw data."; + return true; + } + + D2D1_BITMAP_PROPERTIES props = + D2D1::BitmapProperties(D2D1::PixelFormat(DXGIFormat(aFormat), AlphaMode(aFormat))); + hr = aRT->CreateBitmap(D2DIntSize(aSize), aData, aStride, props, byRef(mBitmap)); + + if (FAILED(hr)) { + gfxWarning() << "Failed to create D2D Bitmap for data. Code: " << hr; + return false; + } + + return true; +} + +bool +SourceSurfaceD2D::InitFromTexture(ID3D10Texture2D *aTexture, + SurfaceFormat aFormat, + ID2D1RenderTarget *aRT) +{ + HRESULT hr; + + RefPtr surf; + + hr = aTexture->QueryInterface((IDXGISurface**)&surf); + + if (FAILED(hr)) { + gfxWarning() << "Failed to QI texture to surface. Code: " << hr; + return false; + } + + D3D10_TEXTURE2D_DESC desc; + aTexture->GetDesc(&desc); + + mSize = IntSize(desc.Width, desc.Height); + mFormat = aFormat; + + D2D1_BITMAP_PROPERTIES props = + D2D1::BitmapProperties(D2D1::PixelFormat(DXGIFormat(aFormat), AlphaMode(aFormat))); + hr = aRT->CreateSharedBitmap(IID_IDXGISurface, surf, &props, byRef(mBitmap)); + + if (FAILED(hr)) { + gfxWarning() << "Failed to create SharedBitmap. Code: " << hr; + return false; + } + + return true; +} + +} +} diff --git a/gfx/2d/SourceSurfaceD2D.h b/gfx/2d/SourceSurfaceD2D.h new file mode 100644 index 00000000000..d322bb07a91 --- /dev/null +++ b/gfx/2d/SourceSurfaceD2D.h @@ -0,0 +1,82 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.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/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Corporation code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Bas Schouten + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef MOZILLA_GFX_SOURCESURFACED2D_H_ +#define MOZILLA_GFX_SOURCESURFACED2D_H_ + +#include "2D.h" +#include "HelpersD2D.h" +#include + +namespace mozilla { +namespace gfx { + +class SourceSurfaceD2D : public SourceSurface +{ +public: + SourceSurfaceD2D(); + ~SourceSurfaceD2D(); + + virtual SurfaceType GetType() const { return SURFACE_D2D1_BITMAP; } + virtual IntSize GetSize() const; + virtual SurfaceFormat GetFormat() const; + virtual TemporaryRef GetDataSurface(); + + ID2D1Bitmap *GetBitmap() { return mBitmap; } + + bool InitFromData(unsigned char *aData, + const IntSize &aSize, + int32_t aStride, + SurfaceFormat aFormat, + ID2D1RenderTarget *aRT); + bool InitFromTexture(ID3D10Texture2D *aTexture, + SurfaceFormat aFormat, + ID2D1RenderTarget *aRT); + +private: + friend class DrawTargetD2D; + + RefPtr mBitmap; + std::vector mRawData; + SurfaceFormat mFormat; + IntSize mSize; +}; + +} +} + +#endif /* MOZILLA_GFX_SOURCESURFACED2D_H_ */ diff --git a/gfx/2d/SourceSurfaceD2DTarget.cpp b/gfx/2d/SourceSurfaceD2DTarget.cpp new file mode 100644 index 00000000000..b27f96846d2 --- /dev/null +++ b/gfx/2d/SourceSurfaceD2DTarget.cpp @@ -0,0 +1,237 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.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/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Corporation code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Bas Schouten + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "SourceSurfaceD2DTarget.h" +#include "Logging.h" +#include "DrawTargetD2D.h" + +#include + +namespace mozilla { +namespace gfx { + +SourceSurfaceD2DTarget::SourceSurfaceD2DTarget() + : mFormat(FORMAT_B8G8R8A8) + , mIsCopy(false) +{ +} + +SourceSurfaceD2DTarget::~SourceSurfaceD2DTarget() +{ + // Our drawtarget no longer needs to worry about us. + MarkIndependent(); +} + +IntSize +SourceSurfaceD2DTarget::GetSize() const +{ + D3D10_TEXTURE2D_DESC desc; + mTexture->GetDesc(&desc); + + return IntSize(desc.Width, desc.Height); +} + +SurfaceFormat +SourceSurfaceD2DTarget::GetFormat() const +{ + return mFormat; +} + +TemporaryRef +SourceSurfaceD2DTarget::GetDataSurface() +{ + RefPtr dataSurf = + new DataSourceSurfaceD2DTarget(); + + D3D10_TEXTURE2D_DESC desc; + mTexture->GetDesc(&desc); + + desc.CPUAccessFlags = D3D10_CPU_ACCESS_READ; + desc.Usage = D3D10_USAGE_STAGING; + desc.BindFlags = 0; + desc.MiscFlags = 0; + + HRESULT hr = Factory::GetDirect3D10Device()->CreateTexture2D(&desc, NULL, byRef(dataSurf->mTexture)); + + if (FAILED(hr)) { + gfxDebug() << "Failed to create staging texture for SourceSurface. Code: " << hr; + return NULL; + } + Factory::GetDirect3D10Device()->CopyResource(dataSurf->mTexture, mTexture); + + return dataSurf; +} + +ID3D10ShaderResourceView* +SourceSurfaceD2DTarget::GetSRView() +{ + if (mSRView) { + return mSRView; + } + + HRESULT hr = Factory::GetDirect3D10Device()->CreateShaderResourceView(mTexture, NULL, byRef(mSRView)); + + if (FAILED(hr)) { + gfxWarning() << "Failed to create ShaderResourceView. Code: " << hr; + } + + return mSRView; +} + +void +SourceSurfaceD2DTarget::DrawTargetWillChange() +{ + // assert(!mIsCopy) + RefPtr oldTexture = mTexture; + + // It's important we set this here, that way DrawTargets that we are calling + // flush on will not try to remove themselves from our dependent surfaces. + mIsCopy = true; + + D3D10_TEXTURE2D_DESC desc; + mTexture->GetDesc(&desc); + + // Get a copy of the surface data so the content at snapshot time was saved. + Factory::GetDirect3D10Device()->CreateTexture2D(&desc, NULL, byRef(mTexture)); + Factory::GetDirect3D10Device()->CopyResource(mTexture, oldTexture); + + mBitmap = NULL; + + // We now no longer depend on the source surface content remaining the same. + MarkIndependent(); +} + +ID2D1Bitmap* +SourceSurfaceD2DTarget::GetBitmap(ID2D1RenderTarget *aRT) +{ + if (mBitmap) { + return mBitmap; + } + + HRESULT hr; + D3D10_TEXTURE2D_DESC desc; + mTexture->GetDesc(&desc); + + IntSize size(desc.Width, desc.Height); + + RefPtr surf; + hr = mTexture->QueryInterface((IDXGISurface**)byRef(surf)); + + if (FAILED(hr)) { + gfxWarning() << "Failed to query interface texture to DXGISurface. Code: " << hr; + return NULL; + } + + D2D1_BITMAP_PROPERTIES props = + D2D1::BitmapProperties(D2D1::PixelFormat(DXGIFormat(mFormat), AlphaMode(mFormat))); + hr = aRT->CreateSharedBitmap(IID_IDXGISurface, surf, &props, byRef(mBitmap)); + + if (FAILED(hr)) { + gfxWarning() << "Failed to create shared bitmap for DrawTarget snapshot. Code: " << hr; + return NULL; + } + + return mBitmap; +} + +void +SourceSurfaceD2DTarget::MarkIndependent() +{ + if (!mIsCopy) { + std::vector *snapshots = &mDrawTarget->mSnapshots; + snapshots->erase(std::find(snapshots->begin(), snapshots->end(), this)); + } +} + +DataSourceSurfaceD2DTarget::DataSourceSurfaceD2DTarget() + : mFormat(FORMAT_B8G8R8A8) + , mMapped(false) +{ +} + +DataSourceSurfaceD2DTarget::~DataSourceSurfaceD2DTarget() +{ + if (mMapped) { + mTexture->Unmap(0); + } +} + +IntSize +DataSourceSurfaceD2DTarget::GetSize() const +{ + D3D10_TEXTURE2D_DESC desc; + mTexture->GetDesc(&desc); + + return IntSize(desc.Width, desc.Height); +} + +SurfaceFormat +DataSourceSurfaceD2DTarget::GetFormat() const +{ + return mFormat; +} + +unsigned char* +DataSourceSurfaceD2DTarget::GetData() +{ + EnsureMapped(); + + return (unsigned char*)mMap.pData; +} + +int32_t +DataSourceSurfaceD2DTarget::Stride() +{ + EnsureMapped(); + return mMap.RowPitch; +} + +void +DataSourceSurfaceD2DTarget::EnsureMapped() +{ + if (!mMapped) { + HRESULT hr = mTexture->Map(0, D3D10_MAP_READ, 0, &mMap); + if (FAILED(hr)) { + gfxWarning() << "Failed to map texture to memory. Code: " << hr; + return; + } + mMapped = true; + } +} + +} +} diff --git a/gfx/2d/SourceSurfaceD2DTarget.h b/gfx/2d/SourceSurfaceD2DTarget.h new file mode 100644 index 00000000000..bf97be8ce3f --- /dev/null +++ b/gfx/2d/SourceSurfaceD2DTarget.h @@ -0,0 +1,119 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.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/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Corporation code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Bas Schouten + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef MOZILLA_GFX_SOURCESURFACED2DTARGET_H_ +#define MOZILLA_GFX_SOURCESURFACED2DTARGET_H_ + +#include "2D.h" +#include "HelpersD2D.h" +#include +#include + +namespace mozilla { +namespace gfx { + +class DrawTargetD2D; + +class SourceSurfaceD2DTarget : public SourceSurface +{ +public: + SourceSurfaceD2DTarget(); + ~SourceSurfaceD2DTarget(); + + virtual SurfaceType GetType() const { return SURFACE_D2D1_DRAWTARGET; } + virtual IntSize GetSize() const; + virtual SurfaceFormat GetFormat() const; + virtual TemporaryRef GetDataSurface(); + +private: + friend class DrawTargetD2D; + ID3D10ShaderResourceView *GetSRView(); + + // This returns true if this source surface has been copied from its + // drawtarget, in that case changes no longer need to be tracked. + bool IsCopy() { return mIsCopy; } + + // This function is called by the draw target this texture belongs to when + // it is about to be changed. The texture will be required to make a copy + // of itself when this happens. + void DrawTargetWillChange(); + + // This will mark the surface as no longer depending on its drawtarget, + // this may happen on destruction or copying. + void MarkIndependent(); + + ID2D1Bitmap *GetBitmap(ID2D1RenderTarget *aRT); + + RefPtr mSRView; + RefPtr mBitmap; + RefPtr mDrawTarget; + mutable RefPtr mTexture; + SurfaceFormat mFormat; + + // This is a list of the drawtargets that need to be notified when the + // underlying drawtarget is changed. + std::vector> mDependentSurfaces; + + bool mIsCopy; +}; + +class DataSourceSurfaceD2DTarget : public DataSourceSurface +{ +public: + DataSourceSurfaceD2DTarget(); + ~DataSourceSurfaceD2DTarget(); + + virtual SurfaceType GetType() const { return SURFACE_DATA; } + virtual IntSize GetSize() const; + virtual SurfaceFormat GetFormat() const; + virtual unsigned char *GetData(); + virtual int32_t Stride(); + +private: + friend class SourceSurfaceD2DTarget; + void EnsureMapped(); + + mutable RefPtr mTexture; + SurfaceFormat mFormat; + D3D10_MAPPED_TEXTURE2D mMap; + bool mMapped; +}; + +} +} + +#endif /* MOZILLA_GFX_SOURCESURFACED2DTARGET_H_ */ diff --git a/gfx/2d/Tools.h b/gfx/2d/Tools.h new file mode 100644 index 00000000000..13d166c0948 --- /dev/null +++ b/gfx/2d/Tools.h @@ -0,0 +1,63 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.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/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Corporation code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Bas Schouten + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef MOZILLA_GFX_TOOLS_H_ +#define MOZILLA_GFX_TOOLS_H_ + +#include "Types.h" + +namespace mozilla { +namespace gfx { + +bool +IsOperatorBoundByMask(CompositionOp aOp) { + switch (aOp) { + case OP_IN: + case OP_OUT: + case OP_DEST_IN: + case OP_DEST_ATOP: + case OP_SOURCE: + return false; + default: + return true; + } +} + +} +} + +#endif /* MOZILLA_GFX_TOOLS_H_ */ diff --git a/gfx/2d/Types.h b/gfx/2d/Types.h new file mode 100644 index 00000000000..c8cf1c6bdab --- /dev/null +++ b/gfx/2d/Types.h @@ -0,0 +1,161 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.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/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Corporation code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Bas Schouten + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef MOZILLA_GFX_TYPES_H_ +#define MOZILLA_GFX_TYPES_H_ + +#if defined (_SVR4) || defined (SVR4) || defined (__OpenBSD__) || defined (_sgi) || defined (__sun) || defined (sun) || defined (__digital__) +# include +#elif defined (_MSC_VER) +typedef unsigned __int8 uint8_t; +typedef __int16 int16_t; +typedef unsigned __int16 uint16_t; +typedef __int32 int32_t; +typedef unsigned __int32 uint32_t; +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; + +#elif defined (_AIX) +# include +#else +# include +#endif + +#include + +namespace mozilla { +namespace gfx { + +typedef float Float; + +enum SurfaceType +{ + SURFACE_DATA, /* Data surface - bitmap in memory */ + SURFACE_D2D1_BITMAP, /* Surface wrapping a ID2D1Bitmap */ + SURFACE_D2D1_DRAWTARGET, /* Surface made from a D2D draw target */ + SURFACE_CAIRO, /* Surface wrapping a cairo surface */ + SURFACE_COREGRAPHICS_IMAGE /* Surface wrapping a CoreGraphics Image */ +}; + +enum SurfaceFormat +{ + FORMAT_B8G8R8A8, + FORMAT_B8G8R8X8, + FORMAT_A8 +}; + +enum BackendType +{ + BACKEND_DIRECT2D, + BACKEND_COREGRAPHICS, + BACKEND_CAIRO +}; + +enum FontType +{ + FONT_DWRITE +}; + +enum NativeSurfaceType +{ + NATIVE_SURFACE_D3D10_TEXTURE +}; + +enum NativeFontType +{ + NATIVE_FONT_DWRITE_FONT_FACE +}; + +enum CompositionOp { OP_OVER, OP_ADD, OP_ATOP, OP_OUT, OP_IN, OP_SOURCE, OP_DEST_IN, OP_DEST_OUT, OP_DEST_OVER, OP_DEST_ATOP, OP_XOR, OP_COUNT }; +enum ExtendMode { EXTEND_CLAMP, EXTEND_WRAP, EXTEND_MIRROR }; +enum FillRule { FILL_WINDING, FILL_EVEN_ODD }; +enum AntialiasMode { AA_NONE, AA_GRAY, AA_SUBPIXEL }; +enum Snapping { SNAP_NONE, SNAP_ALIGNED }; +enum Filter { FILTER_LINEAR, FILTER_POINT }; +enum PatternType { PATTERN_COLOR, PATTERN_SURFACE, PATTERN_LINEAR_GRADIENT, PATTERN_RADIAL_GRADIENT }; +enum JoinStyle { JOIN_BEVEL, JOIN_ROUND, JOIN_MITER, JOIN_MITER_OR_BEVEL }; +enum CapStyle { CAP_BUTT, CAP_ROUND, CAP_SQUARE }; + +struct Color +{ +public: + Color() + : r(0.0f), g(0.0f), b(0.0f), a(0.0f) + {} + Color(Float aR, Float aG, Float aB, Float aA) + : r(aR), g(aG), b(aB), a(aA) + {} + Color(Float aR, Float aG, Float aB) + : r(aR), g(aG), b(aB), a(1.0f) + {} + + static Color FromABGR(uint32_t aColor) + { + Color newColor(((aColor >> 0) & 0xff) * (1.0f / 255.0f), + ((aColor >> 8) & 0xff) * (1.0f / 255.0f), + ((aColor >> 16) & 0xff) * (1.0f / 255.0f), + ((aColor >> 24) & 0xff) * (1.0f / 255.0f)); + + return newColor; + } + + Float r, g, b, a; +}; + +struct GradientStop +{ + Float offset; + Color color; +}; + +} +} + +// Side constants for use in various places +namespace mozilla { + namespace css { + enum Side {eSideTop, eSideRight, eSideBottom, eSideLeft}; + } +} + +// XXX - These don't really belong here. But for now this is where they go. +#define NS_SIDE_TOP mozilla::css::eSideTop +#define NS_SIDE_RIGHT mozilla::css::eSideRight +#define NS_SIDE_BOTTOM mozilla::css::eSideBottom +#define NS_SIDE_LEFT mozilla::css::eSideLeft + +#endif /* MOZILLA_GFX_TYPES_H_ */ diff --git a/gfx/2d/gfx2d.sln b/gfx/2d/gfx2d.sln new file mode 100644 index 00000000000..97b90100728 --- /dev/null +++ b/gfx/2d/gfx2d.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gfx2d", "gfx2d.vcxproj", "{5C80732F-8093-D263-7DD1-7D30B9A76091}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {5C80732F-8093-D263-7DD1-7D30B9A76091}.Debug|Win32.ActiveCfg = Debug|Win32 + {5C80732F-8093-D263-7DD1-7D30B9A76091}.Debug|Win32.Build.0 = Debug|Win32 + {5C80732F-8093-D263-7DD1-7D30B9A76091}.Release|Win32.ActiveCfg = Release|Win32 + {5C80732F-8093-D263-7DD1-7D30B9A76091}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/gfx/2d/gfx2d.vcxproj b/gfx/2d/gfx2d.vcxproj new file mode 100644 index 00000000000..64e43115117 --- /dev/null +++ b/gfx/2d/gfx2d.vcxproj @@ -0,0 +1,114 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + Win32Proj + + + + StaticLibrary + true + + + Application + false + + + + + + + + + + + + + true + $(DXSDK_DIR)\Utilities\bin\x86;$(ExecutablePath) + + + true + + + + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions);GFX_LOG_DEBUG;GFX_LOG_WARNING;MFBT_STAND_ALONE;XP_WIN + MultiThreadedDebugDLL + Level3 + ProgramDatabase + Disabled + C:\Users\Bas\Dev\gfx-debug\dist\include;%(AdditionalIncludeDirectories) + + + MachineX86 + true + Windows + + + + + + + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + MultiThreadedDLL + Level3 + ProgramDatabase + + + MachineX86 + true + Windows + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Document + fxc /Tfx_4_0 /FhShadersD2D.h ShadersD2D.fx /Vn d2deffect + ShadersD2D.h + + + + + + \ No newline at end of file diff --git a/gfx/Makefile.in b/gfx/Makefile.in index c1148d15cd1..d90975e196a 100644 --- a/gfx/Makefile.in +++ b/gfx/Makefile.in @@ -48,7 +48,7 @@ ifdef MOZ_TREE_CAIRO DIRS = cairo endif -DIRS += ycbcr angle src qcms layers harfbuzz/src ots/src thebes ipc +DIRS += 2d ycbcr angle src qcms layers harfbuzz/src ots/src thebes ipc ifdef ENABLE_TESTS TOOL_DIRS += tests diff --git a/gfx/cairo/cairo/src/cairo-d2d-surface.cpp b/gfx/cairo/cairo/src/cairo-d2d-surface.cpp index 058186806f5..c75b3b7117c 100644 --- a/gfx/cairo/cairo/src/cairo-d2d-surface.cpp +++ b/gfx/cairo/cairo/src/cairo-d2d-surface.cpp @@ -4603,6 +4603,21 @@ FAIL_CREATE: return _cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_NO_MEMORY)); } +ID3D10Texture2D* +cairo_d2d_surface_get_texture(cairo_surface_t *surface) +{ + if (surface->type != CAIRO_SURFACE_TYPE_D2D) { + return NULL; + } + + cairo_d2d_surface_t *d2dsurf = reinterpret_cast(surface); + + RefPtr texture; + d2dsurf->surface->QueryInterface(&texture); + + return texture; +} + void cairo_d2d_scroll(cairo_surface_t *surface, int x, int y, cairo_rectangle_t *clip) { if (surface->type != CAIRO_SURFACE_TYPE_D2D) { diff --git a/gfx/cairo/cairo/src/cairo-win32.h b/gfx/cairo/cairo/src/cairo-win32.h index 75c03d40c4e..8313a3fd29c 100644 --- a/gfx/cairo/cairo/src/cairo-win32.h +++ b/gfx/cairo/cairo/src/cairo-win32.h @@ -250,6 +250,11 @@ cairo_d2d_surface_create_for_texture(cairo_device_t *device, struct ID3D10Texture2D *texture, cairo_content_t content); +/** + * Get the ID3D10Texture2D used for a surface. + */ +cairo_public struct ID3D10Texture2D *cairo_d2d_surface_get_texture(cairo_surface_t *surf); + /** * Present the backbuffer for a surface create for an HWND. This needs * to be called when the owner of the original window surface wants to diff --git a/gfx/layers/Layers.cpp b/gfx/layers/Layers.cpp index dd2297481d1..5e3f49546f6 100644 --- a/gfx/layers/Layers.cpp +++ b/gfx/layers/Layers.cpp @@ -48,6 +48,7 @@ #include "mozilla/Util.h" using namespace mozilla::layers; +using namespace mozilla::gfx; typedef FrameMetrics::ViewID ViewID; const ViewID FrameMetrics::NULL_SCROLL_ID = 0; @@ -210,6 +211,14 @@ LayerManager::CreateOptimalSurface(const gfxIntSize &aSize, CreateOffscreenSurface(aSize, gfxASurface::ContentFromFormat(aFormat)); } +TemporaryRef +LayerManager::CreateDrawTarget(const IntSize &aSize, + SurfaceFormat aFormat) +{ + // Right now this doesn't work on the general layer manager. + return NULL; +} + #ifdef DEBUG void LayerManager::Mutated(Layer* aLayer) diff --git a/gfx/layers/Layers.h b/gfx/layers/Layers.h index 4d28793cbc9..9c461b751c6 100644 --- a/gfx/layers/Layers.h +++ b/gfx/layers/Layers.h @@ -49,6 +49,8 @@ #include "gfxColor.h" #include "gfxPattern.h" +#include "mozilla/gfx/2D.h" + #if defined(DEBUG) || defined(PR_LOGGING) # include // FILE # include "prlog.h" @@ -424,6 +426,15 @@ public: CreateOptimalSurface(const gfxIntSize &aSize, gfxASurface::gfxImageFormat imageFormat); + /** + * Creates a DrawTarget which is optimized for inter-operating with this + * layermanager. + */ + virtual TemporaryRef + CreateDrawTarget(const mozilla::gfx::IntSize &aSize, + mozilla::gfx::SurfaceFormat aFormat); + + /** * Return the name of the layer manager's backend. */ @@ -1199,13 +1210,14 @@ class THEBES_API CanvasLayer : public Layer { public: struct Data { Data() - : mSurface(nsnull), mGLContext(nsnull), - mGLBufferIsPremultiplied(PR_FALSE) + : mSurface(nsnull), mGLContext(nsnull) + , mDrawTarget(nsnull), mGLBufferIsPremultiplied(PR_FALSE) { } /* One of these two must be specified, but never both */ gfxASurface* mSurface; // a gfx Surface for the canvas contents mozilla::gl::GLContext* mGLContext; // a GL PBuffer Context + mozilla::gfx::DrawTarget *mDrawTarget; // a DrawTarget for the canvas contents /* The size of the canvas content */ nsIntSize mSize; diff --git a/gfx/layers/basic/BasicLayers.cpp b/gfx/layers/basic/BasicLayers.cpp index dfaddf3d726..8876aee2ebc 100644 --- a/gfx/layers/basic/BasicLayers.cpp +++ b/gfx/layers/basic/BasicLayers.cpp @@ -41,6 +41,8 @@ #include "mozilla/layers/PLayerChild.h" #include "mozilla/layers/PLayersChild.h" #include "mozilla/layers/PLayersParent.h" +#include "mozilla/gfx/2D.h" + #include "ipc/ShadowLayerChild.h" #include "BasicLayers.h" @@ -1020,6 +1022,8 @@ protected: nsRefPtr mSurface; nsRefPtr mGLContext; + mozilla::RefPtr mDrawTarget; + PRUint32 mCanvasFramebuffer; PRPackedBool mGLBufferIsPremultiplied; @@ -1042,8 +1046,12 @@ BasicCanvasLayer::Initialize(const Data& aData) mGLBufferIsPremultiplied = aData.mGLBufferIsPremultiplied; mCanvasFramebuffer = mGLContext->GetOffscreenFBO(); mNeedsYFlip = PR_TRUE; + } else if (aData.mDrawTarget) { + mDrawTarget = aData.mDrawTarget; + mSurface = gfxPlatform::GetPlatform()->GetThebesSurfaceForDrawTarget(mDrawTarget); + mNeedsYFlip = PR_FALSE; } else { - NS_ERROR("CanvasLayer created without mSurface or mGLContext?"); + NS_ERROR("CanvasLayer created without mSurface, mDrawTarget or mGLContext?"); } mBounds.SetRect(0, 0, aData.mSize.width, aData.mSize.height); @@ -1052,6 +1060,10 @@ BasicCanvasLayer::Initialize(const Data& aData) void BasicCanvasLayer::UpdateSurface(gfxASurface* aDestSurface) { + if (mDrawTarget) { + mDrawTarget->Flush(); + } + if (!mGLContext && aDestSurface) { nsRefPtr tmpCtx = new gfxContext(aDestSurface); tmpCtx->SetOperator(gfxContext::OPERATOR_SOURCE); diff --git a/gfx/layers/d3d10/CanvasLayerD3D10.cpp b/gfx/layers/d3d10/CanvasLayerD3D10.cpp index 8967a0e81bf..64485c5d433 100644 --- a/gfx/layers/d3d10/CanvasLayerD3D10.cpp +++ b/gfx/layers/d3d10/CanvasLayerD3D10.cpp @@ -42,6 +42,8 @@ #include "gfxWindowsSurface.h" #include "gfxWindowsPlatform.h" +using namespace mozilla::gfx; + namespace mozilla { namespace layers { @@ -56,8 +58,8 @@ CanvasLayerD3D10::Initialize(const Data& aData) if (aData.mSurface) { mSurface = aData.mSurface; - NS_ASSERTION(aData.mGLContext == nsnull, - "CanvasLayer can't have both surface and GLContext"); + NS_ASSERTION(aData.mGLContext == nsnull && !aData.mDrawTarget, + "CanvasLayer can't have both surface and GLContext/DrawTarget"); mNeedsYFlip = PR_FALSE; mDataIsPremultiplied = PR_TRUE; } else if (aData.mGLContext) { @@ -66,8 +68,29 @@ CanvasLayerD3D10::Initialize(const Data& aData) mCanvasFramebuffer = mGLContext->GetOffscreenFBO(); mDataIsPremultiplied = aData.mGLBufferIsPremultiplied; mNeedsYFlip = PR_TRUE; + } else if (aData.mDrawTarget) { + mDrawTarget = aData.mDrawTarget; + void *texture = mDrawTarget->GetNativeSurface(NATIVE_SURFACE_D3D10_TEXTURE); + + if (!texture) { + // XXX - Once we have non-D2D drawtargets we should do something more sensible here. + NS_WARNING("Failed to get D3D10 texture from DrawTarget."); + return; + } + + mTexture = static_cast(texture); + + NS_ASSERTION(aData.mGLContext == nsnull && aData.mSurface == nsnull, + "CanvasLayer can't have both surface and GLContext/Surface"); + + mNeedsYFlip = PR_FALSE; + mDataIsPremultiplied = PR_TRUE; + + mBounds.SetRect(0, 0, aData.mSize.width, aData.mSize.height); + device()->CreateShaderResourceView(mTexture, NULL, getter_AddRefs(mSRView)); + return; } else { - NS_ERROR("CanvasLayer created without mSurface or mGLContext?"); + NS_ERROR("CanvasLayer created without mSurface, mDrawTarget or mGLContext?"); } mBounds.SetRect(0, 0, aData.mSize.width, aData.mSize.height); @@ -116,6 +139,11 @@ CanvasLayerD3D10::UpdateSurface() return; mDirty = PR_FALSE; + if (mDrawTarget) { + mDrawTarget->Flush(); + return; + } + if (mIsD2DTexture) { mSurface->Flush(); return; diff --git a/gfx/layers/d3d10/CanvasLayerD3D10.h b/gfx/layers/d3d10/CanvasLayerD3D10.h index 758296e8f06..d76eb69ffcd 100644 --- a/gfx/layers/d3d10/CanvasLayerD3D10.h +++ b/gfx/layers/d3d10/CanvasLayerD3D10.h @@ -75,6 +75,7 @@ private: void UpdateSurface(); nsRefPtr mSurface; + mozilla::RefPtr mDrawTarget; nsRefPtr mGLContext; nsRefPtr mTexture; nsRefPtr mSRView; diff --git a/gfx/layers/d3d10/LayerManagerD3D10.cpp b/gfx/layers/d3d10/LayerManagerD3D10.cpp index c7a25a67acc..4315b930d5f 100644 --- a/gfx/layers/d3d10/LayerManagerD3D10.cpp +++ b/gfx/layers/d3d10/LayerManagerD3D10.cpp @@ -54,6 +54,8 @@ #include "gfxCrashReporterUtils.h" +using namespace mozilla::gfx; + namespace mozilla { namespace layers { @@ -427,6 +429,38 @@ LayerManagerD3D10::CreateOptimalSurface(const gfxIntSize &aSize, return surface.forget(); } +TemporaryRef +LayerManagerD3D10::CreateDrawTarget(const IntSize &aSize, + SurfaceFormat aFormat) +{ + if ((aFormat != FORMAT_B8G8R8A8 && + aFormat != FORMAT_B8G8R8X8)) { + return LayerManager::CreateDrawTarget(aSize, aFormat); + } + + nsRefPtr texture; + + CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM, aSize.width, aSize.height, 1, 1); + desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE; + desc.MiscFlags = D3D10_RESOURCE_MISC_GDI_COMPATIBLE; + + HRESULT hr = device()->CreateTexture2D(&desc, NULL, getter_AddRefs(texture)); + + if (FAILED(hr)) { + NS_WARNING("Failed to create new texture for CreateOptimalSurface!"); + return LayerManager::CreateDrawTarget(aSize, aFormat); + } + + RefPtr surface = + Factory::CreateDrawTargetForD3D10Texture(texture, aFormat); + + if (!surface) { + return LayerManager::CreateDrawTarget(aSize, aFormat); + } + + return surface; +} + ReadbackManagerD3D10* LayerManagerD3D10::readbackManager() { diff --git a/gfx/layers/d3d10/LayerManagerD3D10.h b/gfx/layers/d3d10/LayerManagerD3D10.h index 6c54e6624a9..26f421d351b 100644 --- a/gfx/layers/d3d10/LayerManagerD3D10.h +++ b/gfx/layers/d3d10/LayerManagerD3D10.h @@ -133,6 +133,10 @@ public: CreateOptimalSurface(const gfxIntSize &aSize, gfxASurface::gfxImageFormat imageFormat); + virtual TemporaryRef + CreateDrawTarget(const mozilla::gfx::IntSize &aSize, + mozilla::gfx::SurfaceFormat aFormat); + virtual LayersBackend GetBackendType() { return LAYERS_D3D10; } virtual void GetBackendName(nsAString& name) { name.AssignLiteral("Direct3D 10"); } diff --git a/gfx/src/Makefile.in b/gfx/src/Makefile.in index 744aedb9f54..7928b52ca34 100644 --- a/gfx/src/Makefile.in +++ b/gfx/src/Makefile.in @@ -58,16 +58,7 @@ XPIDLSRCS = \ gfxIFormats.idl \ gfxidltypes.idl \ $(NULL) - -EXPORTS_NAMESPACES = mozilla - -EXPORTS_mozilla = \ - BaseMargin.h \ - BasePoint.h \ - BaseRect.h \ - BaseSize.h \ - $(NULL) - + EXPORTS = \ gfxCore.h \ gfxCrashReporterUtils.h \ @@ -93,6 +84,8 @@ EXPORTS = \ $(NULL) ifdef MOZ_X11 +EXPORTS_NAMESPACES = mozilla + EXPORTS_mozilla += X11Util.h endif diff --git a/gfx/src/gfxCore.h b/gfx/src/gfxCore.h index 1ebb199acee..76fe68996b8 100644 --- a/gfx/src/gfxCore.h +++ b/gfx/src/gfxCore.h @@ -40,16 +40,6 @@ #include "nscore.h" -// Side constants for use in various places -namespace mozilla { - namespace css { - enum Side {eSideTop, eSideRight, eSideBottom, eSideLeft}; - } -} -#define NS_SIDE_TOP mozilla::css::eSideTop -#define NS_SIDE_RIGHT mozilla::css::eSideRight -#define NS_SIDE_BOTTOM mozilla::css::eSideBottom -#define NS_SIDE_LEFT mozilla::css::eSideLeft #define NS_GFX #define NS_GFX_(type) type #define NS_GFX_STATIC_MEMBER_(type) type diff --git a/gfx/src/nsMargin.h b/gfx/src/nsMargin.h index 7ae3811b7ca..013ef13d138 100644 --- a/gfx/src/nsMargin.h +++ b/gfx/src/nsMargin.h @@ -41,10 +41,10 @@ #include "nsCoord.h" #include "nsPoint.h" #include "gfxCore.h" -#include "mozilla/BaseMargin.h" +#include "mozilla/gfx/BaseMargin.h" -struct nsMargin : public mozilla::BaseMargin { - typedef mozilla::BaseMargin Super; +struct nsMargin : public mozilla::gfx::BaseMargin { + typedef mozilla::gfx::BaseMargin Super; // Constructors nsMargin() : Super() {} @@ -53,8 +53,8 @@ struct nsMargin : public mozilla::BaseMargin { : Super(aLeft, aTop, aRight, aBottom) {} }; -struct nsIntMargin : public mozilla::BaseMargin { - typedef mozilla::BaseMargin Super; +struct nsIntMargin : public mozilla::gfx::BaseMargin { + typedef mozilla::gfx::BaseMargin Super; // Constructors nsIntMargin() : Super() {} diff --git a/gfx/src/nsPoint.h b/gfx/src/nsPoint.h index f8bd2c9e150..8a36df5f7b0 100644 --- a/gfx/src/nsPoint.h +++ b/gfx/src/nsPoint.h @@ -39,14 +39,14 @@ #define NSPOINT_H #include "nsCoord.h" -#include "mozilla/BaseSize.h" -#include "mozilla/BasePoint.h" +#include "mozilla/gfx/BaseSize.h" +#include "mozilla/gfx/BasePoint.h" #include "nsSize.h" struct nsIntPoint; -struct nsPoint : public mozilla::BasePoint { - typedef mozilla::BasePoint Super; +struct nsPoint : public mozilla::gfx::BasePoint { + typedef mozilla::gfx::BasePoint Super; nsPoint() : Super() {} nsPoint(const nsPoint& aPoint) : Super(aPoint) {} @@ -60,8 +60,8 @@ struct nsPoint : public mozilla::BasePoint { inline nsPoint ConvertAppUnits(PRInt32 aFromAPP, PRInt32 aToAPP) const; }; -struct nsIntPoint : public mozilla::BasePoint { - typedef mozilla::BasePoint Super; +struct nsIntPoint : public mozilla::gfx::BasePoint { + typedef mozilla::gfx::BasePoint Super; nsIntPoint() : Super() {} nsIntPoint(const nsIntPoint& aPoint) : Super(aPoint) {} diff --git a/gfx/src/nsRect.h b/gfx/src/nsRect.h index bc6e657bed3..6fa7f42dc76 100644 --- a/gfx/src/nsRect.h +++ b/gfx/src/nsRect.h @@ -46,13 +46,13 @@ #include "nsMargin.h" #include "gfxCore.h" #include "nsTraceRefcnt.h" -#include "mozilla/BaseRect.h" +#include "mozilla/gfx/BaseRect.h" struct nsIntRect; struct NS_GFX nsRect : - public mozilla::BaseRect { - typedef mozilla::BaseRect Super; + public mozilla::gfx::BaseRect { + typedef mozilla::gfx::BaseRect Super; static void VERIFY_COORD(nscoord aValue) { ::VERIFY_COORD(aValue); } @@ -103,8 +103,8 @@ struct NS_GFX nsRect : }; struct NS_GFX nsIntRect : - public mozilla::BaseRect { - typedef mozilla::BaseRect Super; + public mozilla::gfx::BaseRect { + typedef mozilla::gfx::BaseRect Super; // Constructors nsIntRect() : Super() diff --git a/gfx/src/nsSize.h b/gfx/src/nsSize.h index 876679b4a01..40187f4dd89 100644 --- a/gfx/src/nsSize.h +++ b/gfx/src/nsSize.h @@ -39,15 +39,15 @@ #define NSSIZE_H #include "nsCoord.h" -#include "mozilla/BaseSize.h" +#include "mozilla/gfx/BaseSize.h" // Maximum allowable size #define NS_MAXSIZE nscoord_MAX struct nsIntSize; -struct nsSize : public mozilla::BaseSize { - typedef mozilla::BaseSize Super; +struct nsSize : public mozilla::gfx::BaseSize { + typedef mozilla::gfx::BaseSize Super; nsSize() : Super() {} nsSize(nscoord aWidth, nscoord aHeight) : Super(aWidth, aHeight) {} @@ -59,8 +59,8 @@ struct nsSize : public mozilla::BaseSize { inline nsSize ConvertAppUnits(PRInt32 aFromAPP, PRInt32 aToAPP) const; }; -struct nsIntSize : public mozilla::BaseSize { - typedef mozilla::BaseSize Super; +struct nsIntSize : public mozilla::gfx::BaseSize { + typedef mozilla::gfx::BaseSize Super; nsIntSize() : Super() {} nsIntSize(PRInt32 aWidth, PRInt32 aHeight) : Super(aWidth, aHeight) {} diff --git a/gfx/thebes/Makefile.in b/gfx/thebes/Makefile.in index bec60796b00..ca3f5c92d08 100644 --- a/gfx/thebes/Makefile.in +++ b/gfx/thebes/Makefile.in @@ -12,6 +12,7 @@ LIBXUL_LIBRARY = 1 EXPORT_LIBRARY = 1 EXPORTS = \ + gfx2DGlue.h \ gfx3DMatrix.h \ gfxASurface.h \ gfxAlphaRecovery.h \ diff --git a/gfx/thebes/gfx2DGlue.h b/gfx/thebes/gfx2DGlue.h new file mode 100644 index 00000000000..82c70b8ebd1 --- /dev/null +++ b/gfx/thebes/gfx2DGlue.h @@ -0,0 +1,40 @@ + +#include "gfxRect.h" +#include "mozilla/gfx/Rect.h" + +namespace mozilla { +namespace gfx { +class DrawTarget; +class SourceSurface; +class ScaledFont; +} +} + +namespace mozilla { +namespace gfx { + +inline Rect ToRect(const gfxRect &aRect) +{ + return Rect(Float(aRect.x), Float(aRect.y), + Float(aRect.width), Float(aRect.height)); +} + +inline gfxRect GFXRect(const Rect &aRect) +{ + return gfxRect(aRect.x, aRect.y, aRect.width, aRect.height); +} + +inline gfxASurface::gfxContentType ContentForFormat(const SurfaceFormat &aFormat) +{ + switch (aFormat) { + case FORMAT_B8G8R8X8: + return gfxASurface::CONTENT_COLOR; + case FORMAT_A8: + return gfxASurface::CONTENT_ALPHA; + default: + return gfxASurface::CONTENT_COLOR_ALPHA; + } +} + +} +} diff --git a/gfx/thebes/gfxCoreTextShaper.cpp b/gfx/thebes/gfxCoreTextShaper.cpp index c45629b7e60..00b24fd86ec 100644 --- a/gfx/thebes/gfxCoreTextShaper.cpp +++ b/gfx/thebes/gfxCoreTextShaper.cpp @@ -71,10 +71,18 @@ gfxCoreTextShaper::gfxCoreTextShaper(gfxMacFont *aFont) : gfxFontShaper(aFont) { // Create our CTFontRef - mCTFont = ::CTFontCreateWithPlatformFont(aFont->GetATSFontRef(), - aFont->GetAdjustedSize(), - NULL, - GetDefaultFeaturesDescriptor()); + if (gfxMacPlatformFontList::UseATSFontEntry()) { + ATSFontEntry *fe = static_cast(aFont->GetFontEntry()); + mCTFont = ::CTFontCreateWithPlatformFont(fe->GetATSFontRef(), + aFont->GetAdjustedSize(), + NULL, + GetDefaultFeaturesDescriptor()); + } else { + mCTFont = ::CTFontCreateWithGraphicsFont(aFont->GetCGFontRef(), + aFont->GetAdjustedSize(), + NULL, + GetDefaultFeaturesDescriptor()); + } // Set up the default attribute dictionary that we will need each time we create a CFAttributedString mAttributesDict = ::CFDictionaryCreate(kCFAllocatorDefault, @@ -161,10 +169,8 @@ gfxCoreTextShaper::InitTextRun(gfxContext *aContext, if (disableLigatures) { // For letterspacing (or maybe other situations) we need to make a copy of the CTFont // with the ligature feature disabled - gfxMacFont *font = static_cast(mFont); CTFontRef ctFont = - CreateCTFontWithDisabledLigatures(font->GetATSFontRef(), - ::CTFontGetSize(mCTFont)); + CreateCTFontWithDisabledLigatures(::CTFontGetSize(mCTFont)); attrObj = ::CFDictionaryCreate(kCFAllocatorDefault, @@ -595,9 +601,9 @@ gfxCoreTextShaper::CreateDefaultFeaturesDescriptor() ::CFRelease(attributesDict); } -// Create a CTFontRef, with the Common Ligatures feature disabled [static] +// Create a CTFontRef, with the Common Ligatures feature disabled CTFontRef -gfxCoreTextShaper::CreateCTFontWithDisabledLigatures(ATSFontRef aFontRef, CGFloat aSize) +gfxCoreTextShaper::CreateCTFontWithDisabledLigatures(CGFloat aSize) { if (sDisableLigaturesDescriptor == NULL) { // initialize cached descriptor to turn off the Common Ligatures feature @@ -643,11 +649,20 @@ gfxCoreTextShaper::CreateCTFontWithDisabledLigatures(ATSFontRef aFontRef, CGFloa ::CFRelease(featuresArray); sDisableLigaturesDescriptor = - ::CTFontDescriptorCreateCopyWithAttributes(GetDefaultFeaturesDescriptor(), attributesDict); + ::CTFontDescriptorCreateCopyWithAttributes(GetDefaultFeaturesDescriptor(), + attributesDict); ::CFRelease(attributesDict); } - - return ::CTFontCreateWithPlatformFont(aFontRef, aSize, NULL, sDisableLigaturesDescriptor); + + if (gfxMacPlatformFontList::UseATSFontEntry()) { + ATSFontEntry *fe = static_cast(mFont->GetFontEntry()); + return ::CTFontCreateWithPlatformFont(fe->GetATSFontRef(), aSize, NULL, + sDisableLigaturesDescriptor); + } + + gfxMacFont *f = static_cast(mFont); + return ::CTFontCreateWithGraphicsFont(f->GetCGFontRef(), aSize, NULL, + sDisableLigaturesDescriptor); } void diff --git a/gfx/thebes/gfxCoreTextShaper.h b/gfx/thebes/gfxCoreTextShaper.h index 678507c252d..715b4037491 100644 --- a/gfx/thebes/gfxCoreTextShaper.h +++ b/gfx/thebes/gfxCoreTextShaper.h @@ -77,6 +77,8 @@ protected: PRInt32 aLayoutStart, PRInt32 aLayoutLength); + CTFontRef CreateCTFontWithDisabledLigatures(CGFloat aSize); + static void CreateDefaultFeaturesDescriptor(); static CTFontDescriptorRef GetDefaultFeaturesDescriptor() { @@ -86,8 +88,6 @@ protected: return sDefaultFeaturesDescriptor; } - static CTFontRef CreateCTFontWithDisabledLigatures(ATSFontRef aFontRef, CGFloat aSize); - // cached font descriptor, created the first time it's needed static CTFontDescriptorRef sDefaultFeaturesDescriptor; diff --git a/gfx/thebes/gfxD2DSurface.cpp b/gfx/thebes/gfxD2DSurface.cpp index 88aa6600b1d..6b6f7a53a2d 100644 --- a/gfx/thebes/gfxD2DSurface.cpp +++ b/gfx/thebes/gfxD2DSurface.cpp @@ -97,6 +97,12 @@ gfxD2DSurface::Scroll(const nsIntPoint &aDelta, const nsIntRect &aClip) cairo_d2d_scroll(CairoSurface(), aDelta.x, aDelta.y, &rect); } +ID3D10Texture2D* +gfxD2DSurface::GetTexture() +{ + return cairo_d2d_surface_get_texture(CairoSurface()); +} + HDC gfxD2DSurface::GetDC(PRBool aRetainContents) { diff --git a/gfx/thebes/gfxD2DSurface.h b/gfx/thebes/gfxD2DSurface.h index 85aae2b32e7..a1f67385e33 100644 --- a/gfx/thebes/gfxD2DSurface.h +++ b/gfx/thebes/gfxD2DSurface.h @@ -70,6 +70,8 @@ public: void Present(); void Scroll(const nsIntPoint &aDelta, const nsIntRect &aClip); + ID3D10Texture2D *GetTexture(); + HDC GetDC(PRBool aRetainContents); void ReleaseDC(const nsIntRect *aUpdatedRect); }; diff --git a/gfx/thebes/gfxMacFont.cpp b/gfx/thebes/gfxMacFont.cpp index 2c121204115..14a878bcd64 100644 --- a/gfx/thebes/gfxMacFont.cpp +++ b/gfx/thebes/gfxMacFont.cpp @@ -53,7 +53,6 @@ using namespace mozilla; gfxMacFont::gfxMacFont(MacOSFontEntry *aFontEntry, const gfxFontStyle *aFontStyle, PRBool aNeedsBold) : gfxFont(aFontEntry, aFontStyle), - mATSFont(aFontEntry->GetFontRef()), mCGFont(nsnull), mFontFace(nsnull), mScaledFont(nsnull) @@ -62,7 +61,7 @@ gfxMacFont::gfxMacFont(MacOSFontEntry *aFontEntry, const gfxFontStyle *aFontStyl mSyntheticBoldOffset = 1; // devunit offset when double-striking text to fake boldness } - mCGFont = ::CGFontCreateWithPlatformFont(&mATSFont); + mCGFont = aFontEntry->GetFontRef(); if (!mCGFont) { mIsValid = PR_FALSE; return; @@ -148,9 +147,6 @@ gfxMacFont::~gfxMacFont() if (mFontFace) { cairo_font_face_destroy(mFontFace); } - - // this is documented to be safe if mCGFont is null - ::CGFontRelease(mCGFont); } PRBool @@ -267,7 +263,7 @@ gfxMacFont::InitMetrics() // platform APIs. The InitMetrics...() functions will set mIsValid on success. if (!InitMetricsFromSfntTables(mMetrics) && (!mFontEntry->IsUserFont() || mFontEntry->IsLocalUserFont())) { - InitMetricsFromATSMetrics(); + InitMetricsFromPlatform(); } if (!mIsValid) { return; @@ -291,7 +287,7 @@ gfxMacFont::InitMetrics() mMetrics.xHeight = 0.0; if (!InitMetricsFromSfntTables(mMetrics) && (!mFontEntry->IsUserFont() || mFontEntry->IsLocalUserFont())) { - InitMetricsFromATSMetrics(); + InitMetricsFromPlatform(); } if (!mIsValid) { // this shouldn't happen, as we succeeded earlier before applying @@ -415,19 +411,65 @@ gfxMacFont::GetFontTable(PRUint32 aTag) return nsnull; } -// Try to initialize font metrics via ATS font metrics APIs, +// Try to initialize font metrics via platform APIs (CG/CT), // and set mIsValid = TRUE on success. // We ONLY call this for local (platform) fonts that are not sfnt format; -// for sfnts, including ALL downloadable fonts, use InitMetricsFromSfntTables -// because ATSFontGetHorizontalMetrics() has been known to crash when -// presented with bad fonts. +// for sfnts, including ALL downloadable fonts, we prefer to use +// InitMetricsFromSfntTables and avoid platform APIs. void -gfxMacFont::InitMetricsFromATSMetrics() +gfxMacFont::InitMetricsFromPlatform() +{ + if (gfxMacPlatformFontList::UseATSFontEntry()) { + ATSFontEntry *fe = static_cast(GetFontEntry()); + InitMetricsFromATSMetrics(fe->GetATSFontRef()); + return; + } + + CTFontRef ctFont = ::CTFontCreateWithGraphicsFont(mCGFont, + mAdjustedSize, + NULL, NULL); + if (!ctFont) { + return; + } + + mMetrics.underlineOffset = ::CTFontGetUnderlinePosition(ctFont); + mMetrics.underlineSize = ::CTFontGetUnderlineThickness(ctFont); + + mMetrics.externalLeading = ::CTFontGetLeading(ctFont); + + mMetrics.maxAscent = ::CTFontGetAscent(ctFont); + mMetrics.maxDescent = ::CTFontGetDescent(ctFont); + + // this is not strictly correct, but neither CTFont nor CGFont seems to + // provide maxAdvance, unless we were to iterate over all the glyphs + // (which isn't worth the cost here) + CGRect r = ::CTFontGetBoundingBox(ctFont); + mMetrics.maxAdvance = r.size.width; + + // aveCharWidth is also not provided, so leave it at zero + // (fallback code in gfxMacFont::InitMetrics will then try measuring 'x'); + // this could lead to less-than-"perfect" text field sizing when width is + // specified as a number of characters, and the font in use is a non-sfnt + // legacy font, but that's a sufficiently obscure edge case that we can + // ignore the potential discrepancy. + mMetrics.aveCharWidth = 0; + + mMetrics.xHeight = ::CTFontGetXHeight(ctFont); + + ::CFRelease(ctFont); + + mIsValid = PR_TRUE; +} + +// For OS X 10.5, try to initialize font metrics via ATS font metrics APIs, +// and set mIsValid = TRUE on success. +void +gfxMacFont::InitMetricsFromATSMetrics(ATSFontRef aFontRef) { ATSFontMetrics atsMetrics; OSStatus err; - err = ::ATSFontGetHorizontalMetrics(mATSFont, kATSOptionFlagsDefault, + err = ::ATSFontGetHorizontalMetrics(aFontRef, kATSOptionFlagsDefault, &atsMetrics); if (err != noErr) { #ifdef DEBUG diff --git a/gfx/thebes/gfxMacFont.h b/gfx/thebes/gfxMacFont.h index 956bb5ec69a..f9cfab9dfc1 100644 --- a/gfx/thebes/gfxMacFont.h +++ b/gfx/thebes/gfxMacFont.h @@ -54,7 +54,6 @@ public: virtual ~gfxMacFont(); - ATSFontRef GetATSFontRef() const { return mATSFont; } CGFontRef GetCGFontRef() const { return mCGFont; } /* overrides for the pure virtual methods in gfxFont */ @@ -92,7 +91,8 @@ protected: PRBool aPreferPlatformShaping = PR_FALSE); void InitMetrics(); - void InitMetricsFromATSMetrics(); + void InitMetricsFromPlatform(); + void InitMetricsFromATSMetrics(ATSFontRef aFontRef); // Get width and glyph ID for a character; uses aConvFactor // to convert font units as returned by CG to actual dimensions @@ -101,7 +101,8 @@ protected: static void DestroyBlobFunc(void* aUserData); - ATSFontRef mATSFont; + // a weak reference to the CoreGraphics font: this is owned by the + // MacOSFontEntry, it is not retained or released by gfxMacFont CGFontRef mCGFont; cairo_font_face_t *mFontFace; diff --git a/gfx/thebes/gfxMacPlatformFontList.h b/gfx/thebes/gfxMacPlatformFontList.h index 2eb3942eac0..82830698e94 100644 --- a/gfx/thebes/gfxMacPlatformFontList.h +++ b/gfx/thebes/gfxMacPlatformFontList.h @@ -46,6 +46,7 @@ #include "gfxPlatformFontList.h" #include "gfxPlatform.h" +#include "gfxPlatformMac.h" #include @@ -60,33 +61,83 @@ class MacOSFontEntry : public gfxFontEntry public: friend class gfxMacPlatformFontList; - MacOSFontEntry(const nsAString& aPostscriptName, PRInt32 aWeight, - gfxFontFamily *aFamily, PRBool aIsStandardFace = PR_FALSE); + virtual ~MacOSFontEntry() { + ::CGFontRelease(mFontRef); + } + + virtual CGFontRef GetFontRef() = 0; + + virtual nsresult GetFontTable(PRUint32 aTableTag, + FallibleTArray& aBuffer) = 0; - ATSFontRef GetFontRef(); nsresult ReadCMAP(); PRBool RequiresAATLayout() const { return mRequiresAAT; } - virtual nsresult GetFontTable(PRUint32 aTableTag, FallibleTArray& aBuffer); - PRBool IsCFF(); protected: - // for use with data fonts - MacOSFontEntry(const nsAString& aPostscriptName, ATSFontRef aFontRef, - PRUint16 aWeight, PRUint16 aStretch, PRUint32 aItalicStyle, - gfxUserFontData *aUserFontData); + MacOSFontEntry(const nsAString& aPostscriptName, PRInt32 aWeight, + gfxFontFamily *aFamily, PRBool aIsStandardFace = PR_FALSE); virtual gfxFont* CreateFontInstance(const gfxFontStyle *aFontStyle, PRBool aNeedsBold); - ATSFontRef mATSFontRef; - PRPackedBool mATSFontRefInitialized; + virtual PRBool HasFontTable(PRUint32 aTableTag) = 0; + + CGFontRef mFontRef; // owning reference to the CGFont, released on destruction + + PRPackedBool mFontRefInitialized; PRPackedBool mRequiresAAT; PRPackedBool mIsCFF; PRPackedBool mIsCFFInitialized; }; +// concrete subclasses of MacOSFontEntry: ATSFontEntry for 10.5, CGFontEntry for 10.6+ +class ATSFontEntry : public MacOSFontEntry +{ +public: + ATSFontEntry(const nsAString& aPostscriptName, PRInt32 aWeight, + gfxFontFamily *aFamily, PRBool aIsStandardFace = PR_FALSE); + + // for use with data fonts + ATSFontEntry(const nsAString& aPostscriptName, ATSFontRef aFontRef, + PRUint16 aWeight, PRUint16 aStretch, PRUint32 aItalicStyle, + gfxUserFontData *aUserFontData, PRBool aIsLocal); + + ATSFontRef GetATSFontRef(); + + virtual CGFontRef GetFontRef(); + + virtual nsresult GetFontTable(PRUint32 aTableTag, + FallibleTArray& aBuffer); + +protected: + virtual PRBool HasFontTable(PRUint32 aTableTag); + + ATSFontRef mATSFontRef; + PRPackedBool mATSFontRefInitialized; +}; + +class CGFontEntry : public MacOSFontEntry +{ +public: + CGFontEntry(const nsAString& aPostscriptName, PRInt32 aWeight, + gfxFontFamily *aFamily, PRBool aIsStandardFace = PR_FALSE); + + // for use with data fonts + CGFontEntry(const nsAString& aPostscriptName, CGFontRef aFontRef, + PRUint16 aWeight, PRUint16 aStretch, PRUint32 aItalicStyle, + PRBool aIsUserFont, PRBool aIsLocal); + + virtual CGFontRef GetFontRef(); + + virtual nsresult GetFontTable(PRUint32 aTableTag, + FallibleTArray& aBuffer); + +protected: + virtual PRBool HasFontTable(PRUint32 aTableTag); +}; + class gfxMacPlatformFontList : public gfxPlatformFontList { public: static gfxMacPlatformFontList* PlatformFontList() { @@ -107,6 +158,10 @@ public: void ClearPrefFonts() { mPrefFonts.Clear(); } + static PRBool UseATSFontEntry() { + return gfxPlatformMac::GetPlatform()->OSXVersion() < MAC_OS_X_VERSION_10_6_HEX; + } + private: friend class gfxPlatformMac; @@ -118,8 +173,11 @@ private: // special case font faces treated as font families (set via prefs) void InitSingleFaceList(); - // eliminate faces which have the same ATS font reference - void EliminateDuplicateFaces(const nsAString& aFamilyName); + gfxFontEntry* MakePlatformFontCG(const gfxProxyFontEntry *aProxyEntry, + const PRUint8 *aFontData, PRUint32 aLength); + + gfxFontEntry* MakePlatformFontATS(const gfxProxyFontEntry *aProxyEntry, + const PRUint8 *aFontData, PRUint32 aLength); static void ATSNotification(ATSFontNotificationInfoRef aInfo, void* aUserArg); diff --git a/gfx/thebes/gfxMacPlatformFontList.mm b/gfx/thebes/gfxMacPlatformFontList.mm index ed07c27bf58..7039a644c49 100644 --- a/gfx/thebes/gfxMacPlatformFontList.mm +++ b/gfx/thebes/gfxMacPlatformFontList.mm @@ -135,7 +135,7 @@ static NSString* GetNSStringForString(const nsAString& aSrc) #endif // PR_LOGGING -/* MacOSFontEntry */ +/* MacOSFontEntry - abstract superclass for ATS and CG font entries */ #pragma mark- MacOSFontEntry::MacOSFontEntry(const nsAString& aPostscriptName, @@ -143,8 +143,8 @@ MacOSFontEntry::MacOSFontEntry(const nsAString& aPostscriptName, gfxFontFamily *aFamily, PRBool aIsStandardFace) : gfxFontEntry(aPostscriptName, aFamily, aIsStandardFace), - mATSFontRef(0), - mATSFontRefInitialized(PR_FALSE), + mFontRef(NULL), + mFontRefInitialized(PR_FALSE), mRequiresAAT(PR_FALSE), mIsCFF(PR_FALSE), mIsCFFInitialized(PR_FALSE) @@ -152,38 +152,6 @@ MacOSFontEntry::MacOSFontEntry(const nsAString& aPostscriptName, mWeight = aWeight; } -MacOSFontEntry::MacOSFontEntry(const nsAString& aPostscriptName, ATSFontRef aFontRef, - PRUint16 aWeight, PRUint16 aStretch, PRUint32 aItalicStyle, - gfxUserFontData *aUserFontData) - : gfxFontEntry(aPostscriptName), - mATSFontRef(aFontRef), - mATSFontRefInitialized(PR_TRUE), - mRequiresAAT(PR_FALSE), - mIsCFF(PR_FALSE), - mIsCFFInitialized(PR_FALSE) -{ - // xxx - stretch is basically ignored for now - - mUserFontData = aUserFontData; - mWeight = aWeight; - mStretch = aStretch; - mFixedPitch = PR_FALSE; // xxx - do we need this for downloaded fonts? - mItalic = (aItalicStyle & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)) != 0; - mIsUserFont = aUserFontData != nsnull; -} - -ATSFontRef -MacOSFontEntry::GetFontRef() -{ - if (!mATSFontRefInitialized) { - mATSFontRefInitialized = PR_TRUE; - NSString *psname = GetNSStringForString(mName); - mATSFontRef = ::ATSFontFindFromPostScriptName(CFStringRef(psname), - kATSOptionFlagsDefault); - } - return mATSFontRef; -} - // ATSUI requires AAT-enabled fonts to render complex scripts correctly. // For now, simple clear out the cmap codepoints for fonts that have // codepoints for complex scripts. (Bug 361986) @@ -212,18 +180,18 @@ const ScriptRange gScriptsThatRequireShaping[] = { nsresult MacOSFontEntry::ReadCMAP() { - ByteCount size; - // attempt this once, if errors occur leave a blank cmap - if (mCmapInitialized) + if (mCmapInitialized) { return NS_OK; + } mCmapInitialized = PR_TRUE; PRUint32 kCMAP = TRUETYPE_TAG('c','m','a','p'); AutoFallibleTArray cmap; - if (GetFontTable(kCMAP, cmap) != NS_OK) + if (GetFontTable(kCMAP, cmap) != NS_OK) { return NS_ERROR_FAILURE; + } PRPackedBool unicodeFont, symbolFont; // currently ignored nsresult rv = gfxFontUtils::ReadCMAP(cmap.Elements(), cmap.Length(), @@ -235,22 +203,17 @@ MacOSFontEntry::ReadCMAP() } mHasCmapTable = PR_TRUE; - ATSFontRef fontRef = GetFontRef(); + CGFontRef fontRef = GetFontRef(); + if (!fontRef) { + return NS_ERROR_FAILURE; + } // for layout support, check for the presence of mort/morx and/or // opentype layout tables - PRBool hasAATLayout = - (::ATSFontGetTable(fontRef, TRUETYPE_TAG('m','o','r','x'), - 0, 0, 0, &size) == noErr) || - (::ATSFontGetTable(fontRef, TRUETYPE_TAG('m','o','r','t'), - 0, 0, 0, &size) == noErr); - - PRBool hasGSUB = - (::ATSFontGetTable(fontRef, TRUETYPE_TAG('G','S','U','B'), - 0, 0, 0, &size) == noErr); - PRBool hasGPOS = - (::ATSFontGetTable(fontRef, TRUETYPE_TAG('G','P','O','S'), - 0, 0, 0, &size) == noErr); + PRBool hasAATLayout = HasFontTable(TRUETYPE_TAG('m','o','r','x')) || + HasFontTable(TRUETYPE_TAG('m','o','r','t')); + PRBool hasGSUB = HasFontTable(TRUETYPE_TAG('G','S','U','B')); + PRBool hasGPOS = HasFontTable(TRUETYPE_TAG('G','P','O','S')); if (hasAATLayout && !(hasGSUB || hasGPOS)) { mRequiresAAT = PR_TRUE; // prefer CoreText if font has no OTL tables @@ -305,13 +268,93 @@ MacOSFontEntry::ReadCMAP() return rv; } +gfxFont* +MacOSFontEntry::CreateFontInstance(const gfxFontStyle *aFontStyle, PRBool aNeedsBold) +{ + return new gfxMacFont(this, aFontStyle, aNeedsBold); +} + +PRBool +MacOSFontEntry::IsCFF() +{ + if (!mIsCFFInitialized) { + mIsCFFInitialized = PR_TRUE; + mIsCFF = HasFontTable(TRUETYPE_TAG('C','F','F',' ')); + } + + return mIsCFF; +} + +/* ATSFontEntry - used on Mac OS X 10.5.x */ +#pragma mark- + +ATSFontEntry::ATSFontEntry(const nsAString& aPostscriptName, + PRInt32 aWeight, + gfxFontFamily *aFamily, + PRBool aIsStandardFace) + : MacOSFontEntry(aPostscriptName, aWeight, aFamily, aIsStandardFace), + mATSFontRef(kInvalidFont), + mATSFontRefInitialized(PR_FALSE) +{ +} + +ATSFontEntry::ATSFontEntry(const nsAString& aPostscriptName, + ATSFontRef aFontRef, + PRUint16 aWeight, PRUint16 aStretch, + PRUint32 aItalicStyle, + gfxUserFontData *aUserFontData, + PRBool aIsLocal) + : MacOSFontEntry(aPostscriptName, aWeight, nsnull, PR_FALSE) +{ + mATSFontRef = aFontRef; + mATSFontRefInitialized = PR_TRUE; + + mWeight = aWeight; + mStretch = aStretch; + mFixedPitch = PR_FALSE; // xxx - do we need this for downloaded fonts? + mItalic = (aItalicStyle & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)) != 0; + mUserFontData = aUserFontData; + mIsUserFont = (aUserFontData != nsnull) || aIsLocal; + mIsLocalUserFont = aIsLocal; +} + +ATSFontRef +ATSFontEntry::GetATSFontRef() +{ + if (!mATSFontRefInitialized) { + mATSFontRefInitialized = PR_TRUE; + NSString *psname = GetNSStringForString(mName); + mATSFontRef = ::ATSFontFindFromPostScriptName(CFStringRef(psname), + kATSOptionFlagsDefault); + } + return mATSFontRef; +} + +CGFontRef +ATSFontEntry::GetFontRef() +{ + if (mFontRefInitialized) { + return mFontRef; + } + + // GetATSFontRef will initialize mATSFontRef + if (GetATSFontRef() == kInvalidFont) { + return nsnull; + } + + mFontRef = ::CGFontCreateWithPlatformFont(&mATSFontRef); + mFontRefInitialized = PR_TRUE; + + return mFontRef; +} + nsresult -MacOSFontEntry::GetFontTable(PRUint32 aTableTag, FallibleTArray& aBuffer) +ATSFontEntry::GetFontTable(PRUint32 aTableTag, FallibleTArray& aBuffer) { nsAutoreleasePool localPool; - ATSFontRef fontRef = GetFontRef(); - if (fontRef == (ATSFontRef)kATSUInvalidFontID) { + ATSFontRef fontRef = GetATSFontRef(); + if (fontRef == kInvalidFont) { return NS_ERROR_FAILURE; } @@ -331,33 +374,103 @@ MacOSFontEntry::GetFontTable(PRUint32 aTableTag, FallibleTArray& aBuffe return NS_OK; } - -gfxFont* -MacOSFontEntry::CreateFontInstance(const gfxFontStyle *aFontStyle, PRBool aNeedsBold) + +PRBool +ATSFontEntry::HasFontTable(PRUint32 aTableTag) { - return new gfxMacFont(this, aFontStyle, aNeedsBold); + ATSFontRef fontRef = GetATSFontRef(); + ByteCount size; + return fontRef != kInvalidFont && + (::ATSFontGetTable(fontRef, aTableTag, 0, 0, 0, &size) == noErr); +} + +/* CGFontEntry - used on Mac OS X 10.6+ */ +#pragma mark- + +CGFontEntry::CGFontEntry(const nsAString& aPostscriptName, + PRInt32 aWeight, + gfxFontFamily *aFamily, + PRBool aIsStandardFace) + : MacOSFontEntry(aPostscriptName, aWeight, aFamily, aIsStandardFace) +{ +} + +CGFontEntry::CGFontEntry(const nsAString& aPostscriptName, + CGFontRef aFontRef, + PRUint16 aWeight, PRUint16 aStretch, + PRUint32 aItalicStyle, + PRBool aIsUserFont, PRBool aIsLocal) + : MacOSFontEntry(aPostscriptName, aWeight, nsnull, PR_FALSE) +{ + mFontRef = aFontRef; + mFontRefInitialized = PR_TRUE; + ::CFRetain(mFontRef); + + mWeight = aWeight; + mStretch = aStretch; + mFixedPitch = PR_FALSE; // xxx - do we need this for downloaded fonts? + mItalic = (aItalicStyle & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)) != 0; + mIsUserFont = aIsUserFont; + mIsLocalUserFont = aIsLocal; +} + +CGFontRef +CGFontEntry::GetFontRef() +{ + if (!mFontRefInitialized) { + mFontRefInitialized = PR_TRUE; + NSString *psname = GetNSStringForString(mName); + mFontRef = ::CGFontCreateWithFontName(CFStringRef(psname)); + } + return mFontRef; +} + +nsresult +CGFontEntry::GetFontTable(PRUint32 aTableTag, FallibleTArray& aBuffer) +{ + nsAutoreleasePool localPool; + + CGFontRef fontRef = GetFontRef(); + if (!fontRef) { + return NS_ERROR_FAILURE; + } + + CFDataRef tableData = ::CGFontCopyTableForTag(fontRef, aTableTag); + if (!tableData) { + return NS_ERROR_FAILURE; + } + + nsresult rval = NS_OK; + CFIndex dataLength = ::CFDataGetLength(tableData); + if (aBuffer.AppendElements(dataLength)) { + ::CFDataGetBytes(tableData, ::CFRangeMake(0, dataLength), + aBuffer.Elements()); + } else { + rval = NS_ERROR_OUT_OF_MEMORY; + } + ::CFRelease(tableData); + + return rval; } PRBool -MacOSFontEntry::IsCFF() +CGFontEntry::HasFontTable(PRUint32 aTableTag) { - if (!mIsCFFInitialized) { - mIsCFFInitialized = PR_TRUE; - ATSFontRef fontRef = GetFontRef(); - if (fontRef != (ATSFontRef)kATSUInvalidFontID) { - ByteCount dataLength; - OSStatus status = ::ATSFontGetTable(fontRef, - TRUETYPE_TAG('C','F','F',' '), - 0, 0, 0, &dataLength); - if (status == noErr && dataLength > 0) { - mIsCFF = PR_TRUE; - } - } + nsAutoreleasePool localPool; + + CGFontRef fontRef = GetFontRef(); + if (!fontRef) { + return PR_FALSE; } - return mIsCFF; -} + CFDataRef tableData = ::CGFontCopyTableForTag(fontRef, aTableTag); + if (!tableData) { + return PR_FALSE; + } + ::CFRelease(tableData); + return PR_TRUE; +} /* gfxMacFontFamily */ #pragma mark- @@ -374,8 +487,6 @@ public: virtual void LocalizedName(nsAString& aLocalizedName); virtual void FindStyleVariations(); - - void EliminateDuplicateFaces(); }; void @@ -455,9 +566,17 @@ gfxMacFontFamily::FindStyleVariations() } // create a font entry - MacOSFontEntry *fontEntry = new MacOSFontEntry(postscriptFontName, - cssWeight, this, isStandardFace); - if (!fontEntry) break; + MacOSFontEntry *fontEntry; + if (gfxMacPlatformFontList::UseATSFontEntry()) { + fontEntry = new ATSFontEntry(postscriptFontName, + cssWeight, this, isStandardFace); + } else { + fontEntry = new CGFontEntry(postscriptFontName, + cssWeight, this, isStandardFace); + } + if (!fontEntry) { + break; + } // set additional properties based on the traits reported by Cocoa if (macTraits & (NSCondensedFontMask | NSNarrowFontMask | NSCompressedFontMask)) { @@ -502,54 +621,6 @@ gfxMacFontFamily::FindStyleVariations() } } -void -gfxMacFontFamily::EliminateDuplicateFaces() -{ - PRUint32 i, bold, numFonts, italicIndex; - MacOSFontEntry *italic, *nonitalic; - - FindStyleVariations(); - - // if normal and italic have the same ATS font ref, delete italic - // if bold and bold-italic have the same ATS font ref, delete bold-italic - - // two iterations, one for normal, one for bold - for (bold = 0; bold < 2; bold++) { - numFonts = mAvailableFonts.Length(); - - // find the non-italic face - nonitalic = nsnull; - for (i = 0; i < numFonts; i++) { - if ((mAvailableFonts[i]->IsBold() == (bold == 1)) && - !mAvailableFonts[i]->IsItalic()) { - nonitalic = static_cast(mAvailableFonts[i].get()); - break; - } - } - - // find the italic face - if (nonitalic) { - italic = nsnull; - for (i = 0; i < numFonts; i++) { - if ((mAvailableFonts[i]->IsBold() == (bold == 1)) && - mAvailableFonts[i]->IsItalic()) { - italic = static_cast(mAvailableFonts[i].get()); - italicIndex = i; - break; - } - } - - // if italic face and non-italic face have matching ATS refs, - // or if the italic returns 0 rather than an actual ATSFontRef, - // then the italic face is bogus so remove it - if (italic && (italic->GetFontRef() == 0 || - italic->GetFontRef() == nonitalic->GetFontRef())) { - mAvailableFonts.RemoveElementAt(italicIndex); - } - } - } -} - /* gfxSingleFaceMacFontFamily */ #pragma mark- @@ -686,19 +757,6 @@ gfxMacPlatformFontList::InitFontList() // a font lookup miss earlier. this is a simple optimization, it's not required for correctness PreloadNamesList(); - // clean up various minor 10.4 font problems for specific fonts - if (gfxPlatformMac::GetPlatform()->OSXVersion() < MAC_OS_X_VERSION_10_5_HEX) { - // Cocoa calls report that italic faces exist for Courier and Helvetica, - // even though only bold faces exist so test for this using ATS font refs (10.5 has proper faces) - EliminateDuplicateFaces(NS_LITERAL_STRING("Courier")); - EliminateDuplicateFaces(NS_LITERAL_STRING("Helvetica")); - - // Cocoa reports that Courier and Monaco are not fixed-pitch fonts - // so explicitly tweak these settings - SetFixedPitch(NS_LITERAL_STRING("Courier")); - SetFixedPitch(NS_LITERAL_STRING("Monaco")); - } - // start the delayed cmap loader StartLoader(kDelayBeforeLoadingCmaps, kIntervalBetweenLoadingCmaps); @@ -747,16 +805,6 @@ gfxMacPlatformFontList::InitSingleFaceList() } } -void -gfxMacPlatformFontList::EliminateDuplicateFaces(const nsAString& aFamilyName) -{ - gfxMacFontFamily *family = - static_cast(FindFamily(aFamilyName)); - - if (family) - family->EliminateDuplicateFaces(); -} - PRBool gfxMacPlatformFontList::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName) { @@ -841,41 +889,132 @@ gfxMacPlatformFontList::LookupLocalFont(const gfxProxyFontEntry *aProxyEntry, nsAutoreleasePool localPool; NSString *faceName = GetNSStringForString(aFontName); - - // first lookup a single face based on postscript name - ATSFontRef fontRef = ::ATSFontFindFromPostScriptName(CFStringRef(faceName), - kATSOptionFlagsDefault); - - // if not found, lookup using full font name - if (fontRef == kInvalidFont) - fontRef = ::ATSFontFindFromName(CFStringRef(faceName), - kATSOptionFlagsDefault); - - // not found - if (fontRef == kInvalidFont) - return nsnull; - MacOSFontEntry *newFontEntry; - if (aProxyEntry) { - PRUint16 w = aProxyEntry->mWeight; - NS_ASSERTION(w >= 100 && w <= 900, "bogus font weight value!"); - newFontEntry = - new MacOSFontEntry(aFontName, fontRef, - w, aProxyEntry->mStretch, - aProxyEntry->mItalic ? - FONT_STYLE_ITALIC : FONT_STYLE_NORMAL, - nsnull); - newFontEntry->mIsUserFont = newFontEntry->mIsLocalUserFont = PR_TRUE; + if (UseATSFontEntry()) { + // first lookup a single face based on postscript name + ATSFontRef fontRef = ::ATSFontFindFromPostScriptName(CFStringRef(faceName), + kATSOptionFlagsDefault); + + // if not found, lookup using full font name + if (fontRef == kInvalidFont) { + fontRef = ::ATSFontFindFromName(CFStringRef(faceName), + kATSOptionFlagsDefault); + if (fontRef == kInvalidFont) { + return nsnull; + } + } + + if (aProxyEntry) { + PRUint16 w = aProxyEntry->mWeight; + NS_ASSERTION(w >= 100 && w <= 900, "bogus font weight value!"); + + newFontEntry = + new ATSFontEntry(aFontName, fontRef, + w, aProxyEntry->mStretch, + aProxyEntry->mItalic ? + FONT_STYLE_ITALIC : FONT_STYLE_NORMAL, + nsnull, PR_TRUE); + } else { + newFontEntry = + new ATSFontEntry(aFontName, fontRef, + 400, 0, FONT_STYLE_NORMAL, nsnull, PR_FALSE); + } } else { - newFontEntry = - new MacOSFontEntry(aFontName, fontRef, - 400, 0, FONT_STYLE_NORMAL, nsnull); + // lookup face based on postscript or full name + CGFontRef fontRef = ::CGFontCreateWithFontName(CFStringRef(faceName)); + if (!fontRef) { + return nsnull; + } + + if (aProxyEntry) { + PRUint16 w = aProxyEntry->mWeight; + NS_ASSERTION(w >= 100 && w <= 900, "bogus font weight value!"); + + newFontEntry = + new CGFontEntry(aFontName, fontRef, + w, aProxyEntry->mStretch, + aProxyEntry->mItalic ? + FONT_STYLE_ITALIC : FONT_STYLE_NORMAL, + PR_TRUE, PR_TRUE); + } else { + newFontEntry = + new CGFontEntry(aFontName, fontRef, + 400, 0, FONT_STYLE_NORMAL, + PR_FALSE, PR_FALSE); + } + ::CFRelease(fontRef); } return newFontEntry; } +gfxFontEntry* +gfxMacPlatformFontList::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry, + const PRUint8 *aFontData, + PRUint32 aLength) +{ + return UseATSFontEntry() + ? MakePlatformFontATS(aProxyEntry, aFontData, aLength) + : MakePlatformFontCG(aProxyEntry, aFontData, aLength); +} + +static void ReleaseData(void *info, const void *data, size_t size) +{ + NS_Free((void*)data); +} + +gfxFontEntry* +gfxMacPlatformFontList::MakePlatformFontCG(const gfxProxyFontEntry *aProxyEntry, + const PRUint8 *aFontData, + PRUint32 aLength) +{ + NS_ASSERTION(aFontData, "MakePlatformFont called with null data"); + + PRUint16 w = aProxyEntry->mWeight; + NS_ASSERTION(w >= 100 && w <= 900, "bogus font weight value!"); + + // create the font entry + nsAutoString uniqueName; + + nsresult rv = gfxFontUtils::MakeUniqueUserFontName(uniqueName); + if (NS_FAILED(rv)) { + return nsnull; + } + + CGDataProviderRef provider = + ::CGDataProviderCreateWithData(nsnull, aFontData, aLength, + &ReleaseData); + CGFontRef fontRef = ::CGFontCreateWithDataProvider(provider); + ::CGDataProviderRelease(provider); + + if (!fontRef) { + return nsnull; + } + + nsAutoPtr + newFontEntry(new CGFontEntry(uniqueName, fontRef, w, + aProxyEntry->mStretch, + aProxyEntry->mItalic ? + FONT_STYLE_ITALIC : FONT_STYLE_NORMAL, + PR_TRUE, PR_FALSE)); + + // if succeeded and font cmap is good, return the new font + if (newFontEntry->mIsValid && NS_SUCCEEDED(newFontEntry->ReadCMAP())) { + return newFontEntry.forget(); + } + + // if something is funky about this font, delete immediately +#if DEBUG + char warnBuf[1024]; + sprintf(warnBuf, "downloaded font not loaded properly, removed face for (%s)", + NS_ConvertUTF16toUTF8(aProxyEntry->mFamily->Name()).get()); + NS_WARNING(warnBuf); +#endif + + return nsnull; +} + // grumble, another non-publised Apple API dependency (found in Webkit code) // activated with this value, font will not be found via system lookup routines // it can only be used via the created ATSFontRef @@ -885,26 +1024,27 @@ enum { kPrivateATSFontContextPrivate = 3 }; -class MacOSUserFontData : public gfxUserFontData { +class ATSUserFontData : public gfxUserFontData { public: - MacOSUserFontData(ATSFontContainerRef aContainerRef) + ATSUserFontData(ATSFontContainerRef aContainerRef) : mContainerRef(aContainerRef) { } - virtual ~MacOSUserFontData() + virtual ~ATSUserFontData() { // deactivate font - if (mContainerRef) + if (mContainerRef) { ::ATSFontDeactivate(mContainerRef, NULL, kATSOptionFlagsDefault); + } } ATSFontContainerRef mContainerRef; }; gfxFontEntry* -gfxMacPlatformFontList::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry, - const PRUint8 *aFontData, - PRUint32 aLength) +gfxMacPlatformFontList::MakePlatformFontATS(const gfxProxyFontEntry *aProxyEntry, + const PRUint8 *aFontData, + PRUint32 aLength) { OSStatus err; @@ -982,42 +1122,30 @@ gfxMacPlatformFontList::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry, continue; } - // font entry will own this - MacOSUserFontData *userFontData = new MacOSUserFontData(containerRef); - - if (!userFontData) { - ::ATSFontDeactivate(containerRef, NULL, kATSOptionFlagsDefault); - return nsnull; - } - PRUint16 w = aProxyEntry->mWeight; NS_ASSERTION(w >= 100 && w <= 900, "bogus font weight value!"); - // create the font entry nsAutoString uniqueName; - nsresult rv = gfxFontUtils::MakeUniqueUserFontName(uniqueName); if (NS_FAILED(rv)) { - delete userFontData; return nsnull; } - MacOSFontEntry *newFontEntry = - new MacOSFontEntry(uniqueName, - fontRef, - w, aProxyEntry->mStretch, - aProxyEntry->mItalic ? - FONT_STYLE_ITALIC : FONT_STYLE_NORMAL, - userFontData); + // font entry will own this + ATSUserFontData *userFontData = new ATSUserFontData(containerRef); - if (!newFontEntry) { - delete userFontData; - return nsnull; - } + ATSFontEntry *newFontEntry = + new ATSFontEntry(uniqueName, + fontRef, + w, aProxyEntry->mStretch, + aProxyEntry->mItalic ? + FONT_STYLE_ITALIC : FONT_STYLE_NORMAL, + userFontData, PR_FALSE); // if succeeded and font cmap is good, return the new font - if (newFontEntry->mIsValid && NS_SUCCEEDED(newFontEntry->ReadCMAP())) + if (newFontEntry->mIsValid && NS_SUCCEEDED(newFontEntry->ReadCMAP())) { return newFontEntry; + } // if something is funky about this font, delete immediately #if DEBUG @@ -1039,4 +1167,3 @@ gfxMacPlatformFontList::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry, // if we get here, the activation failed (even with possible retries); can't use this font return nsnull; } - diff --git a/gfx/thebes/gfxPlatform.cpp b/gfx/thebes/gfxPlatform.cpp index 99d3b09daf8..ab35a62f26f 100644 --- a/gfx/thebes/gfxPlatform.cpp +++ b/gfx/thebes/gfxPlatform.cpp @@ -44,6 +44,7 @@ #if defined(XP_WIN) #include "gfxWindowsPlatform.h" +#include "gfxD2DSurface.h" #elif defined(XP_MACOSX) #include "gfxPlatformMac.h" #elif defined(MOZ_WIDGET_GTK2) @@ -114,6 +115,8 @@ static const char *CMForceSRGBPrefName = "gfx.color_management.force_srgb"; static void ShutdownCMS(); static void MigratePrefs(); +#include "mozilla/gfx/2D.h" +using namespace mozilla::gfx; // logs shared across gfx #ifdef PR_LOGGING @@ -415,6 +418,101 @@ gfxPlatform::OptimizeImage(gfxImageSurface *aSurface, return ret; } +cairo_user_data_key_t kDrawTarget; + +RefPtr +gfxPlatform::CreateDrawTargetForSurface(gfxASurface *aSurface) +{ +#ifdef XP_WIN + if (aSurface->GetType() == gfxASurface::SurfaceTypeD2D) { + RefPtr drawTarget = + Factory::CreateDrawTargetForD3D10Texture(static_cast(aSurface)->GetTexture(), FORMAT_B8G8R8A8); + aSurface->SetData(&kDrawTarget, drawTarget, NULL); + return drawTarget; + } +#endif + + // Can't create a draw target for general cairo surfaces yet. + return NULL; +} + +cairo_user_data_key_t kSourceSurface; + +void SourceBufferDestroy(void *srcBuffer) +{ + static_cast(srcBuffer)->Release(); +} + +RefPtr +gfxPlatform::GetSourceSurfaceForSurface(DrawTarget *aTarget, gfxASurface *aSurface) +{ + void *userData = aSurface->GetData(&kSourceSurface); + + if (userData) { + return static_cast(userData); + } + + SurfaceFormat format; + if (aSurface->GetContentType() == gfxASurface::CONTENT_ALPHA) { + format = FORMAT_A8; + } else if (aSurface->GetContentType() == gfxASurface::CONTENT_COLOR) { + format = FORMAT_B8G8R8X8; + } else { + format = FORMAT_B8G8R8A8; + } + + RefPtr srcBuffer; + +#ifdef XP_WIN + if (aSurface->GetType() == gfxASurface::SurfaceTypeD2D) { + NativeSurface surf; + surf.mFormat = format; + surf.mType = NATIVE_SURFACE_D3D10_TEXTURE; + surf.mSurface = static_cast(aSurface)->GetTexture(); + mozilla::gfx::DrawTarget *dt = static_cast(aSurface->GetData(&kDrawTarget)); + if (dt) { + dt->Flush(); + } + srcBuffer = aTarget->CreateSourceSurfaceFromNativeSurface(surf); + } +#endif + + if (!srcBuffer) { + nsRefPtr imgSurface = aSurface->GetAsImageSurface(); + + if (!imgSurface) { + imgSurface = new gfxImageSurface(aSurface->GetSize(), gfxASurface::FormatFromContent(aSurface->GetContentType())); + nsRefPtr ctx = new gfxContext(imgSurface); + ctx->SetSource(aSurface); + ctx->SetOperator(gfxContext::OPERATOR_SOURCE); + ctx->Paint(); + } + + srcBuffer = aTarget->CreateSourceSurfaceFromData(imgSurface->Data(), + IntSize(imgSurface->GetSize().width, imgSurface->GetSize().height), + imgSurface->Stride(), + format); + } + + srcBuffer->AddRef(); + aSurface->SetData(&kSourceSurface, srcBuffer, SourceBufferDestroy); + + return srcBuffer; +} + +RefPtr +gfxPlatform::GetScaledFontForFont(gfxFont *aFont) +{ + return NULL; +} + +already_AddRefed +gfxPlatform::GetThebesSurfaceForDrawTarget(DrawTarget *aTarget) +{ + // Don't know how to do this outside of Windows with D2D yet. + return NULL; +} + nsresult gfxPlatform::GetFontList(nsIAtom *aLangGroup, const nsACString& aGenericFamily, diff --git a/gfx/thebes/gfxPlatform.h b/gfx/thebes/gfxPlatform.h index de1d1496dde..f4b4a83ded2 100644 --- a/gfx/thebes/gfxPlatform.h +++ b/gfx/thebes/gfxPlatform.h @@ -66,6 +66,11 @@ class gfxTextRun; class nsIURI; class nsIAtom; +#include "gfx2DGlue.h" +#include "mozilla/RefPtr.h" + +extern cairo_user_data_key_t kDrawTarget; + // pref lang id's for font prefs // !!! needs to match the list of pref font.default.xx entries listed in all.js !!! // !!! don't use as bit mask, this may grow larger !!! @@ -167,6 +172,18 @@ public: virtual already_AddRefed OptimizeImage(gfxImageSurface *aSurface, gfxASurface::gfxImageFormat format); + virtual mozilla::RefPtr + CreateDrawTargetForSurface(gfxASurface *aSurface); + + virtual mozilla::RefPtr + GetSourceSurfaceForSurface(mozilla::gfx::DrawTarget *aTarget, gfxASurface *aSurface); + + virtual mozilla::RefPtr + GetScaledFontForFont(gfxFont *aFont); + + virtual already_AddRefed + GetThebesSurfaceForDrawTarget(mozilla::gfx::DrawTarget *aTarget); + /* * Font bits */ diff --git a/gfx/thebes/gfxPoint.h b/gfx/thebes/gfxPoint.h index 610ae4b0860..dfbf3594b94 100644 --- a/gfx/thebes/gfxPoint.h +++ b/gfx/thebes/gfxPoint.h @@ -39,8 +39,8 @@ #define GFX_POINT_H #include "nsMathUtils.h" -#include "mozilla/BaseSize.h" -#include "mozilla/BasePoint.h" +#include "mozilla/gfx/BaseSize.h" +#include "mozilla/gfx/BasePoint.h" #include "nsSize.h" #include "nsPoint.h" @@ -48,16 +48,16 @@ typedef nsIntSize gfxIntSize; -struct THEBES_API gfxSize : public mozilla::BaseSize { - typedef mozilla::BaseSize Super; +struct THEBES_API gfxSize : public mozilla::gfx::BaseSize { + typedef mozilla::gfx::BaseSize Super; gfxSize() : Super() {} gfxSize(gfxFloat aWidth, gfxFloat aHeight) : Super(aWidth, aHeight) {} gfxSize(const nsIntSize& aSize) : Super(aSize.width, aSize.height) {} }; -struct THEBES_API gfxPoint : public mozilla::BasePoint { - typedef mozilla::BasePoint Super; +struct THEBES_API gfxPoint : public mozilla::gfx::BasePoint { + typedef mozilla::gfx::BasePoint Super; gfxPoint() : Super() {} gfxPoint(gfxFloat aX, gfxFloat aY) : Super(aX, aY) {} diff --git a/gfx/thebes/gfxRect.h b/gfx/thebes/gfxRect.h index 91b1de0f06b..c63dd78386d 100644 --- a/gfx/thebes/gfxRect.h +++ b/gfx/thebes/gfxRect.h @@ -43,12 +43,12 @@ #include "gfxPoint.h" #include "gfxCore.h" #include "nsDebug.h" -#include "mozilla/BaseMargin.h" -#include "mozilla/BaseRect.h" +#include "mozilla/gfx/BaseMargin.h" +#include "mozilla/gfx/BaseRect.h" #include "nsRect.h" -struct gfxMargin : public mozilla::BaseMargin { - typedef mozilla::BaseMargin Super; +struct gfxMargin : public mozilla::gfx::BaseMargin { + typedef mozilla::gfx::BaseMargin Super; // Constructors gfxMargin() : Super() {} @@ -88,8 +88,8 @@ static inline mozilla::css::Corner operator++(mozilla::css::Corner& corner, int) } struct THEBES_API gfxRect : - public mozilla::BaseRect { - typedef mozilla::BaseRect Super; + public mozilla::gfx::BaseRect { + typedef mozilla::gfx::BaseRect Super; gfxRect() : Super() {} gfxRect(const gfxPoint& aPos, const gfxSize& aSize) : diff --git a/gfx/thebes/gfxWindowsPlatform.cpp b/gfx/thebes/gfxWindowsPlatform.cpp index ca717ee79da..c527839ff08 100644 --- a/gfx/thebes/gfxWindowsPlatform.cpp +++ b/gfx/thebes/gfxWindowsPlatform.cpp @@ -73,11 +73,15 @@ #include +using namespace mozilla::gfx; + #ifdef CAIRO_HAS_D2D_SURFACE #include "gfxD2DSurface.h" #include +#include "mozilla/gfx/2D.h" + #include "nsIMemoryReporter.h" #include "nsMemory.h" #endif @@ -402,8 +406,10 @@ gfxWindowsPlatform::VerifyD2DDevice(PRBool aAttemptForce) mD2DDevice = cairo_d2d_create_device(); } - if (mD2DDevice) + if (mD2DDevice) { reporter.SetSuccessful(); + mozilla::gfx::Factory::SetDirect3D10Device(cairo_d2d_device_get_device(mD2DDevice)); + } #endif } @@ -483,6 +489,48 @@ gfxWindowsPlatform::CreateOffscreenSurface(const gfxIntSize& size, return surf; } +RefPtr +gfxWindowsPlatform::GetScaledFontForFont(gfxFont *aFont) +{ + if(mUseDirectWrite) { + gfxDWriteFont *font = static_cast(aFont); + + NativeFont nativeFont; + nativeFont.mType = NATIVE_FONT_DWRITE_FONT_FACE; + nativeFont.mFont = font->GetFontFace(); + RefPtr scaledFont = + mozilla::gfx::Factory::CreateScaledFontForNativeFont(nativeFont, font->GetAdjustedSize()); + + return scaledFont; + } +} + +already_AddRefed +gfxWindowsPlatform::GetThebesSurfaceForDrawTarget(DrawTarget *aTarget) +{ +#ifdef XP_WIN + if (aTarget->GetType() == BACKEND_DIRECT2D) { + RefPtr texture = + static_cast(aTarget->GetNativeSurface(NATIVE_SURFACE_D3D10_TEXTURE)); + + if (!texture) { + return gfxPlatform::GetThebesSurfaceForDrawTarget(aTarget); + } + + aTarget->Flush(); + + nsRefPtr surf = + new gfxD2DSurface(texture, ContentForFormat(aTarget->GetFormat())); + + surf->SetData(&kDrawTarget, aTarget, NULL); + + return surf.forget(); + } +#endif + + return gfxPlatform::GetThebesSurfaceForDrawTarget(aTarget); +} + nsresult gfxWindowsPlatform::GetFontList(nsIAtom *aLangGroup, const nsACString& aGenericFamily, diff --git a/gfx/thebes/gfxWindowsPlatform.h b/gfx/thebes/gfxWindowsPlatform.h index a70ffea8bc6..9684e317e29 100644 --- a/gfx/thebes/gfxWindowsPlatform.h +++ b/gfx/thebes/gfxWindowsPlatform.h @@ -127,6 +127,10 @@ public: already_AddRefed CreateOffscreenSurface(const gfxIntSize& size, gfxASurface::gfxContentType contentType); + virtual mozilla::RefPtr + GetScaledFontForFont(gfxFont *aFont); + virtual already_AddRefed + GetThebesSurfaceForDrawTarget(mozilla::gfx::DrawTarget *aTarget); enum RenderMode { /* Use GDI and windows surfaces */ diff --git a/ipc/glue/Shmem.cpp b/ipc/glue/Shmem.cpp index d8ab314525e..6fe37587bbf 100644 --- a/ipc/glue/Shmem.cpp +++ b/ipc/glue/Shmem.cpp @@ -45,6 +45,7 @@ #include "SharedMemorySysV.h" #include "nsAutoPtr.h" +#include "mozilla/unused.h" namespace mozilla { @@ -356,7 +357,10 @@ Shmem::AssertInvariants() const // trigger SIGSEGV char checkMappingFront = *reinterpret_cast(mData); char checkMappingBack = *(reinterpret_cast(mData) + mSize - 1); - checkMappingFront = checkMappingBack; // avoid "unused" warnings + + // avoid "unused" warnings for these variables: + unused << checkMappingFront; + unused << checkMappingBack; } void diff --git a/js/src/xpconnect/src/dom_quickstubs.qsconf b/js/src/xpconnect/src/dom_quickstubs.qsconf index 9af5fd164aa..e8fb2d4ac06 100644 --- a/js/src/xpconnect/src/dom_quickstubs.qsconf +++ b/js/src/xpconnect/src/dom_quickstubs.qsconf @@ -780,6 +780,10 @@ customMethodCalls = { ' rv = nsGenericElement::doQuerySelectorAll(self, ' 'arg0, getter_AddRefs(result));' }, + 'nsIDOMNode_Normalize': { + 'thisType': 'nsINode', + 'canFail': False + }, 'nsIDOMNode_GetBaseURI': { 'thisType': 'nsINode', 'canFail': False diff --git a/js/src/xpconnect/src/nsXPConnect.cpp b/js/src/xpconnect/src/nsXPConnect.cpp index 8d76ea09b18..359b00c7256 100644 --- a/js/src/xpconnect/src/nsXPConnect.cpp +++ b/js/src/xpconnect/src/nsXPConnect.cpp @@ -747,7 +747,7 @@ nsXPConnect::Traverse(void *p, nsCycleCollectionTraversalCallback &cb) } } - CCNodeType type; + PRBool isMarked; #ifdef DEBUG_CC // Note that the conditions under which we specify GCMarked vs. @@ -765,14 +765,13 @@ nsXPConnect::Traverse(void *p, nsCycleCollectionTraversalCallback &cb) // ExplainLiveExpectedGarbage codepath PLDHashEntryHdr* entry = PL_DHashTableOperate(&mJSRoots, p, PL_DHASH_LOOKUP); - type = markJSObject || PL_DHASH_ENTRY_IS_BUSY(entry) ? GCMarked : - GCUnmarked; + isMarked = markJSObject || PL_DHASH_ENTRY_IS_BUSY(entry); } else #endif { // Normal codepath (matches non-DEBUG_CC codepath). - type = !markJSObject && xpc_IsGrayGCThing(p) ? GCUnmarked : GCMarked; + isMarked = markJSObject || !xpc_IsGrayGCThing(p); } if (cb.WantDebugInfo()) { @@ -845,19 +844,19 @@ nsXPConnect::Traverse(void *p, nsCycleCollectionTraversalCallback &cb) char fullname[100]; JS_snprintf(fullname, sizeof(fullname), "%s (global=%p)", name, global); - cb.DescribeNode(type, 0, sizeof(JSObject), fullname); + cb.DescribeGCedNode(isMarked, sizeof(JSObject), fullname); } else { - cb.DescribeNode(type, 0, sizeof(JSObject), name); + cb.DescribeGCedNode(isMarked, sizeof(JSObject), name); } } else { - cb.DescribeNode(type, 0, sizeof(JSObject), "JS Object"); + cb.DescribeGCedNode(isMarked, sizeof(JSObject), "JS Object"); } // There's no need to trace objects that have already been marked by the JS // GC. Any JS objects hanging from them will already be marked. Only do this // if DEBUG_CC is not defined, else we do want to know about all JS objects // to get better graphs and explanations. - if(!cb.WantAllTraces() && type == GCMarked) + if(!cb.WantAllTraces() && isMarked) return NS_OK; TraversalTracer trc(cb); @@ -932,8 +931,7 @@ public: // edges will ensure that any cycles this context is in won't be // collected. unsigned refCount = nsXPConnect::GetXPConnect()->GetOutstandingRequests(cx) + 1; - - cb.DescribeNode(RefCounted, refCount, sizeof(JSContext), "JSContext"); + NS_IMPL_CYCLE_COLLECTION_DESCRIBE(JSContext, refCount) NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "[global object]"); if (cx->globalObject) { cb.NoteScriptChild(nsIProgrammingLanguage::JAVASCRIPT, diff --git a/js/src/xpconnect/src/xpcwrappedjs.cpp b/js/src/xpconnect/src/xpcwrappedjs.cpp index a86af154e27..c2e0e4776c4 100644 --- a/js/src/xpconnect/src/xpcwrappedjs.cpp +++ b/js/src/xpconnect/src/xpcwrappedjs.cpp @@ -67,10 +67,9 @@ NS_CYCLE_COLLECTION_CLASSNAME(nsXPCWrappedJS)::Traverse tmp->GetClass()->GetInterfaceName()); else JS_snprintf(name, sizeof(name), "nsXPCWrappedJS"); - cb.DescribeNode(RefCounted, refcnt, sizeof(nsXPCWrappedJS), name); + cb.DescribeRefCountedNode(refcnt, sizeof(nsXPCWrappedJS), name); } else { - cb.DescribeNode(RefCounted, refcnt, sizeof(nsXPCWrappedJS), - "nsXPCWrappedJS"); + NS_IMPL_CYCLE_COLLECTION_DESCRIBE(nsXPCWrappedJS, refcnt) } // nsXPCWrappedJS keeps its own refcount artificially at or above 1, see the diff --git a/js/src/xpconnect/src/xpcwrappednative.cpp b/js/src/xpconnect/src/xpcwrappednative.cpp index be27a7856e8..c19a84613a1 100644 --- a/js/src/xpconnect/src/xpcwrappednative.cpp +++ b/js/src/xpconnect/src/xpcwrappednative.cpp @@ -115,11 +115,10 @@ NS_CYCLE_COLLECTION_CLASSNAME(XPCWrappedNative)::Traverse(void *p, else JS_snprintf(name, sizeof(name), "XPCWrappedNative"); - cb.DescribeNode(RefCounted, tmp->mRefCnt.get(), - sizeof(XPCWrappedNative), name); + cb.DescribeRefCountedNode(tmp->mRefCnt.get(), + sizeof(XPCWrappedNative), name); } else { - cb.DescribeNode(RefCounted, tmp->mRefCnt.get(), - sizeof(XPCWrappedNative), "XPCWrappedNative"); + NS_IMPL_CYCLE_COLLECTION_DESCRIBE(XPCWrappedNative, tmp->mRefCnt.get()) } if(tmp->mRefCnt.get() > 1) { diff --git a/layout/base/nsDocumentViewer.cpp b/layout/base/nsDocumentViewer.cpp index 643648b4531..8016ff1607f 100644 --- a/layout/base/nsDocumentViewer.cpp +++ b/layout/base/nsDocumentViewer.cpp @@ -3410,37 +3410,20 @@ DocumentViewerImpl::GetPopupLinkNode(nsIDOMNode** aNode) // find out if we have a link in our ancestry while (node) { - // are we an anchor? - nsCOMPtr anchor(do_QueryInterface(node)); - nsCOMPtr area; - nsCOMPtr link; - nsAutoString xlinkType; - if (!anchor) { - // area? - area = do_QueryInterface(node); - if (!area) { - // link? - link = do_QueryInterface(node); - if (!link) { - // XLink? - nsCOMPtr element(do_QueryInterface(node)); - if (element) { - element->GetAttributeNS(NS_LITERAL_STRING("http://www.w3.org/1999/xlink"),NS_LITERAL_STRING("type"),xlinkType); - } - } + nsCOMPtr content(do_QueryInterface(node)); + if (content) { + nsCOMPtr hrefURI = content->GetHrefURI(); + if (hrefURI) { + *aNode = node; + NS_IF_ADDREF(*aNode); // addref + return NS_OK; } } - if (anchor || area || link || xlinkType.EqualsLiteral("simple")) { - *aNode = node; - NS_IF_ADDREF(*aNode); // addref - return NS_OK; - } - else { - // if not, get our parent and keep trying... - nsCOMPtr parentNode; - node->GetParentNode(getter_AddRefs(parentNode)); - node = parentNode; - } + + // get our parent and keep trying... + nsCOMPtr parentNode; + node->GetParentNode(getter_AddRefs(parentNode)); + node = parentNode; } // if we have no node, fail diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index feb63a25c39..91aa9e605e6 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -4365,66 +4365,26 @@ nsresult PresShell::GetLinkLocation(nsIDOMNode* aNode, nsAString& aLocationStrin #endif NS_ENSURE_ARG_POINTER(aNode); - nsresult rv; - nsAutoString anchorText; - static const char strippedChars[] = "\t\r\n"; - // are we an anchor? - nsCOMPtr anchor(do_QueryInterface(aNode)); - nsCOMPtr area; - nsCOMPtr link; - nsAutoString xlinkType; - if (anchor) { - rv = anchor->GetHref(anchorText); - NS_ENSURE_SUCCESS(rv, rv); - } else { - // area? - area = do_QueryInterface(aNode); - if (area) { - rv = area->GetHref(anchorText); + nsCOMPtr content(do_QueryInterface(aNode)); + if (content) { + nsCOMPtr hrefURI = content->GetHrefURI(); + if (hrefURI) { + nsCAutoString specUTF8; + nsresult rv = hrefURI->GetSpec(specUTF8); NS_ENSURE_SUCCESS(rv, rv); - } else { - // link? - link = do_QueryInterface(aNode); - if (link) { - rv = link->GetHref(anchorText); - NS_ENSURE_SUCCESS(rv, rv); - } else { - // Xlink? - nsCOMPtr element(do_QueryInterface(aNode)); - if (element) { - NS_NAMED_LITERAL_STRING(xlinkNS,"http://www.w3.org/1999/xlink"); - element->GetAttributeNS(xlinkNS,NS_LITERAL_STRING("type"),xlinkType); - if (xlinkType.EqualsLiteral("simple")) { - element->GetAttributeNS(xlinkNS,NS_LITERAL_STRING("href"),anchorText); - if (!anchorText.IsEmpty()) { - // Resolve the full URI using baseURI property - nsCOMPtr node = do_QueryInterface(aNode); - NS_ENSURE_TRUE(node, NS_ERROR_UNEXPECTED); - nsCOMPtr baseURI = node->GetBaseURI(); + nsAutoString anchorText; + CopyUTF8toUTF16(specUTF8, anchorText); - nsCAutoString spec; - rv = baseURI->Resolve(NS_ConvertUTF16toUTF8(anchorText),spec); - NS_ENSURE_SUCCESS(rv, rv); - - CopyUTF8toUTF16(spec, anchorText); - } - } - } - } + // Remove all the '\t', '\r' and '\n' from 'anchorText' + static const char strippedChars[] = "\t\r\n"; + anchorText.StripChars(strippedChars); + aLocationString = anchorText; + return NS_OK; } } - if (anchor || area || link || xlinkType.EqualsLiteral("simple")) { - //Remove all the '\t', '\r' and '\n' from 'anchorText' - anchorText.StripChars(strippedChars); - - aLocationString = anchorText; - - return NS_OK; - } - // if no link, fail. return NS_ERROR_FAILURE; } diff --git a/layout/build/nsLayoutCID.h b/layout/build/nsLayoutCID.h index d13349429a8..b18ccd4445c 100644 --- a/layout/build/nsLayoutCID.h +++ b/layout/build/nsLayoutCID.h @@ -91,6 +91,10 @@ #define NS_CANVASRENDERINGCONTEXT2D_CID \ { 0xa35d1cd4, 0xc505, 0x4d2d, { 0xa0, 0xf9, 0xae, 0xf0, 0x0b, 0x7c, 0xe5, 0xa5 } } +// {9052bb12-79b0-4bdd-8e60-7bf078026b6d} +#define NS_CANVASRENDERINGCONTEXT2DAZURE_CID \ +{0x9052bb12, 0x79b0, 0x4bdd, {0x8e, 0x60, 0x7b, 0xf0, 0x78, 0x02, 0x6b, 0x6d}} + // {2fe88332-31c6-4829-b247-a07d8a73e80f} #define NS_CANVASRENDERINGCONTEXTWEBGL_CID \ { 0x2fe88332, 0x31c6, 0x4829, { 0xb2, 0x47, 0xa0, 0x7d, 0x8a, 0x7e, 0xe8, 0x0fe } } diff --git a/layout/build/nsLayoutModule.cpp b/layout/build/nsLayoutModule.cpp index 931fce2fa3b..53aa9bc4db2 100644 --- a/layout/build/nsLayoutModule.cpp +++ b/layout/build/nsLayoutModule.cpp @@ -771,6 +771,7 @@ NS_DEFINE_NAMED_CID(NS_HTMLOPTIONELEMENT_CID); NS_DEFINE_NAMED_CID(NS_HTMLAUDIOELEMENT_CID); #endif NS_DEFINE_NAMED_CID(NS_CANVASRENDERINGCONTEXT2D_CID); +NS_DEFINE_NAMED_CID(NS_CANVASRENDERINGCONTEXT2DAZURE_CID); NS_DEFINE_NAMED_CID(NS_CANVASRENDERINGCONTEXTWEBGL_CID); NS_DEFINE_NAMED_CID(NS_TEXT_ENCODER_CID); NS_DEFINE_NAMED_CID(NS_HTMLCOPY_TEXT_ENCODER_CID); diff --git a/layout/generic/crashtests/667025.html b/layout/generic/crashtests/667025.html new file mode 100644 index 00000000000..29ef3d32b5e --- /dev/null +++ b/layout/generic/crashtests/667025.html @@ -0,0 +1,22 @@ + + + + + x y + diff --git a/layout/generic/crashtests/crashtests.list b/layout/generic/crashtests/crashtests.list index 1a4ffb6296a..8aa74fa2321 100644 --- a/layout/generic/crashtests/crashtests.list +++ b/layout/generic/crashtests/crashtests.list @@ -364,3 +364,4 @@ load text-overflow-form-elements.html load text-overflow-iframe.html load text-overflow-bug666751-1.html load text-overflow-bug666751-2.html +load 667025.html diff --git a/layout/generic/nsContainerFrame.cpp b/layout/generic/nsContainerFrame.cpp index 3098ba9d7cd..8e45b5a7718 100644 --- a/layout/generic/nsContainerFrame.cpp +++ b/layout/generic/nsContainerFrame.cpp @@ -219,9 +219,8 @@ nsContainerFrame::RemoveFrame(nsIAtom* aListName, generateReflowCommand = PR_FALSE; } #endif + nsContainerFrame* parent = static_cast(aOldFrame->GetParent()); while (aOldFrame) { - nsContainerFrame* parent = - static_cast(aOldFrame->GetParent()); // When the parent is an inline frame we have a simple task - just // remove the frame from its parents list and generate a reflow // command. @@ -238,17 +237,15 @@ nsContainerFrame::RemoveFrame(nsIAtom* aListName, aOldFrame->Destroy(); } } else { - // We don't want to simply make a recursive call here because with - // thousands of continuations it would exhaust the stack. Instead, - // unhook aOldFrame from the continuation chain, destroy it, and - // continue the loop. - if (oldFrameNextContinuation) { - oldFrameNextContinuation->SetPrevContinuation(nsnull); - aOldFrame->SetNextContinuation(nsnull); - } - parent->RemoveFrame(aListName, aOldFrame); + // This recursive call takes care of all continuations after aOldFrame, + // so we don't need to loop anymore. + parent->RemoveFrame(nsnull, aOldFrame); + break; } aOldFrame = oldFrameNextContinuation; + if (aOldFrame) { + parent = static_cast(aOldFrame->GetParent()); + } } if (generateReflowCommand) { diff --git a/layout/mathml/mathml.css b/layout/mathml/mathml.css index 0268ee895dc..37d6cbd946e 100644 --- a/layout/mathml/mathml.css +++ b/layout/mathml/mathml.css @@ -99,6 +99,13 @@ math[display="inline"] { font-weight: normal; } +/**************************************************************************/ +/* Links */ +/**************************************************************************/ +:-moz-any-link { + text-decoration: none !important; +} + /**************************************************************************/ /* attributes common to all tags */ /**************************************************************************/ diff --git a/layout/reftests/bugs/624359-1-notref.html b/layout/reftests/bugs/624359-1-notref.html deleted file mode 100644 index e8479c563bc..00000000000 --- a/layout/reftests/bugs/624359-1-notref.html +++ /dev/null @@ -1,38 +0,0 @@ - - - -Bug 624359 - - - - -
Cluster in mozTextAlongPath:
- - - diff --git a/layout/reftests/bugs/624359-1.html b/layout/reftests/bugs/624359-1.html deleted file mode 100644 index 01d7ced3e7d..00000000000 --- a/layout/reftests/bugs/624359-1.html +++ /dev/null @@ -1,41 +0,0 @@ - - - -Bug 624359 - - - - -
Cluster in mozTextAlongPath:
- - - diff --git a/layout/reftests/bugs/reftest.list b/layout/reftests/bugs/reftest.list index bfe96087a77..9b586c953fc 100644 --- a/layout/reftests/bugs/reftest.list +++ b/layout/reftests/bugs/reftest.list @@ -1614,7 +1614,6 @@ fails-if(Android) HTTP(..) == 619511-1.html 619511-1-ref.html random-if(winWidget) == 621918-1.svg 621918-1-ref.svg # 1-pixel diacritic positioning discrepancy in rotated text (may depend on platform fonts) random-if(winWidget) HTTP(..) == 621918-2.svg 621918-2-ref.svg # same 1px issue as above, and HTTP(..) for filters.svg, used to mask antialiasing issues where glyphs touch == 622585-1.html 622585-1-ref.html -HTTP(..) != 624359-1.html 624359-1-notref.html # http(..) for @font-face, to ensure consistent behavior fails-if(Android) == 625409-1.html 625409-1-ref.html == 627393-1.html about:blank == 630835-1.html about:blank diff --git a/layout/reftests/image-element/canvas-outside-document-invalidate-02.html b/layout/reftests/image-element/canvas-outside-document-invalidate-02.html index 0047ff810b0..a24e398a2bd 100644 --- a/layout/reftests/image-element/canvas-outside-document-invalidate-02.html +++ b/layout/reftests/image-element/canvas-outside-document-invalidate-02.html @@ -18,10 +18,11 @@ var ctx = canvas.getContext('2d'); ctx.fillStyle = "red"; ctx.fillRect(0, 0, 1, 1); window.addEventListener("MozReftestInvalidate", function () { - ctx.fillStyle = "white"; - ctx.mozTextStyle = "50px bold Arial"; + ctx.strokeStyle = "white"; + ctx.font = "50px bold Arial"; ctx.translate(-8, 18); - ctx.mozDrawText("•"); + ctx.lineWidth = 50; + ctx.strokeText("•", 0, 0); document.documentElement.className = ""; }, false); diff --git a/layout/reftests/image-element/reftest.list b/layout/reftests/image-element/reftest.list index 2769f929841..4bf5d142c90 100644 --- a/layout/reftests/image-element/reftest.list +++ b/layout/reftests/image-element/reftest.list @@ -5,7 +5,7 @@ fails-if(Android) == canvas-outside-document.html canvas-inside-document.html == mozsetimageelement-02.html about:blank == image-outside-document-invalidate.html about:blank == canvas-outside-document-invalidate-01.html about:blank -== canvas-outside-document-invalidate-02.html about:blank +fails-if(cocoaWidget) == canvas-outside-document-invalidate-02.html about:blank # See bug 666800 == element-paint-simple.html element-paint-simple-ref.html == element-paint-repeated.html element-paint-repeated-ref.html == element-paint-recursion.html element-paint-recursion-ref.html diff --git a/layout/reftests/mathml/link-1.xhtml b/layout/reftests/mathml/link-1.xhtml new file mode 100644 index 00000000000..13ab701890b --- /dev/null +++ b/layout/reftests/mathml/link-1.xhtml @@ -0,0 +1,12 @@ + + + + Test XLink + + + + MathML Link + + + diff --git a/layout/reftests/mathml/link-ref.xhtml b/layout/reftests/mathml/link-ref.xhtml new file mode 100644 index 00000000000..a5ac817f184 --- /dev/null +++ b/layout/reftests/mathml/link-ref.xhtml @@ -0,0 +1,11 @@ + + + + Test link + + + + MathML Link + + + diff --git a/layout/reftests/mathml/reftest.list b/layout/reftests/mathml/reftest.list index cd8540692f7..5496de575fc 100644 --- a/layout/reftests/mathml/reftest.list +++ b/layout/reftests/mathml/reftest.list @@ -62,3 +62,4 @@ fails == mstyle-5.xhtml mstyle-5-ref.xhtml # See bug 569125#c29 == math-as-mstyle-1.xhtml math-as-mstyle-1-ref.xhtml == mfrac-linethickness-1.xhtml mfrac-linethickness-1-ref.xhtml == mathml-negativespace.html mathml-negativespace-ref.html +!= link-1.xhtml link-ref.xhtml diff --git a/layout/tables/celldata.h b/layout/tables/celldata.h index 89ba17a5e70..09d50715123 100644 --- a/layout/tables/celldata.h +++ b/layout/tables/celldata.h @@ -39,7 +39,7 @@ #include "nsISupports.h" #include "nsCoord.h" -#include "gfxCore.h" +#include "mozilla/gfx/Types.h" class nsTableCellFrame; class nsCellMap; diff --git a/layout/tools/reftest/runreftest.py b/layout/tools/reftest/runreftest.py index ee2d522ecd1..2b3c0900827 100644 --- a/layout/tools/reftest/runreftest.py +++ b/layout/tools/reftest/runreftest.py @@ -133,7 +133,7 @@ class RefTest(object): def cleanup(self, profileDir): if profileDir: - shutil.rmtree(profileDir) + shutil.rmtree(profileDir, True) def runTests(self, testPath, options): debuggerInfo = getDebuggerInfo(self.oldcwd, options.debugger, options.debuggerArgs, diff --git a/layout/xul/base/public/nsIMenuFrame.h b/layout/xul/base/public/nsIMenuFrame.h index aee0ec847e5..3c65ba8cbca 100644 --- a/layout/xul/base/public/nsIMenuFrame.h +++ b/layout/xul/base/public/nsIMenuFrame.h @@ -40,6 +40,12 @@ #include "nsQueryFrame.h" +enum nsMenuListType { + eNotMenuList, + eReadonlyMenuList, + eEditableMenuList +}; + // this interface exists solely because native themes need to call into it. // Only menu frames should implement it @@ -52,6 +58,7 @@ public: virtual PRBool IsMenu() = 0; virtual PRBool IsOnMenuBar() = 0; virtual PRBool IsOnActiveMenuBar() = 0; + virtual nsMenuListType GetParentMenuListType() = 0; }; #endif diff --git a/layout/xul/base/src/nsMenuFrame.cpp b/layout/xul/base/src/nsMenuFrame.cpp index a0180a6ebed..63027319468 100644 --- a/layout/xul/base/src/nsMenuFrame.cpp +++ b/layout/xul/base/src/nsMenuFrame.cpp @@ -871,6 +871,24 @@ nsMenuFrame::IsMenu() return mIsMenu; } +nsMenuListType +nsMenuFrame::GetParentMenuListType() +{ + if (mMenuParent && mMenuParent->IsMenu()) { + nsMenuPopupFrame* popupFrame = static_cast(mMenuParent); + nsIFrame* parentMenu = popupFrame->GetParent(); + if (parentMenu) { + nsCOMPtr menulist = do_QueryInterface(parentMenu->GetContent()); + if (menulist) { + PRBool isEditable = PR_FALSE; + menulist->GetEditable(&isEditable); + return isEditable ? eEditableMenuList : eReadonlyMenuList; + } + } + } + return eNotMenuList; +} + nsresult nsMenuFrame::Notify(nsITimer* aTimer) { @@ -1198,18 +1216,9 @@ nsMenuFrame::ShouldBlink() return PR_FALSE; // Don't blink in editable menulists. - if (mMenuParent && mMenuParent->IsMenu()) { - nsMenuPopupFrame* popupFrame = static_cast(mMenuParent); - nsIFrame* parentMenu = popupFrame->GetParent(); - if (parentMenu) { - nsCOMPtr menulist = do_QueryInterface(parentMenu->GetContent()); - if (menulist) { - PRBool isEditable = PR_FALSE; - menulist->GetEditable(&isEditable); - return !isEditable; - } - } - } + if (GetParentMenuListType() == eEditableMenuList) + return PR_FALSE; + return PR_TRUE; } diff --git a/layout/xul/base/src/nsMenuFrame.h b/layout/xul/base/src/nsMenuFrame.h index d6a69ae0a4c..fdc34c614f8 100644 --- a/layout/xul/base/src/nsMenuFrame.h +++ b/layout/xul/base/src/nsMenuFrame.h @@ -189,6 +189,7 @@ public: virtual PRBool IsOnActiveMenuBar() { return IsOnMenuBar() && mMenuParent->IsActive(); } virtual PRBool IsOpen(); virtual PRBool IsMenu(); + virtual nsMenuListType GetParentMenuListType(); PRBool IsDisabled(); void ToggleMenuState(); diff --git a/modules/libpref/src/init/all.js b/modules/libpref/src/init/all.js index da1ae77e0cf..645700e1497 100644 --- a/modules/libpref/src/init/all.js +++ b/modules/libpref/src/init/all.js @@ -212,6 +212,10 @@ pref("gfx.font_rendering.directwrite.enabled", false); pref("gfx.font_rendering.directwrite.use_gdi_table_loading", true); #endif +#ifdef XP_WIN +pref("gfx.canvas.azure.enabled", true); +#endif + pref("accessibility.browsewithcaret", false); pref("accessibility.warn_on_browsewithcaret", true); @@ -276,6 +280,10 @@ pref("toolkit.scrollbox.clickToScroll.scrollDelay", 150); // Telemetry pref("toolkit.telemetry.enabled", false); pref("toolkit.telemetry.server", "https://data.mozilla.com"); +// Telemetry server owner. Please change if you set toolkit.telemetry.server to a different server +pref("toolkit.telemetry.server_owner", "Mozilla"); +// Information page about telemetry (temporary ; will be about:telemetry in the end) +pref("toolkit.telemetry.infoURL", "http://www.mozilla.com/legal/privacy/firefox.html#telemetry"); // view source pref("view_source.syntax_highlight", true); diff --git a/parser/htmlparser/src/nsScanner.cpp b/parser/htmlparser/src/nsScanner.cpp index d88229386ea..fb93b6cd8de 100644 --- a/parser/htmlparser/src/nsScanner.cpp +++ b/parser/htmlparser/src/nsScanner.cpp @@ -301,14 +301,13 @@ nsresult nsScanner::Append(const nsAString& aBuffer) { nsresult nsScanner::Append(const char* aBuffer, PRUint32 aLen, nsIRequest *aRequest) { - nsresult res=NS_OK; - PRUnichar *unichars, *start; + nsresult res = NS_OK; if (mUnicodeDecoder) { PRInt32 unicharBufLen = 0; mUnicodeDecoder->GetMaxLength(aBuffer, aLen, &unicharBufLen); nsScannerString::Buffer* buffer = nsScannerString::AllocBuffer(unicharBufLen + 1); NS_ENSURE_TRUE(buffer,NS_ERROR_OUT_OF_MEMORY); - start = unichars = buffer->DataStart(); + PRUnichar *unichars = buffer->DataStart(); PRInt32 totalChars = 0; PRInt32 unicharLength = unicharBufLen; diff --git a/security/manager/ssl/src/nsCertVerificationThread.cpp b/security/manager/ssl/src/nsCertVerificationThread.cpp index b70d448ce69..94165869ea8 100644 --- a/security/manager/ssl/src/nsCertVerificationThread.cpp +++ b/security/manager/ssl/src/nsCertVerificationThread.cpp @@ -132,14 +132,15 @@ void nsCertVerificationThread::Run(void) { MutexAutoLock threadLock(verification_thread_singleton->mMutex); - - while (!mExitRequested && (0 == verification_thread_singleton->mJobQ.GetSize())) { + + while (!exitRequested(threadLock) && + 0 == verification_thread_singleton->mJobQ.GetSize()) { // no work to do ? let's wait a moment mCond.Wait(); } - if (mExitRequested) + if (exitRequested(threadLock)) break; job = static_cast(mJobQ.PopFront()); @@ -160,6 +161,7 @@ void nsCertVerificationThread::Run(void) static_cast(mJobQ.PopFront()); delete job; } + postStoppedEventToMainThread(threadLock); } } diff --git a/security/manager/ssl/src/nsNSSCallbacks.cpp b/security/manager/ssl/src/nsNSSCallbacks.cpp index 4078bca1552..a23cbb05262 100644 --- a/security/manager/ssl/src/nsNSSCallbacks.cpp +++ b/security/manager/ssl/src/nsNSSCallbacks.cpp @@ -436,7 +436,7 @@ nsNSSHttpRequestSession::internal_send_receive_attempt(PRBool &retryable_error, if (!request_canceled) { - PRBool wantExit = nsSSLThread::exitRequested(); + PRBool wantExit = nsSSLThread::stoppedOrStopping(); PRBool timeout = (PRIntervalTime)(PR_IntervalNow() - start_time) > mTimeoutInterval; diff --git a/security/manager/ssl/src/nsNSSComponent.cpp b/security/manager/ssl/src/nsNSSComponent.cpp index 8f162b3eeda..bb8ad4984da 100644 --- a/security/manager/ssl/src/nsNSSComponent.cpp +++ b/security/manager/ssl/src/nsNSSComponent.cpp @@ -392,7 +392,8 @@ nsNSSComponent::nsNSSComponent() mIsNetworkDown = PR_FALSE; } -nsNSSComponent::~nsNSSComponent() +void +nsNSSComponent::deleteBackgroundThreads() { if (mSSLThread) { @@ -400,16 +401,43 @@ nsNSSComponent::~nsNSSComponent() delete mSSLThread; mSSLThread = nsnull; } - if (mCertVerificationThread) { mCertVerificationThread->requestExit(); delete mCertVerificationThread; mCertVerificationThread = nsnull; } +} +void +nsNSSComponent::createBackgroundThreads() +{ + NS_ASSERTION(mSSLThread == nsnull, "SSL thread already created."); + NS_ASSERTION(mCertVerificationThread == nsnull, + "Cert verification thread already created."); + + mSSLThread = new nsSSLThread; + nsresult rv = mSSLThread->startThread(); + if (NS_FAILED(rv)) { + delete mSSLThread; + mSSLThread = nsnull; + return; + } + + mCertVerificationThread = new nsCertVerificationThread; + rv = mCertVerificationThread->startThread(); + if (NS_FAILED(rv)) { + delete mCertVerificationThread; + mCertVerificationThread = nsnull; + } +} + +nsNSSComponent::~nsNSSComponent() +{ PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsNSSComponent::dtor\n")); + deleteBackgroundThreads(); + if (mUpdateTimerInitialized) { { MutexAutoLock lock(mCrlTimerLock); @@ -2007,13 +2035,7 @@ nsNSSComponent::Init() if (mClientAuthRememberService) mClientAuthRememberService->Init(); - mSSLThread = new nsSSLThread(); - if (mSSLThread) - mSSLThread->startThread(); - mCertVerificationThread = new nsCertVerificationThread(); - if (mCertVerificationThread) - mCertVerificationThread->startThread(); - + createBackgroundThreads(); if (!mSSLThread || !mCertVerificationThread) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("NSS init, could not create threads\n")); @@ -2625,14 +2647,9 @@ nsNSSComponent::DoProfileBeforeChange(nsISupports* aSubject) void nsNSSComponent::DoProfileChangeNetRestore() { - delete mSSLThread; - mSSLThread = new nsSSLThread(); - if (mSSLThread) - mSSLThread->startThread(); - delete mCertVerificationThread; - mCertVerificationThread = new nsCertVerificationThread(); - if (mCertVerificationThread) - mCertVerificationThread->startThread(); + /* XXX this doesn't work well, since nothing expects null pointers */ + deleteBackgroundThreads(); + createBackgroundThreads(); mIsNetworkDown = PR_FALSE; } diff --git a/security/manager/ssl/src/nsNSSComponent.h b/security/manager/ssl/src/nsNSSComponent.h index 17d0b9cc350..5a971c5ecca 100644 --- a/security/manager/ssl/src/nsNSSComponent.h +++ b/security/manager/ssl/src/nsNSSComponent.h @@ -357,8 +357,12 @@ private: nsNSSShutDownList *mShutdownObjectList; SmartCardThreadList *mThreadList; PRBool mIsNetworkDown; + + void deleteBackgroundThreads(); + void createBackgroundThreads(); nsSSLThread *mSSLThread; nsCertVerificationThread *mCertVerificationThread; + nsNSSHttpInterface mHttpForNSS; nsRefPtr mClientAuthRememberService; nsRefPtr mDefaultCERTValInParam; diff --git a/security/manager/ssl/src/nsNSSIOLayer.cpp b/security/manager/ssl/src/nsNSSIOLayer.cpp index c89030d74b3..53d02d2890f 100644 --- a/security/manager/ssl/src/nsNSSIOLayer.cpp +++ b/security/manager/ssl/src/nsNSSIOLayer.cpp @@ -360,7 +360,7 @@ nsNSSSocketInfo::EnsureDocShellDependentStuffKnown() if (mDocShellDependentStuffKnown) return NS_OK; - if (!mCallbacks || nsSSLThread::exitRequested()) + if (!mCallbacks || nsSSLThread::stoppedOrStopping()) return NS_ERROR_FAILURE; mDocShellDependentStuffKnown = PR_TRUE; @@ -567,7 +567,7 @@ NS_IMETHODIMP nsNSSSocketInfo::GetInterface(const nsIID & uuid, void * *result) rv = ir->GetInterface(uuid, result); } else { - if (nsSSLThread::exitRequested()) + if (nsSSLThread::stoppedOrStopping()) return NS_ERROR_FAILURE; nsCOMPtr proxiedCallbacks; @@ -1413,7 +1413,7 @@ displayAlert(nsAFlatString &formattedString, nsNSSSocketInfo *infoObject) // The interface requestor object may not be safe, so proxy the call to get // the nsIPrompt. - if (nsSSLThread::exitRequested()) + if (nsSSLThread::stoppedOrStopping()) return NS_ERROR_FAILURE; nsCOMPtr proxiedCallbacks; @@ -1450,7 +1450,7 @@ nsHandleSSLError(nsNSSSocketInfo *socketInfo, PRInt32 err) return NS_OK; } - if (nsSSLThread::exitRequested()) { + if (nsSSLThread::stoppedOrStopping()) { return NS_ERROR_FAILURE; } @@ -3354,7 +3354,7 @@ nsNSSBadCertHandler(void *arg, PRFileDesc *sslSocket) if (!infoObject) return SECFailure; - if (nsSSLThread::exitRequested()) + if (nsSSLThread::stoppedOrStopping()) return cancel_and_failure(infoObject); CERTCertificate *peerCert = nsnull; diff --git a/security/manager/ssl/src/nsPSMBackgroundThread.cpp b/security/manager/ssl/src/nsPSMBackgroundThread.cpp index 592e31d114b..012ceef3759 100644 --- a/security/manager/ssl/src/nsPSMBackgroundThread.cpp +++ b/security/manager/ssl/src/nsPSMBackgroundThread.cpp @@ -36,6 +36,7 @@ * ***** END LICENSE BLOCK ***** */ #include "nsPSMBackgroundThread.h" +#include "nsThreadUtils.h" using namespace mozilla; @@ -49,7 +50,7 @@ nsPSMBackgroundThread::nsPSMBackgroundThread() : mThreadHandle(nsnull), mMutex("nsPSMBackgroundThread.mMutex"), mCond(mMutex, "nsPSMBackgroundThread.mCond"), - mExitRequested(PR_FALSE) + mExitState(ePSMThreadRunning) { } @@ -70,19 +71,48 @@ nsPSMBackgroundThread::~nsPSMBackgroundThread() { } +PRBool +nsPSMBackgroundThread::exitRequested(const MutexAutoLock & /*proofOfLock*/) const +{ + return exitRequestedNoLock(); +} + +nsresult +nsPSMBackgroundThread::postStoppedEventToMainThread( + MutexAutoLock const & /*proofOfLock*/) +{ + NS_ASSERTION(PR_GetCurrentThread() == mThreadHandle, + "Background thread stopped from another thread"); + + mExitState = ePSMThreadStopped; + // requestExit is waiting for an event, so give it one. + return NS_DispatchToMainThread(new nsRunnable()); +} + void nsPSMBackgroundThread::requestExit() { + NS_ASSERTION(NS_IsMainThread(), + "nsPSMBackgroundThread::requestExit called off main thread."); + if (!mThreadHandle) return; { MutexAutoLock threadLock(mMutex); - - if (mExitRequested) - return; - - mExitRequested = PR_TRUE; - mCond.NotifyAll(); + if (mExitState < ePSMThreadStopRequested) { + mExitState = ePSMThreadStopRequested; + mCond.NotifyAll(); + } + } + + nsCOMPtr mainThread = do_GetCurrentThread(); + for (;;) { + { + MutexAutoLock threadLock(mMutex); + if (mExitState == ePSMThreadStopped) + break; + } + NS_ProcessPendingEvents(mainThread, PR_MillisecondsToInterval(50)); } PR_JoinThread(mThreadHandle); diff --git a/security/manager/ssl/src/nsPSMBackgroundThread.h b/security/manager/ssl/src/nsPSMBackgroundThread.h index 0683ad10411..2cb50409981 100644 --- a/security/manager/ssl/src/nsPSMBackgroundThread.h +++ b/security/manager/ssl/src/nsPSMBackgroundThread.h @@ -42,6 +42,7 @@ #include "nscore.h" #include "mozilla/CondVar.h" #include "mozilla/Mutex.h" +#include "nsNSSComponent.h" class nsPSMBackgroundThread { @@ -53,16 +54,25 @@ protected: PRThread *mThreadHandle; // Shared mutex used for condition variables, - // and to protect access to mExitRequested. + // and to protect access to mExitState. // Derived classes may use it to protect additional // resources. mozilla::Mutex mMutex; - // Used to signal the thread's Run loop + // Used to signal the thread's Run loop when a job is added + // and/or exit is requested. mozilla::CondVar mCond; - // Has termination of the SSL thread been requested? - PRBool mExitRequested; + PRBool exitRequested(::mozilla::MutexAutoLock const & proofOfLock) const; + PRBool exitRequestedNoLock() const { return mExitState != ePSMThreadRunning; } + nsresult postStoppedEventToMainThread(::mozilla::MutexAutoLock const & proofOfLock); + +private: + enum { + ePSMThreadRunning = 0, + ePSMThreadStopRequested = 1, + ePSMThreadStopped = 2 + } mExitState; public: nsPSMBackgroundThread(); diff --git a/security/manager/ssl/src/nsSSLThread.cpp b/security/manager/ssl/src/nsSSLThread.cpp index e8fdbc81196..1f084bf0371 100644 --- a/security/manager/ssl/src/nsSSLThread.cpp +++ b/security/manager/ssl/src/nsSSLThread.cpp @@ -510,7 +510,7 @@ PRInt32 nsSSLThread::requestRead(nsNSSSocketInfo *si, void *buf, PRInt32 amount, { MutexAutoLock threadLock(ssl_thread_singleton->mMutex); - if (ssl_thread_singleton->mExitRequested) { + if (ssl_thread_singleton->exitRequested(threadLock)) { PR_SetError(PR_UNKNOWN_ERROR, 0); return -1; } @@ -737,7 +737,7 @@ PRInt32 nsSSLThread::requestWrite(nsNSSSocketInfo *si, const void *buf, PRInt32 { MutexAutoLock threadLock(ssl_thread_singleton->mMutex); - if (ssl_thread_singleton->mExitRequested) { + if (ssl_thread_singleton->exitRequested(threadLock)) { PR_SetError(PR_UNKNOWN_ERROR, 0); return -1; } @@ -958,7 +958,7 @@ void nsSSLThread::Run(void) continue; // go back and finally destroy it, before doing anything else } - if (mExitRequested) + if (exitRequested(threadLock)) break; PRBool pending_work = PR_FALSE; @@ -981,12 +981,13 @@ void nsSSLThread::Run(void) mCond.Wait(); } - } while (!pending_work && !mExitRequested && !mSocketScheduledToBeDestroyed); + } while (!pending_work && !exitRequested(threadLock) && + !mSocketScheduledToBeDestroyed); if (mSocketScheduledToBeDestroyed) continue; - if (mExitRequested) + if (exitRequested(threadLock)) break; if (!pending_work) @@ -1134,17 +1135,16 @@ void nsSSLThread::Run(void) PR_SetPollableEvent(nsSSLIOLayerHelpers::mSharedPollableEvent); } } + postStoppedEventToMainThread(threadLock); } } -PRBool nsSSLThread::exitRequested() +PRBool nsSSLThread::stoppedOrStopping() { if (!ssl_thread_singleton) return PR_FALSE; - // no lock - - return ssl_thread_singleton->mExitRequested; + return ssl_thread_singleton->exitRequestedNoLock(); } nsSSLThread *nsSSLThread::ssl_thread_singleton = nsnull; diff --git a/security/manager/ssl/src/nsSSLThread.h b/security/manager/ssl/src/nsSSLThread.h index d91b2ee7727..cc58830e0a5 100644 --- a/security/manager/ssl/src/nsSSLThread.h +++ b/security/manager/ssl/src/nsSSLThread.h @@ -152,7 +152,7 @@ public: static nsresult requestActivateSSL(nsNSSSocketInfo *si); - static PRBool exitRequested(); + static PRBool stoppedOrStopping(); }; #endif //_NSSSLTHREAD_H_ diff --git a/security/nss/lib/util/secport.c b/security/nss/lib/util/secport.c index 5fd2718ea94..3d254409f5e 100644 --- a/security/nss/lib/util/secport.c +++ b/security/nss/lib/util/secport.c @@ -180,6 +180,10 @@ PORT_SetError(int value) #ifdef DEBUG_jp96085 PORT_Assert(value != SEC_ERROR_REUSED_ISSUER_AND_SERIAL); #endif + if (value == SEC_ERROR_NO_MEMORY && + PR_GetEnv("NSS_DEBUG_SEC_ERROR_NO_MEMORY")) { + PR_Assert("SEC_ERROR_NO_MEMORY: attach minidump to bug 662557", __FILE__, __LINE__); + } PR_SetError(value, 0); return; } diff --git a/security/patches/bug-662557-nss-debug-sec-error-no-memory.patch b/security/patches/bug-662557-nss-debug-sec-error-no-memory.patch new file mode 100644 index 00000000000..3474ae8cf3b --- /dev/null +++ b/security/patches/bug-662557-nss-debug-sec-error-no-memory.patch @@ -0,0 +1,27 @@ +# HG changeset patch +# Parent d9973f355dc5d8cc8649fe269561478541c79c99 +# User Brian Smith +diff --git a/security/nss/lib/util/secport.c b/security/nss/lib/util/secport.c +--- a/security/nss/lib/util/secport.c ++++ b/security/nss/lib/util/secport.c +@@ -175,16 +175,20 @@ PORT_Strdup(const char *str) + } + + void + PORT_SetError(int value) + { + #ifdef DEBUG_jp96085 + PORT_Assert(value != SEC_ERROR_REUSED_ISSUER_AND_SERIAL); + #endif ++ if (value == SEC_ERROR_NO_MEMORY && ++ PR_GetEnv("NSS_DEBUG_SEC_ERROR_NO_MEMORY")) { ++ PR_Assert("SEC_ERROR_NO_MEMORY: attach minidump to bug 662557", __FILE__, __LINE__); ++ } + PR_SetError(value, 0); + return; + } + + int + PORT_GetError(void) + { + return(PR_GetError()); diff --git a/testing/mochitest/harness-overlay.xul b/testing/mochitest/harness-overlay.xul index 2ddc1d14a87..7683fda1382 100644 --- a/testing/mochitest/harness-overlay.xul +++ b/testing/mochitest/harness-overlay.xul @@ -79,7 +79,7 @@ function loadTests()
- +
diff --git a/toolkit/components/places/tests/unit/test_database_replaceOnStartup.js b/toolkit/components/places/tests/unit/test_database_replaceOnStartup.js index d55e593f8e6..1f3a95d2e0d 100644 --- a/toolkit/components/places/tests/unit/test_database_replaceOnStartup.js +++ b/toolkit/components/places/tests/unit/test_database_replaceOnStartup.js @@ -16,7 +16,8 @@ function run_test() { } let file = do_get_file("default.sqlite"); - file.copyTo(gProfD, "places.sqlite"); + file.copyToFollowingLinks(gProfD, "places.sqlite"); + file = gProfD.clone().append("places.sqlite"); // Create some unique stuff to check later. let db = Services.storage.openUnsharedDatabase(file); diff --git a/toolkit/content/tests/chrome/Makefile.in b/toolkit/content/tests/chrome/Makefile.in index 4bdd1e2bee0..bc42321707c 100644 --- a/toolkit/content/tests/chrome/Makefile.in +++ b/toolkit/content/tests/chrome/Makefile.in @@ -107,6 +107,74 @@ _TEST_FILES = findbar_window.xul \ window_panel.xul \ $(NULL) + +_TEST_FILES += \ + test_bug360220.xul \ + test_bug365773.xul \ + test_bug382990.xul \ + test_bug457632.xul \ + test_bug460942.xul \ + test_bug509732.xul \ + test_bug554279.xul \ + test_bug557987.xul\ + test_bug562554.xul \ + test_button.xul \ + test_closemenu_attribute.xul \ + test_colorpicker_popup.xul \ + test_menulist.xul \ + test_menuitem_blink.xul \ + test_menulist_keynav.xul \ + test_popup_coords.xul \ + test_popup_recreate.xul \ + test_popup_preventdefault.xul \ + test_notificationbox.xul \ + test_scale.xul \ + test_radio.xul \ + test_tabbox.xul \ + test_progressmeter.xul \ + test_props.xul \ + test_statusbar.xul \ + test_timepicker.xul \ + test_tree.xul \ + test_tree_view.xul \ + test_tree_single.xul \ + test_textbox_emptytext.xul \ + test_textbox_number.xul \ + test_textbox_search.xul \ + test_toolbar.xul \ + xul_selectcontrol.js \ + test_popupincontent.xul \ + test_panelfrommenu.xul \ + test_hiddenitems.xul \ + test_hiddenpaging.xul \ + test_popup_tree.xul \ + test_popup_keys.xul \ + test_popuphidden.xul \ + test_popup_scaled.xul \ + test_popupremoving.xul \ + test_popupremoving_frame.xul \ + frame_popupremoving_frame.xul \ + test_position.xul \ + test_menu.xul \ + test_menu_hide.xul \ + test_focus_anons.xul \ + test_tabindex.xul \ + test_scrollbar.xul \ + test_sorttemplate.xul \ + test_contextmenu_list.xul \ + test_richlist_direction.xul \ + test_tooltip.xul \ + test_popup_attribute.xul \ + window_popup_attribute.xul \ + test_popup_button.xul \ + window_popup_button.xul \ + popup_childframe_node.xul \ + popup_trigger.js \ + test_tooltip_noautohide.xul \ + $(NULL) + + + # test_panel_focus.xul won't work if the Full Keyboard Access preference is set to # textboxes and lists only, so skip this test on Mac ifneq (cocoa,$(MOZ_WIDGET_TOOLKIT)) diff --git a/toolkit/content/tests/widgets/frame_popupremoving_frame.xul b/toolkit/content/tests/chrome/frame_popupremoving_frame.xul similarity index 100% rename from toolkit/content/tests/widgets/frame_popupremoving_frame.xul rename to toolkit/content/tests/chrome/frame_popupremoving_frame.xul diff --git a/toolkit/content/tests/widgets/popup_childframe_node.xul b/toolkit/content/tests/chrome/popup_childframe_node.xul similarity index 100% rename from toolkit/content/tests/widgets/popup_childframe_node.xul rename to toolkit/content/tests/chrome/popup_childframe_node.xul diff --git a/toolkit/content/tests/widgets/popup_trigger.js b/toolkit/content/tests/chrome/popup_trigger.js similarity index 99% rename from toolkit/content/tests/widgets/popup_trigger.js rename to toolkit/content/tests/chrome/popup_trigger.js index 5027b612249..97b37b8b911 100644 --- a/toolkit/content/tests/widgets/popup_trigger.js +++ b/toolkit/content/tests/chrome/popup_trigger.js @@ -417,7 +417,6 @@ var popupTests = [ var childframe = document.getElementById("childframe"); if (childframe) { for (var t = 0; t < 2; t++) { - netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); var child = childframe.contentDocument; var evt = child.createEvent("Event"); evt.initEvent("click", true, true); diff --git a/toolkit/content/tests/widgets/test_bug360220.xul b/toolkit/content/tests/chrome/test_bug360220.xul similarity index 79% rename from toolkit/content/tests/widgets/test_bug360220.xul rename to toolkit/content/tests/chrome/test_bug360220.xul index ec7007a0477..401a1465c86 100644 --- a/toolkit/content/tests/widgets/test_bug360220.xul +++ b/toolkit/content/tests/chrome/test_bug360220.xul @@ -1,6 +1,6 @@ - + @@ -9,8 +9,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=360220 xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> Test for Bug 360220 - - + + Mozilla Bug 360220 diff --git a/toolkit/content/tests/widgets/test_bug365773.xul b/toolkit/content/tests/chrome/test_bug365773.xul similarity index 84% rename from toolkit/content/tests/widgets/test_bug365773.xul rename to toolkit/content/tests/chrome/test_bug365773.xul index cbf6932e095..9b3e0a5c994 100644 --- a/toolkit/content/tests/widgets/test_bug365773.xul +++ b/toolkit/content/tests/chrome/test_bug365773.xul @@ -1,6 +1,6 @@ - + @@ -9,8 +9,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=365773 xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> Test for Bug 365773 - - + + Mozilla Bug 365773 diff --git a/toolkit/content/tests/widgets/test_bug382990.xul b/toolkit/content/tests/chrome/test_bug382990.xul similarity index 77% rename from toolkit/content/tests/widgets/test_bug382990.xul rename to toolkit/content/tests/chrome/test_bug382990.xul index bedb6cee850..31523116981 100644 --- a/toolkit/content/tests/widgets/test_bug382990.xul +++ b/toolkit/content/tests/chrome/test_bug382990.xul @@ -1,15 +1,15 @@ - + - - + + diff --git a/toolkit/content/tests/widgets/test_bug460942.xul b/toolkit/content/tests/chrome/test_bug460942.xul similarity index 78% rename from toolkit/content/tests/widgets/test_bug460942.xul rename to toolkit/content/tests/chrome/test_bug460942.xul index 1e9e9d7372c..1f8a760ff08 100644 --- a/toolkit/content/tests/widgets/test_bug460942.xul +++ b/toolkit/content/tests/chrome/test_bug460942.xul @@ -1,14 +1,14 @@ - + - - + +