author | Carsten "Tomcat" Book <cbook@mozilla.com> |
Thu, 15 Oct 2015 11:52:40 +0200 | |
changeset 267831 | e193b4da0a8c1025aa76a403c64663ff1cd41709 |
parent 267728 | 3c18fce625f9dc8973dc492e1ce733334c8e0eca (current diff) |
parent 267830 | 1c9516a8f8f5cc996e8d26b88769ed4c72923e32 (diff) |
child 267834 | f9e8bd374203682da519f6e3a63fa44157013033 |
child 267868 | ceb07c2b56f92e7674a5f54ecdb3e04d9262f2a6 |
child 267882 | 6c3246a2a4acaf735c2231a7cf15de5a5d6539d2 |
push id | 29530 |
push user | cbook@mozilla.com |
push date | Thu, 15 Oct 2015 09:53:07 +0000 |
treeherder | mozilla-central@e193b4da0a8c [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | merge |
milestone | 44.0a1 |
first release with | nightly linux32
e193b4da0a8c
/
44.0a1
/
20151015030233
/
files
nightly linux64
e193b4da0a8c
/
44.0a1
/
20151015030233
/
files
nightly mac
e193b4da0a8c
/
44.0a1
/
20151015030233
/
files
nightly win32
e193b4da0a8c
/
44.0a1
/
20151015030233
/
files
nightly win64
e193b4da0a8c
/
44.0a1
/
20151015030233
/
files
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
releases | nightly linux32
44.0a1
/
20151015030233
/
pushlog to previous
nightly linux64
44.0a1
/
20151015030233
/
pushlog to previous
nightly mac
44.0a1
/
20151015030233
/
pushlog to previous
nightly win32
44.0a1
/
20151015030233
/
pushlog to previous
nightly win64
44.0a1
/
20151015030233
/
pushlog to previous
|
--- a/accessible/ipc/DocAccessibleParent.cpp +++ b/accessible/ipc/DocAccessibleParent.cpp @@ -257,16 +257,17 @@ DocAccessibleParent::Destroy() MOZ_ASSERT(!mShutdown); mShutdown = true; uint32_t childDocCount = mChildDocs.Length(); for (uint32_t i = childDocCount - 1; i < childDocCount; i--) mChildDocs[i]->Destroy(); for (auto iter = mAccessibles.Iter(); !iter.Done(); iter.Next()) { + MOZ_ASSERT(iter.Get()->mProxy != this); ProxyDestroyed(iter.Get()->mProxy); iter.Remove(); } ProxyDestroyed(this); if (mParentDoc) mParentDoc->RemoveChildDoc(this); else if (IsTopLevel()) GetAccService()->RemoteDocShutdown(this);
--- a/accessible/windows/msaa/Platform.cpp +++ b/accessible/windows/msaa/Platform.cpp @@ -56,24 +56,27 @@ a11y::ProxyDestroyed(ProxyAccessible* aP AccessibleWrap* wrapper = reinterpret_cast<AccessibleWrap*>(aProxy->GetWrapper()); MOZ_ASSERT(wrapper); if (!wrapper) return; auto doc = static_cast<DocProxyAccessibleWrap*>(WrapperFor(aProxy->Document())); + MOZ_ASSERT(doc); + if (doc) { #ifdef _WIN64 - uint32_t id = wrapper->GetExistingID(); - if (id != AccessibleWrap::kNoID) { - doc->RemoveID(id); + uint32_t id = wrapper->GetExistingID(); + if (id != AccessibleWrap::kNoID) { + doc->RemoveID(id); + } +#else + doc->RemoveID(-reinterpret_cast<int32_t>(wrapper)); +#endif } -#else - doc->RemoveID(-reinterpret_cast<int32_t>(wrapper)); -#endif wrapper->Shutdown(); aProxy->SetWrapper(0); wrapper->Release(); } void a11y::ProxyEvent(ProxyAccessible* aTarget, uint32_t aEventType)
--- a/b2g/app/b2g.js +++ b/b2g/app/b2g.js @@ -314,17 +314,17 @@ pref("media.preload.auto", 2); // pre pref("media.cache_size", 4096); // 4MB media cache // Try to save battery by not resuming reading from a connection until we fall // below 10s of buffered data. pref("media.cache_resume_threshold", 10); pref("media.cache_readahead_limit", 30); #ifdef MOZ_FMP4 // Enable/Disable Gonk Decoder Module -pref("media.fragmented-mp4.gonk.enabled", true); +pref("media.gonk.enabled", true); #endif //Encrypted media extensions. pref("media.eme.enabled", true); pref("media.eme.apiVisible", true); // The default number of decoded video frames that are enqueued in // MediaDecoderReader's mVideoQueue. pref("media.video-queue.default-size", 3);
--- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -1830,18 +1830,18 @@ pref("ui.key.menuAccessKeyFocuses", true #endif // Encrypted media extensions. pref("media.eme.enabled", true); pref("media.eme.apiVisible", true); // If decoding-via-gmp is turned on for <video>, default to using // Adobe's GMP for decoding. -pref("media.fragmented-mp4.gmp.aac", 2); -pref("media.fragmented-mp4.gmp.h264", 2); +pref("media.gmp.decoder.aac", 2); +pref("media.gmp.decoder.h264", 2); // Whether we should run a test-pattern through EME GMPs before assuming they'll // decode H.264. pref("media.gmp.trial-create.enabled", true); #ifdef MOZ_ADOBE_EME pref("browser.eme.ui.enabled", true); pref("media.gmp-eme-adobe.enabled", true);
--- a/browser/base/content/browser.xul +++ b/browser/base/content/browser.xul @@ -157,16 +157,17 @@ </panel> <!-- for select dropdowns. The menupopup is what shows the list of options, and the popuponly menulist makes things like the menuactive attributes work correctly on the menupopup. ContentSelectDropdown expects the popuponly menulist to be its immediate parent. --> <menulist popuponly="true" id="ContentSelectDropdown" hidden="true"> <menupopup rolluponmousewheel="true" + activateontab="true" #ifdef XP_WIN consumeoutsideclicks="false" ignorekeys="handled" #endif /> </menulist> <!-- for invalid form error message --> <panel id="invalid-form-popup" type="arrow" orient="vertical" noautofocus="true" hidden="true" level="parent">
--- a/browser/base/content/test/general/browser_audioTabIcon.js +++ b/browser/base/content/test/general/browser_audioTabIcon.js @@ -93,20 +93,19 @@ function* test_mute_tab(tab, icon, expec EventUtils.synthesizeMouseAtCenter(icon, {button: 0}); leave_icon(icon); is(gBrowser.selectedTab, activeTab, "Clicking on mute should not change the currently selected tab"); return mutedPromise; } -function get_tab_attributes(tab) { +function get_tab_state(tab) { const ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore); - let {attributes} = JSON.parse(ss.getTabState(tab)); - return attributes; + return JSON.parse(ss.getTabState(tab)); } function* test_muting_using_menu(tab, expectMuted) { // Show the popup menu let contextMenu = document.getElementById("tabContextMenu"); let popupShownPromise = BrowserTestUtils.waitForEvent(contextMenu, "popupshown"); EventUtils.synthesizeMouseAtCenter(tab, {type: "contextmenu", button: 2}); yield popupShownPromise; @@ -142,27 +141,27 @@ function* test_playing_icon_on_tab(tab, let icon = document.getAnonymousElementByAttribute(tab, "anonid", isPinned ? "overlay-icon" : "soundplaying-icon"); let isActiveTab = tab === gBrowser.selectedTab; yield play(tab); yield test_tooltip(icon, "Mute tab", isActiveTab); - ok(!("muted" in get_tab_attributes(tab)), "No muted attribute should be persisted"); + ok(!("muted" in get_tab_state(tab)), "No muted attribute should be persisted"); yield test_mute_tab(tab, icon, true); - ok("muted" in get_tab_attributes(tab), "Muted attribute should be persisted"); + ok("muted" in get_tab_state(tab), "Muted attribute should be persisted"); yield test_tooltip(icon, "Unmute tab", isActiveTab); yield test_mute_tab(tab, icon, false); - ok(!("muted" in get_tab_attributes(tab)), "No muted attribute should be persisted"); + ok(!("muted" in get_tab_state(tab)), "No muted attribute should be persisted"); yield test_tooltip(icon, "Mute tab", isActiveTab); yield test_mute_tab(tab, icon, true); yield pause(tab); ok(tab.hasAttribute("muted") &&
--- a/browser/components/sessionstore/SessionStore.jsm +++ b/browser/components/sessionstore/SessionStore.jsm @@ -2674,16 +2674,20 @@ var SessionStoreInternal = { if (winData.tabs[t].hidden) { tabbrowser.hideTab(tabs[t]); } else { tabbrowser.showTab(tabs[t]); numVisibleTabs++; } + + if (!!winData.tabs[t].muted != tabs[t].linkedBrowser.audioMuted) { + tabs[t].toggleMuteAudio(); + } } if (!overwriteTabs && firstWindow) { // Move the originally open tabs to the end let endPosition = tabbrowser.tabs.length - 1; for (let i = 0; i < initialTabs.length; i++) { tabbrowser.moveTabTo(initialTabs[i], endPosition); } @@ -2933,16 +2937,20 @@ var SessionStoreInternal = { } if (tabData.hidden) { tabbrowser.hideTab(tab); } else { tabbrowser.showTab(tab); } + if (!!tabData.muted != browser.audioMuted) { + tab.toggleMuteAudio(); + } + if (tabData.lastAccessed) { tab.lastAccessed = tabData.lastAccessed; } if ("attributes" in tabData) { // Ensure that we persist tab attributes restored from previous sessions. Object.keys(tabData.attributes).forEach(a => TabAttributes.persist(a)); }
--- a/browser/components/sessionstore/TabAttributes.jsm +++ b/browser/components/sessionstore/TabAttributes.jsm @@ -19,23 +19,25 @@ this.TabAttributes = Object.freeze({ }, set: function (tab, data = {}) { TabAttributesInternal.set(tab, data); } }); var TabAttributesInternal = { - _attrs: new Set(["muted"]), + _attrs: new Set(), // We never want to directly read or write those attributes. // 'image' should not be accessed directly but handled by using the // gBrowser.getIcon()/setIcon() methods. + // 'muted' should not be accessed directly but handled by using the + // tab.linkedBrowser.audioMuted/toggleMuteAudio methods. // 'pending' is used internal by sessionstore and managed accordingly. - _skipAttrs: new Set(["image", "pending"]), + _skipAttrs: new Set(["image", "muted", "pending"]), persist: function (name) { if (this._attrs.has(name) || this._skipAttrs.has(name)) { return false; } this._attrs.add(name); return true;
--- a/browser/components/sessionstore/TabState.jsm +++ b/browser/components/sessionstore/TabState.jsm @@ -154,16 +154,20 @@ var TabStateInternal = { let tabData = {entries: [], lastAccessed: tab.lastAccessed }; let browser = tab.linkedBrowser; if (tab.pinned) tabData.pinned = true; else delete tabData.pinned; tabData.hidden = tab.hidden; + if (browser.audioMuted) + tabData.muted = true; + else + delete tabData.muted; // Save tab attributes. tabData.attributes = TabAttributes.get(tab); if (tab.__SS_extdata) tabData.extData = tab.__SS_extdata; else if (tabData.extData) delete tabData.extData;
--- a/browser/components/sessionstore/test/browser_attributes.js +++ b/browser/components/sessionstore/test/browser_attributes.js @@ -1,34 +1,40 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ */ /** * This test makes sure that we correctly preserve tab attributes when storing * and restoring tabs. It also ensures that we skip special attributes like - * 'image' and 'pending' that need to be handled differently or internally. + * 'image', 'muted' and 'pending' that need to be handled differently or internally. */ const PREF = "browser.sessionstore.restore_on_demand"; add_task(function* test() { Services.prefs.setBoolPref(PREF, true) registerCleanupFunction(() => Services.prefs.clearUserPref(PREF)); // Add a new tab with a nice icon. let tab = gBrowser.addTab("about:robots"); yield promiseBrowserLoaded(tab.linkedBrowser); // Check that the tab has an 'image' attribute. ok(tab.hasAttribute("image"), "tab.image exists"); - // Make sure we do not persist 'image' attributes. + tab.toggleMuteAudio(); + // Check that the tab has a 'muted' attribute. + ok(tab.hasAttribute("muted"), "tab.muted exists"); + + // Make sure we do not persist 'image' or 'muted' attributes. ss.persistTabAttribute("image"); + ss.persistTabAttribute("muted"); let {attributes} = JSON.parse(ss.getTabState(tab)); ok(!("image" in attributes), "'image' attribute not saved"); + ok(!("muted" in attributes), "'muted' attribute not saved"); ok(!("custom" in attributes), "'custom' attribute not saved"); // Test persisting a custom attribute. tab.setAttribute("custom", "foobar"); ss.persistTabAttribute("custom"); ({attributes} = JSON.parse(ss.getTabState(tab))); is(attributes.custom, "foobar", "'custom' attribute is correct");
--- a/browser/config/mozconfigs/macosx-universal/l10n-mozconfig +++ b/browser/config/mozconfigs/macosx-universal/l10n-mozconfig @@ -1,12 +1,12 @@ . "$topsrcdir/browser/config/mozconfigs/common" . "$topsrcdir/build/macosx/mozconfig.common" -ac_add_options --with-l10n-base=../../../l10n +ac_add_options --with-l10n-base=../../l10n ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL} ac_add_options --enable-update-packaging ac_add_options --with-branding=browser/branding/nightly if test "${MOZ_UPDATE_CHANNEL}" = "nightly"; then ac_add_options --with-macbundlename-prefix=Firefox fi
--- a/browser/extensions/pdfjs/test/browser.ini +++ b/browser/extensions/pdfjs/test/browser.ini @@ -1,9 +1,12 @@ [DEFAULT] -skip-if = e10s # Bug 1159385 support-files = file_pdfjs_test.pdf [browser_pdfjs_main.js] +skip-if = e10s # Bug 1159385 [browser_pdfjs_navigation.js] +skip-if = e10s # Bug 1159385 [browser_pdfjs_savedialog.js] [browser_pdfjs_views.js] +skip-if = e10s # Bug 1159385 [browser_pdfjs_zoom.js] +skip-if = e10s # Bug 1159385
--- a/build/clang-plugin/clang-plugin.cpp +++ b/build/clang-plugin/clang-plugin.cpp @@ -219,16 +219,43 @@ bool isIgnoredPathForImplicitConversion( } return false; } bool isInterestingDeclForImplicitConversion(const Decl *decl) { return !isInIgnoredNamespaceForImplicitConversion(decl) && !isIgnoredPathForImplicitConversion(decl); } + +bool isIgnoredExprForMustUse(const Expr *E) { + if (const CXXOperatorCallExpr *OpCall = dyn_cast<CXXOperatorCallExpr>(E)) { + switch (OpCall->getOperator()) { + case OO_Equal: + case OO_PlusEqual: + case OO_MinusEqual: + case OO_StarEqual: + case OO_SlashEqual: + case OO_PercentEqual: + case OO_CaretEqual: + case OO_AmpEqual: + case OO_PipeEqual: + case OO_LessLessEqual: + case OO_GreaterGreaterEqual: + return true; + default: + return false; + } + } + + if (const BinaryOperator *Op = dyn_cast<BinaryOperator>(E)) { + return Op->isAssignmentOp(); + } + + return false; +} } class CustomTypeAnnotation { enum ReasonKind { RK_None, RK_Direct, RK_ArrayElement, RK_BaseClass, @@ -315,17 +342,17 @@ public: return false; } void HandleUnusedExprResult(const Stmt *stmt) { const Expr *E = dyn_cast_or_null<Expr>(stmt); if (E) { QualType T = E->getType(); - if (MustUse.hasEffectiveAnnotation(T)) { + if (MustUse.hasEffectiveAnnotation(T) && !isIgnoredExprForMustUse(E)) { unsigned errorID = Diag.getDiagnosticIDs()->getCustomDiagID( DiagnosticIDs::Error, "Unused value of must-use type %0"); Diag.Report(E->getLocStart(), errorID) << T; MustUse.dumpAnnotationReason(Diag, T, E->getLocStart()); } } }
--- a/build/clang-plugin/tests/TestMustUse.cpp +++ b/build/clang-plugin/tests/TestMustUse.cpp @@ -15,142 +15,163 @@ void use(MustUse*); void use(MustUse&); void use(MustUse&&); void use(MayUse*); void use(MayUse&); void use(MayUse&&); void use(bool); void foo() { + MustUse u; + producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}} producesMustUsePointer(); producesMustUseRef(); // expected-error {{Unused value of must-use type 'MustUse'}} producesMayUse(); producesMayUsePointer(); producesMayUseRef(); + u = producesMustUse(); { producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}} producesMustUsePointer(); producesMustUseRef(); // expected-error {{Unused value of must-use type 'MustUse'}} producesMayUse(); producesMayUsePointer(); producesMayUseRef(); + u = producesMustUse(); } if (true) { producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}} producesMustUsePointer(); producesMustUseRef(); // expected-error {{Unused value of must-use type 'MustUse'}} producesMayUse(); producesMayUsePointer(); producesMayUseRef(); + u = producesMustUse(); } else { producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}} producesMustUsePointer(); producesMustUseRef(); // expected-error {{Unused value of must-use type 'MustUse'}} producesMayUse(); producesMayUsePointer(); producesMayUseRef(); + u = producesMustUse(); } if(true) producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}} else producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}} if(true) producesMustUsePointer(); else producesMustUsePointer(); if(true) producesMustUseRef(); // expected-error {{Unused value of must-use type 'MustUse'}} else producesMustUseRef(); // expected-error {{Unused value of must-use type 'MustUse'}} if(true) producesMayUse(); else producesMayUse(); if(true) producesMayUsePointer(); else producesMayUsePointer(); if(true) producesMayUseRef(); else producesMayUseRef(); + if(true) u = producesMustUse(); + else u = producesMustUse(); while (true) producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}} while (true) producesMustUsePointer(); while (true) producesMustUseRef(); // expected-error {{Unused value of must-use type 'MustUse'}} while (true) producesMayUse(); while (true) producesMayUsePointer(); while (true) producesMayUseRef(); + while (true) u = producesMustUse(); do producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}} while (true); do producesMustUsePointer(); while (true); do producesMustUseRef(); // expected-error {{Unused value of must-use type 'MustUse'}} while (true); do producesMayUse(); while (true); do producesMayUsePointer(); while (true); do producesMayUseRef(); while (true); + do u = producesMustUse(); + while (true); for (;;) producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}} for (;;) producesMustUsePointer(); for (;;) producesMustUseRef(); // expected-error {{Unused value of must-use type 'MustUse'}} for (;;) producesMayUse(); for (;;) producesMayUsePointer(); for (;;) producesMayUseRef(); + for (;;) u = producesMustUse(); for (producesMustUse();;); // expected-error {{Unused value of must-use type 'MustUse'}} for (producesMustUsePointer();;); for (producesMustUseRef();;); // expected-error {{Unused value of must-use type 'MustUse'}} for (producesMayUse();;); for (producesMayUsePointer();;); for (producesMayUseRef();;); + for (u = producesMustUse();;); for (;;producesMustUse()); // expected-error {{Unused value of must-use type 'MustUse'}} for (;;producesMustUsePointer()); for (;;producesMustUseRef()); // expected-error {{Unused value of must-use type 'MustUse'}} for (;;producesMayUse()); for (;;producesMayUsePointer()); for (;;producesMayUseRef()); + for (;;u = producesMustUse()); use((producesMustUse(), false)); // expected-error {{Unused value of must-use type 'MustUse'}} use((producesMustUsePointer(), false)); use((producesMustUseRef(), false)); // expected-error {{Unused value of must-use type 'MustUse'}} use((producesMayUse(), false)); use((producesMayUsePointer(), false)); use((producesMayUseRef(), false)); + use((u = producesMustUse(), false)); switch (1) { case 1: producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}} producesMustUsePointer(); producesMustUseRef(); // expected-error {{Unused value of must-use type 'MustUse'}} producesMayUse(); producesMayUsePointer(); producesMayUseRef(); + u = producesMustUse(); case 2: producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}} case 3: producesMustUsePointer(); case 4: producesMustUseRef(); // expected-error {{Unused value of must-use type 'MustUse'}} case 5: producesMayUse(); case 6: producesMayUsePointer(); case 7: producesMayUseRef(); + case 8: + u = producesMustUse(); default: producesMustUse(); // expected-error {{Unused value of must-use type 'MustUse'}} producesMustUsePointer(); producesMustUseRef(); // expected-error {{Unused value of must-use type 'MustUse'}} producesMayUse(); producesMayUsePointer(); producesMayUseRef(); + u = producesMustUse(); } use(producesMustUse()); use(producesMustUsePointer()); use(producesMustUseRef()); use(producesMayUse()); use(producesMayUsePointer()); use(producesMayUseRef()); + use(u = producesMustUse()); MustUse a = producesMustUse(); MustUse *b = producesMustUsePointer(); MustUse &c = producesMustUseRef(); MayUse d = producesMayUse(); MayUse *e = producesMayUsePointer(); MayUse &f = producesMayUseRef(); + MustUse g = u = producesMustUse(); }
--- a/build/sanitizers/lsan_suppressions.txt +++ b/build/sanitizers/lsan_suppressions.txt @@ -78,22 +78,16 @@ leak:nsPSPrinterList::GetPrinterList leak:_PR_Getfd # Bug 1028483 - The XML parser sometimes leaks an object. bc3 leak:processInternalEntity # Bug 1187421 - With e10s, NSS does not always free the error stack. m1. leak:nss_ClearErrorStack -# Bug 1090570 - IPC Transport lifetime is not always managed correctly. -leak:mozilla::ipc::OpenDescriptor -leak:IPC::Channel::ChannelImpl::OutputQueuePush -leak:IPC::Channel::Channel -leak:base::MessagePumpLibevent::WatchFileDescriptor - # Bug 1122045 - Leaks in MessageLoop::MessageLoop() leak:MessageLoop::MessageLoop # This may not actually be related to MessageLoop. leak:base::WaitableEvent::TimedWait leak:MessageLoop::PostTask_Helper # Bug 1189430 - DNS leaks in mochitest-chrome. leak:nsDNSService::AsyncResolveExtended
--- a/dom/base/nsGkAtomList.h +++ b/dom/base/nsGkAtomList.h @@ -62,16 +62,17 @@ GK_ATOM(above, "above") GK_ATOM(acceltext, "acceltext") GK_ATOM(accept, "accept") GK_ATOM(acceptcharset, "accept-charset") GK_ATOM(accesskey, "accesskey") GK_ATOM(acronym, "acronym") GK_ATOM(action, "action") GK_ATOM(active, "active") GK_ATOM(activetitlebarcolor, "activetitlebarcolor") +GK_ATOM(activateontab, "activateontab") GK_ATOM(actuate, "actuate") GK_ATOM(address, "address") GK_ATOM(after, "after") GK_ATOM(after_end, "after_end") GK_ATOM(after_start, "after_start") GK_ATOM(align, "align") GK_ATOM(alink, "alink") GK_ATOM(all, "all")
--- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -8795,17 +8795,17 @@ nsGlobalWindow::CanClose() if (NS_SUCCEEDED(rv) && !canClose) return false; } return true; } void -nsGlobalWindow::CloseOuter() +nsGlobalWindow::CloseOuter(bool aTrustedCaller) { MOZ_RELEASE_ASSERT(IsOuterWindow()); if (!mDocShell || IsInModalState() || (IsFrame() && !mDocShell->GetIsBrowserOrApp())) { // window.close() is called on a frame in a frameset, on a window // that's already closed, or on a window for which there's // currently a modal dialog open. Ignore such calls. @@ -8827,17 +8827,17 @@ nsGlobalWindow::CloseOuter() } // Don't allow scripts from content to close non-app or non-neterror // windows that were not opened by script. nsAutoString url; mDoc->GetURL(url); if (!mDocShell->GetIsApp() && !StringBeginsWith(url, NS_LITERAL_STRING("about:neterror")) && - !mHadOriginalOpener && !nsContentUtils::IsCallerChrome()) { + !mHadOriginalOpener && !aTrustedCaller) { bool allowClose = mAllowScriptsToClose || Preferences::GetBool("dom.allow_scripts_to_close_windows", true); if (!allowClose) { // We're blocking the close operation // report localized error msg in JS console nsContentUtils::ReportToConsole( nsIScriptError::warningFlag, NS_LITERAL_CSTRING("DOM Window"), mDoc, // Better name for the category? @@ -8871,28 +8871,25 @@ nsGlobalWindow::CloseOuter() } FinalClose(); } void nsGlobalWindow::Close(ErrorResult& aError) { - FORWARD_TO_OUTER_OR_THROW(CloseOuter, (), aError, ); + FORWARD_TO_OUTER_OR_THROW(CloseOuter, (nsContentUtils::IsCallerChrome()), aError, ); } NS_IMETHODIMP nsGlobalWindow::Close() { - FORWARD_TO_INNER(Close, (), NS_ERROR_UNEXPECTED); - - ErrorResult rv; - Close(rv); - - return rv.StealNSResult(); + FORWARD_TO_OUTER(Close, (), NS_ERROR_UNEXPECTED); + CloseOuter(/* aTrustedCaller = */ true); + return NS_OK; } void nsGlobalWindow::ForceClose() { MOZ_ASSERT(IsOuterWindow()); if (IsFrame() || !mDocShell) { @@ -10001,21 +9998,16 @@ nsGlobalWindow::AddEventListener(const n bool aUseCapture, bool aWantsUntrusted, uint8_t aOptionalArgc) { NS_ASSERTION(!aWantsUntrusted || aOptionalArgc > 1, "Won't check if this is chrome, you want to set " "aWantsUntrusted to false or make the aWantsUntrusted " "explicit by making optional_argc non-zero."); - if (IsOuterWindow() && mInnerWindow && - !nsContentUtils::CanCallerAccess(mInnerWindow)) { - return NS_ERROR_DOM_SECURITY_ERR; - } - if (!aWantsUntrusted && (aOptionalArgc < 2 && !nsContentUtils::IsChromeDoc(mDoc))) { aWantsUntrusted = true; } EventListenerManager* manager = GetOrCreateListenerManager(); NS_ENSURE_STATE(manager); manager->AddEventListener(aType, aListener, aUseCapture, aWantsUntrusted);
--- a/dom/base/nsGlobalWindow.h +++ b/dom/base/nsGlobalWindow.h @@ -860,17 +860,17 @@ public: mozilla::dom::BarProp* GetPersonalbar(mozilla::ErrorResult& aError); mozilla::dom::BarProp* GetScrollbars(mozilla::ErrorResult& aError); mozilla::dom::BarProp* GetStatusbar(mozilla::ErrorResult& aError); mozilla::dom::BarProp* GetToolbar(mozilla::ErrorResult& aError); void GetStatusOuter(nsAString& aStatus); void GetStatus(nsAString& aStatus, mozilla::ErrorResult& aError); void SetStatusOuter(const nsAString& aStatus); void SetStatus(const nsAString& aStatus, mozilla::ErrorResult& aError); - void CloseOuter(); + void CloseOuter(bool aTrustedCaller); void Close(mozilla::ErrorResult& aError); bool GetClosedOuter(); bool GetClosed(mozilla::ErrorResult& aError); void StopOuter(mozilla::ErrorResult& aError); void Stop(mozilla::ErrorResult& aError); void FocusOuter(mozilla::ErrorResult& aError); void Focus(mozilla::ErrorResult& aError); void BlurOuter();
--- a/dom/base/nsLocation.cpp +++ b/dom/base/nsLocation.cpp @@ -274,19 +274,16 @@ nsLocation::SetURI(nsIURI* aURI, bool aR } return NS_OK; } NS_IMETHODIMP nsLocation::GetHash(nsAString& aHash) { - if (!CallerSubsumes()) - return NS_ERROR_DOM_SECURITY_ERR; - aHash.SetLength(0); nsCOMPtr<nsIURI> uri; nsresult rv = GetURI(getter_AddRefs(uri)); if (NS_FAILED(rv) || !uri) { return rv; } @@ -357,19 +354,16 @@ nsLocation::SetHash(const nsAString& aHa } return SetURI(uri); } NS_IMETHODIMP nsLocation::GetHost(nsAString& aHost) { - if (!CallerSubsumes()) - return NS_ERROR_DOM_SECURITY_ERR; - aHost.Truncate(); nsCOMPtr<nsIURI> uri; nsresult result; result = GetURI(getter_AddRefs(uri), true); if (uri) { @@ -383,19 +377,16 @@ nsLocation::GetHost(nsAString& aHost) } return NS_OK; } NS_IMETHODIMP nsLocation::SetHost(const nsAString& aHost) { - if (!CallerSubsumes()) - return NS_ERROR_DOM_SECURITY_ERR; - nsCOMPtr<nsIURI> uri; nsresult rv = GetWritableURI(getter_AddRefs(uri)); if (NS_WARN_IF(NS_FAILED(rv) || !uri)) { return rv; } rv = uri->SetHostPort(NS_ConvertUTF16toUTF8(aHost)); if (NS_WARN_IF(NS_FAILED(rv))) { @@ -403,36 +394,30 @@ nsLocation::SetHost(const nsAString& aHo } return SetURI(uri); } NS_IMETHODIMP nsLocation::GetHostname(nsAString& aHostname) { - if (!CallerSubsumes()) - return NS_ERROR_DOM_SECURITY_ERR; - aHostname.Truncate(); nsCOMPtr<nsIURI> uri; GetURI(getter_AddRefs(uri), true); if (uri) { nsContentUtils::GetHostOrIPv6WithBrackets(uri, aHostname); } return NS_OK; } NS_IMETHODIMP nsLocation::SetHostname(const nsAString& aHostname) { - if (!CallerSubsumes()) - return NS_ERROR_DOM_SECURITY_ERR; - nsCOMPtr<nsIURI> uri; nsresult rv = GetWritableURI(getter_AddRefs(uri)); if (NS_WARN_IF(NS_FAILED(rv) || !uri)) { return rv; } rv = uri->SetHost(NS_ConvertUTF16toUTF8(aHostname)); if (NS_WARN_IF(NS_FAILED(rv))) { @@ -440,19 +425,16 @@ nsLocation::SetHostname(const nsAString& } return SetURI(uri); } NS_IMETHODIMP nsLocation::GetHref(nsAString& aHref) { - if (!CallerSubsumes()) - return NS_ERROR_DOM_SECURITY_ERR; - aHref.Truncate(); nsCOMPtr<nsIURI> uri; nsresult result; result = GetURI(getter_AddRefs(uri)); if (uri) { @@ -558,19 +540,16 @@ nsLocation::SetHrefWithBase(const nsAStr } return result; } NS_IMETHODIMP nsLocation::GetOrigin(nsAString& aOrigin) { - if (!CallerSubsumes()) - return NS_ERROR_DOM_SECURITY_ERR; - aOrigin.Truncate(); nsCOMPtr<nsIURI> uri; nsresult rv = GetURI(getter_AddRefs(uri), true); NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_TRUE(uri, NS_OK); nsAutoString origin; @@ -579,19 +558,16 @@ nsLocation::GetOrigin(nsAString& aOrigin aOrigin = origin; return NS_OK; } NS_IMETHODIMP nsLocation::GetPathname(nsAString& aPathname) { - if (!CallerSubsumes()) - return NS_ERROR_DOM_SECURITY_ERR; - aPathname.Truncate(); nsCOMPtr<nsIURI> uri; nsresult result = NS_OK; result = GetURI(getter_AddRefs(uri)); nsCOMPtr<nsIURL> url(do_QueryInterface(uri)); @@ -606,19 +582,16 @@ nsLocation::GetPathname(nsAString& aPath } return result; } NS_IMETHODIMP nsLocation::SetPathname(const nsAString& aPathname) { - if (!CallerSubsumes()) - return NS_ERROR_DOM_SECURITY_ERR; - nsCOMPtr<nsIURI> uri; nsresult rv = GetWritableURI(getter_AddRefs(uri)); if (NS_WARN_IF(NS_FAILED(rv) || !uri)) { return rv; } rv = uri->SetPath(NS_ConvertUTF16toUTF8(aPathname)); if (NS_WARN_IF(NS_FAILED(rv))) { @@ -626,19 +599,16 @@ nsLocation::SetPathname(const nsAString& } return SetURI(uri); } NS_IMETHODIMP nsLocation::GetPort(nsAString& aPort) { - if (!CallerSubsumes()) - return NS_ERROR_DOM_SECURITY_ERR; - aPort.SetLength(0); nsCOMPtr<nsIURI> uri; nsresult result = NS_OK; result = GetURI(getter_AddRefs(uri), true); if (uri) { @@ -656,19 +626,16 @@ nsLocation::GetPort(nsAString& aPort) } return result; } NS_IMETHODIMP nsLocation::SetPort(const nsAString& aPort) { - if (!CallerSubsumes()) - return NS_ERROR_DOM_SECURITY_ERR; - nsCOMPtr<nsIURI> uri; nsresult rv = GetWritableURI(getter_AddRefs(uri)); if (NS_WARN_IF(NS_FAILED(rv) || !uri)) { return rv; } // perhaps use nsReadingIterators at some point? NS_ConvertUTF16toUTF8 portStr(aPort); @@ -690,19 +657,16 @@ nsLocation::SetPort(const nsAString& aPo } return SetURI(uri); } NS_IMETHODIMP nsLocation::GetProtocol(nsAString& aProtocol) { - if (!CallerSubsumes()) - return NS_ERROR_DOM_SECURITY_ERR; - aProtocol.SetLength(0); nsCOMPtr<nsIURI> uri; nsresult result = NS_OK; result = GetURI(getter_AddRefs(uri)); if (uri) { @@ -717,19 +681,16 @@ nsLocation::GetProtocol(nsAString& aProt } return result; } NS_IMETHODIMP nsLocation::SetProtocol(const nsAString& aProtocol) { - if (!CallerSubsumes()) - return NS_ERROR_DOM_SECURITY_ERR; - nsCOMPtr<nsIURI> uri; nsresult rv = GetWritableURI(getter_AddRefs(uri)); if (NS_WARN_IF(NS_FAILED(rv) || !uri)) { return rv; } rv = uri->SetScheme(NS_ConvertUTF16toUTF8(aProtocol)); if (NS_WARN_IF(NS_FAILED(rv))) { @@ -737,40 +698,34 @@ nsLocation::SetProtocol(const nsAString& } return SetURI(uri); } void nsLocation::GetUsername(nsAString& aUsername, ErrorResult& aError) { - if (!CallerSubsumes()) { - aError.Throw(NS_ERROR_DOM_SECURITY_ERR); - return; - } + THROW_AND_RETURN_IF_CALLER_DOESNT_SUBSUME(); aUsername.Truncate(); nsCOMPtr<nsIURI> uri; nsresult result = GetURI(getter_AddRefs(uri)); if (uri) { nsAutoCString username; result = uri->GetUsername(username); if (NS_SUCCEEDED(result)) { CopyUTF8toUTF16(username, aUsername); } } } void nsLocation::SetUsername(const nsAString& aUsername, ErrorResult& aError) { - if (!CallerSubsumes()) { - aError.Throw(NS_ERROR_DOM_SECURITY_ERR); - return; - } + THROW_AND_RETURN_IF_CALLER_DOESNT_SUBSUME(); nsCOMPtr<nsIURI> uri; nsresult rv = GetWritableURI(getter_AddRefs(uri)); if (NS_WARN_IF(NS_FAILED(rv))) { aError.Throw(rv); return; } @@ -785,40 +740,34 @@ nsLocation::SetUsername(const nsAString& } rv = SetURI(uri); } void nsLocation::GetPassword(nsAString& aPassword, ErrorResult& aError) { - if (!CallerSubsumes()) { - aError.Throw(NS_ERROR_DOM_SECURITY_ERR); - return; - } + THROW_AND_RETURN_IF_CALLER_DOESNT_SUBSUME(); aPassword.Truncate(); nsCOMPtr<nsIURI> uri; nsresult result = GetURI(getter_AddRefs(uri)); if (uri) { nsAutoCString password; result = uri->GetPassword(password); if (NS_SUCCEEDED(result)) { CopyUTF8toUTF16(password, aPassword); } } } void nsLocation::SetPassword(const nsAString& aPassword, ErrorResult& aError) { - if (!CallerSubsumes()) { - aError.Throw(NS_ERROR_DOM_SECURITY_ERR); - return; - } + THROW_AND_RETURN_IF_CALLER_DOESNT_SUBSUME(); nsCOMPtr<nsIURI> uri; nsresult rv = GetWritableURI(getter_AddRefs(uri)); if (NS_WARN_IF(NS_FAILED(rv))) { aError.Throw(rv); return; } @@ -833,19 +782,16 @@ nsLocation::SetPassword(const nsAString& } rv = SetURI(uri); } NS_IMETHODIMP nsLocation::GetSearch(nsAString& aSearch) { - if (!CallerSubsumes()) - return NS_ERROR_DOM_SECURITY_ERR; - aSearch.SetLength(0); nsCOMPtr<nsIURI> uri; nsresult result = NS_OK; result = GetURI(getter_AddRefs(uri)); nsCOMPtr<nsIURL> url(do_QueryInterface(uri)); @@ -873,19 +819,16 @@ nsLocation::SetSearch(const nsAString& a } return NS_OK; } nsresult nsLocation::SetSearchInternal(const nsAString& aSearch) { - if (!CallerSubsumes()) - return NS_ERROR_DOM_SECURITY_ERR; - nsCOMPtr<nsIURI> uri; nsresult rv = GetWritableURI(getter_AddRefs(uri)); nsCOMPtr<nsIURL> url(do_QueryInterface(uri)); if (NS_WARN_IF(NS_FAILED(rv) || !url)) { return rv; } @@ -895,19 +838,16 @@ nsLocation::SetSearchInternal(const nsAS } return SetURI(uri); } NS_IMETHODIMP nsLocation::Reload(bool aForceget) { - if (!CallerSubsumes()) - return NS_ERROR_DOM_SECURITY_ERR; - nsresult rv; nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mDocShell)); nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(docShell)); nsCOMPtr<nsPIDOMWindow> window = docShell ? docShell->GetWindow() : nullptr; if (window && window->IsHandlingResizeEvent()) { // location.reload() was called on a window that is handling a // resize event. Sites do this since Netscape 4.x needed it, but @@ -967,19 +907,16 @@ nsLocation::Replace(const nsAString& aUr NS_ENSURE_SUCCESS(rv, rv); return SetHrefWithBase(aUrl, oldUri, true); } NS_IMETHODIMP nsLocation::Assign(const nsAString& aUrl) { - if (!CallerSubsumes()) - return NS_ERROR_DOM_SECURITY_ERR; - nsAutoString oldHref; nsresult result = NS_OK; result = GetHref(oldHref); if (NS_SUCCEEDED(result)) { nsCOMPtr<nsIURI> oldUri; @@ -991,17 +928,16 @@ nsLocation::Assign(const nsAString& aUrl } return result; } NS_IMETHODIMP nsLocation::ToString(nsAString& aReturn) { - // NB: GetHref checks CallerSubsumes(). return GetHref(aReturn); } NS_IMETHODIMP nsLocation::ValueOf(nsIDOMLocation** aReturn) { nsCOMPtr<nsIDOMLocation> loc(this); loc.forget(aReturn);
--- a/dom/base/nsLocation.h +++ b/dom/base/nsLocation.h @@ -37,104 +37,132 @@ public: nsIDOMLocation) void SetDocShell(nsIDocShell *aDocShell); nsIDocShell *GetDocShell(); // nsIDOMLocation NS_DECL_NSIDOMLOCATION + #define THROW_AND_RETURN_IF_CALLER_DOESNT_SUBSUME() { \ + if (!CallerSubsumes()) { \ + aError.Throw(NS_ERROR_DOM_SECURITY_ERR); \ + return; \ + } \ + } + // WebIDL API: void Assign(const nsAString& aUrl, ErrorResult& aError) { + THROW_AND_RETURN_IF_CALLER_DOESNT_SUBSUME(); aError = Assign(aUrl); } + void Replace(const nsAString& aUrl, ErrorResult& aError) { aError = Replace(aUrl); } + void Reload(bool aForceget, ErrorResult& aError) { + THROW_AND_RETURN_IF_CALLER_DOESNT_SUBSUME(); aError = Reload(aForceget); } void GetHref(nsAString& aHref, ErrorResult& aError) { + THROW_AND_RETURN_IF_CALLER_DOESNT_SUBSUME(); aError = GetHref(aHref); } void SetHref(const nsAString& aHref, ErrorResult& aError) { aError = SetHref(aHref); } void GetOrigin(nsAString& aOrigin, ErrorResult& aError) { + THROW_AND_RETURN_IF_CALLER_DOESNT_SUBSUME(); aError = GetOrigin(aOrigin); } void GetProtocol(nsAString& aProtocol, ErrorResult& aError) { + THROW_AND_RETURN_IF_CALLER_DOESNT_SUBSUME(); aError = GetProtocol(aProtocol); } void SetProtocol(const nsAString& aProtocol, ErrorResult& aError) { + THROW_AND_RETURN_IF_CALLER_DOESNT_SUBSUME(); aError = SetProtocol(aProtocol); } void GetUsername(nsAString& aUsername, ErrorResult& aError); void SetUsername(const nsAString& aUsername, ErrorResult& aError); void GetPassword(nsAString& aPassword, ErrorResult& aError); void SetPassword(const nsAString& aPassword, ErrorResult& aError); void GetHost(nsAString& aHost, ErrorResult& aError) { + THROW_AND_RETURN_IF_CALLER_DOESNT_SUBSUME(); aError = GetHost(aHost); } void SetHost(const nsAString& aHost, ErrorResult& aError) { + THROW_AND_RETURN_IF_CALLER_DOESNT_SUBSUME(); aError = SetHost(aHost); } void GetHostname(nsAString& aHostname, ErrorResult& aError) { + THROW_AND_RETURN_IF_CALLER_DOESNT_SUBSUME(); aError = GetHostname(aHostname); } void SetHostname(const nsAString& aHostname, ErrorResult& aError) { + THROW_AND_RETURN_IF_CALLER_DOESNT_SUBSUME(); aError = SetHostname(aHostname); } void GetPort(nsAString& aPort, ErrorResult& aError) { + THROW_AND_RETURN_IF_CALLER_DOESNT_SUBSUME(); aError = GetPort(aPort); } void SetPort(const nsAString& aPort, ErrorResult& aError) { + THROW_AND_RETURN_IF_CALLER_DOESNT_SUBSUME(); aError = SetPort(aPort); } void GetPathname(nsAString& aPathname, ErrorResult& aError) { + THROW_AND_RETURN_IF_CALLER_DOESNT_SUBSUME(); aError = GetPathname(aPathname); } void SetPathname(const nsAString& aPathname, ErrorResult& aError) { + THROW_AND_RETURN_IF_CALLER_DOESNT_SUBSUME(); aError = SetPathname(aPathname); } void GetSearch(nsAString& aSeach, ErrorResult& aError) { + THROW_AND_RETURN_IF_CALLER_DOESNT_SUBSUME(); aError = GetSearch(aSeach); } void SetSearch(const nsAString& aSeach, ErrorResult& aError) { + THROW_AND_RETURN_IF_CALLER_DOESNT_SUBSUME(); aError = SetSearch(aSeach); } void GetHash(nsAString& aHash, ErrorResult& aError) { + THROW_AND_RETURN_IF_CALLER_DOESNT_SUBSUME(); aError = GetHash(aHash); } void SetHash(const nsAString& aHash, ErrorResult& aError) { + THROW_AND_RETURN_IF_CALLER_DOESNT_SUBSUME(); aError = SetHash(aHash); } void Stringify(nsAString& aRetval, ErrorResult& aError) { + // GetHref checks CallerSubsumes. GetHref(aRetval, aError); } nsPIDOMWindow* GetParentObject() const { return mInnerWindow; } virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
--- a/dom/base/nsXMLHttpRequest.cpp +++ b/dom/base/nsXMLHttpRequest.cpp @@ -2699,17 +2699,18 @@ nsXMLHttpRequest::Send(nsIVariant* aVari net::InScriptableRange(size_u64) ? static_cast<int64_t>(size_u64) : -1; if (postDataStream) { // If no content type header was set by the client, we set it to // application/xml. nsAutoCString contentType; if (NS_FAILED(httpChannel-> GetRequestHeader(NS_LITERAL_CSTRING("Content-Type"), - contentType))) { + contentType)) || + contentType.IsEmpty()) { contentType = defaultContentType; if (!charset.IsEmpty()) { // If we are providing the default content type, then we also need to // provide a charset declaration. contentType.Append(NS_LITERAL_CSTRING(";charset=")); contentType.Append(charset); }
--- a/dom/canvas/WebGL2Context.cpp +++ b/dom/canvas/WebGL2Context.cpp @@ -175,14 +175,12 @@ WebGLContext::InitWebGL2() } mBoundTransformFeedbackBuffers.SetLength(mGLMaxTransformFeedbackSeparateAttribs); mBoundUniformBuffers.SetLength(mGLMaxUniformBufferBindings); mDefaultTransformFeedback = new WebGLTransformFeedback(this, 0); mBoundTransformFeedback = mDefaultTransformFeedback; - mBypassShaderValidation = true; - return true; } } // namespace mozilla
--- a/dom/canvas/WebGLShaderValidator.cpp +++ b/dom/canvas/WebGLShaderValidator.cpp @@ -94,17 +94,17 @@ ChooseValidatorCompileOptions(const ShBu //////////////////////////////////////// webgl::ShaderValidator* WebGLContext::CreateShaderValidator(GLenum shaderType) const { if (mBypassShaderValidation) return nullptr; - ShShaderSpec spec = SH_WEBGL_SPEC; + ShShaderSpec spec = IsWebGL2() ? SH_WEBGL2_SPEC : SH_WEBGL_SPEC; ShShaderOutput outputLanguage = gl->IsGLES() ? SH_ESSL_OUTPUT : SH_GLSL_OUTPUT; ShBuiltInResources resources; memset(&resources, 0, sizeof(resources)); ShInitBuiltInResources(&resources); resources.HashFunction = webgl::IdentifierHashFunc;
--- a/dom/canvas/test/webgl-mochitest/webgl-util.js +++ b/dom/canvas/test/webgl-mochitest/webgl-util.js @@ -57,16 +57,17 @@ WebGLUtil = (function() { return gl; } function withWebGL2(canvasId, callback, onFinished) { var prefArrArr = [ ['webgl.force-enabled', true], ['webgl.disable-angle', true], + ['webgl.bypass-shader-validation', true], ['webgl.enable-prototype-webgl2', true], ]; var prefEnv = {'set': prefArrArr}; SpecialPowers.pushPrefEnv(prefEnv, function() { var canvas = document.getElementById(canvasId); var gl = null; try {
--- a/dom/crypto/test/test_WebCrypto_ECDH.html +++ b/dom/crypto/test/test_WebCrypto_ECDH.html @@ -368,17 +368,17 @@ TestArray.addTest( Promise.all([ crypto.subtle.importKey("jwk", tv.ecdh_p521.jwk_priv, alg, false, ["deriveKey"]) .then(setPriv), crypto.subtle.importKey("jwk", tv.ecdh_p521.jwk_pub, alg, false, ["deriveKey"]) .then(setPub) ]).then(doDerive) .then(doSignAndVerify) - .then(complete(that), error(that)); + .then(complete(that, x => x), error(that)); } ); // ----------------------------------------------------------------------------- TestArray.addTest( "SPKI import/export of public ECDH keys (P-256)", function () { var that = this;
--- a/dom/crypto/test/test_WebCrypto_ECDSA.html +++ b/dom/crypto/test/test_WebCrypto_ECDSA.html @@ -50,25 +50,25 @@ TestArray.addTest( } ); // ----------------------------------------------------------------------------- TestArray.addTest( "ECDSA JWK import and verify a known-good signature", function() { var that = this; - var alg = { name: "ECDSA", namedCurve: "P-256", hash: "SHA-256" }; + var alg = { name: "ECDSA", namedCurve: "P-521", hash: "SHA-512" }; function doVerify(x) { return crypto.subtle.verify(alg, x, tv.ecdsa_verify.sig, tv.ecdsa_verify.data); } crypto.subtle.importKey("jwk", tv.ecdsa_verify.pub_jwk, alg, true, ["verify"]) .then(doVerify) - .then(complete(that), error(that)) + .then(complete(that, x => x), error(that)) } ); // ----------------------------------------------------------------------------- TestArray.addTest( "ECDSA key generation with public key export", function() { var that = this; @@ -77,17 +77,17 @@ TestArray.addTest( crypto.subtle.generateKey(alg, false, ["sign", "verify"]) .then(pair => Promise.all([ crypto.subtle.sign(alg, pair.privateKey, msg), crypto.subtle.exportKey("spki", pair.publicKey) .then(spki => crypto.subtle.importKey("spki", spki, alg, false, ["verify"])) ])) .then(sigAndKey => crypto.subtle.verify(alg, sigAndKey[1], sigAndKey[0], msg)) - .then(complete(that), error(that)) + .then(complete(that, x => x), error(that)) } ); // ----------------------------------------------------------------------------- TestArray.addTest( "ECDSA JWK import and reject a known-bad signature", function() { var that = this; @@ -119,17 +119,17 @@ TestArray.addTest( } function doVerify(sig) { return crypto.subtle.verify(alg, pubKey, sig, tv.ecdsa_verify.data); } crypto.subtle.generateKey(alg, true, ["sign", "verify"]) .then(doSign) .then(doVerify) - .then(complete(that), error(that)) + .then(complete(that, x => x), error(that)) } ); // ----------------------------------------------------------------------------- TestArray.addTest( "Verify that ECDSA import fails with a known-bad public key", function() { var that = this; @@ -169,17 +169,17 @@ TestArray.addTest( var alg = { name: "ECDSA", namedCurve: "P-521", hash: "SHA-512" }; function doVerify(x) { return crypto.subtle.verify(alg, x, tv.ecdsa_verify.sig, tv.ecdsa_verify.data); } crypto.subtle.importKey("raw", tv.ecdsa_verify.raw, alg, true, ["verify"]) .then(doVerify) - .then(complete(that), error(that)) + .then(complete(that, x => x), error(that)) } ); /*]]>*/</script> </head> <body>
--- a/dom/crypto/test/test_WebCrypto_PBKDF2.html +++ b/dom/crypto/test/test_WebCrypto_PBKDF2.html @@ -114,17 +114,17 @@ TestArray.addTest( }); } function fail(x) { console.log("failing"); error(that)(x); } crypto.subtle.importKey("raw", key, alg, false, ["deriveKey"]) .then( doDerive, fail ) .then( doSignAndVerify, fail ) - .then( complete(that), fail ); + .then( complete(that, x => x), fail ); } ); // ----------------------------------------------------------------------------- TestArray.addTest( "Import raw PBKDF2 key and derive a new key using HMAC-SHA-1 with custom length", function() { var that = this;
--- a/dom/ipc/ContentChild.cpp +++ b/dom/ipc/ContentChild.cpp @@ -895,16 +895,42 @@ private: nsRefPtr<MemoryReportRequestChild> mActor; const nsCString mProcess; }; NS_IMPL_ISUPPORTS( MemoryReportCallback , nsIMemoryReporterCallback ) +class MemoryReportFinishedCallback final : public nsIFinishReportingCallback +{ +public: + NS_DECL_ISUPPORTS + + explicit MemoryReportFinishedCallback(MemoryReportRequestChild* aActor) + : mActor(aActor) + { + } + + NS_IMETHOD Callback(nsISupports* aUnused) override + { + bool sent = PMemoryReportRequestChild::Send__delete__(mActor); + return sent ? NS_OK : NS_ERROR_FAILURE; + } + +private: + ~MemoryReportFinishedCallback() {} + + nsRefPtr<MemoryReportRequestChild> mActor; +}; +NS_IMPL_ISUPPORTS( + MemoryReportFinishedCallback +, nsIFinishReportingCallback +) + bool ContentChild::RecvPMemoryReportRequestConstructor( PMemoryReportRequestChild* aChild, const uint32_t& aGeneration, const bool& aAnonymize, const bool& aMinimizeMemoryUsage, const MaybeFileDesc& aDMDFile) { @@ -931,21 +957,22 @@ NS_IMETHODIMP MemoryReportRequestChild:: nsCString process; child->GetProcessName(process); child->AppendProcessId(process); // Run the reporters. The callback will turn each measurement into a // MemoryReport. nsRefPtr<MemoryReportCallback> cb = new MemoryReportCallback(this, process); - mgr->GetReportsForThisProcessExtended(cb, nullptr, mAnonymize, - FileDescriptorToFILE(mDMDFile, "wb")); - - bool sent = Send__delete__(this); - return sent ? NS_OK : NS_ERROR_FAILURE; + nsRefPtr<MemoryReportFinishedCallback> finished = + new MemoryReportFinishedCallback(this); + + return mgr->GetReportsForThisProcessExtended(cb, nullptr, mAnonymize, + FileDescriptorToFILE(mDMDFile, "wb"), + finished, nullptr); } bool ContentChild::RecvDataStoreNotify(const uint32_t& aAppId, const nsString& aName, const nsString& aManifestURL) { nsRefPtr<DataStoreService> service = DataStoreService::GetOrCreate();
--- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -19,16 +19,17 @@ #include <sys/types.h> #include <sys/wait.h> #endif #include "chrome/common/process_watcher.h" #include <set> +#include "mozilla/a11y/PDocAccessible.h" #include "AppProcessChecker.h" #include "AudioChannelService.h" #include "BlobParent.h" #include "CrashReporterParent.h" #include "GMPServiceParent.h" #include "IHistory.h" #include "imgIContainer.h" #include "mozIApplication.h" @@ -5471,8 +5472,24 @@ NS_IMPL_ISUPPORTS(ParentIdleListener, ns NS_IMETHODIMP ParentIdleListener::Observe(nsISupports*, const char* aTopic, const char16_t* aData) { mozilla::unused << mParent->SendNotifyIdleObserver(mObserver, nsDependentCString(aTopic), nsDependentString(aData)); return NS_OK; } + +bool +ContentParent::HandleWindowsMessages(const Message& aMsg) const +{ + MOZ_ASSERT(aMsg.is_sync()); + + // a11y messages can be triggered by windows messages, which means if we + // allow handling windows messages while we wait for the response to a sync + // a11y message we can reenter the ipc message sending code. + if (a11y::PDocAccessible::PDocAccessibleStart < aMsg.type() && + a11y::PDocAccessible::PDocAccessibleEnd > aMsg.type()) { + return false; + } + + return true; +}
--- a/dom/ipc/ContentParent.h +++ b/dom/ipc/ContentParent.h @@ -422,16 +422,18 @@ public: virtual PContentPermissionRequestParent* AllocPContentPermissionRequestParent(const InfallibleTArray<PermissionRequest>& aRequests, const IPC::Principal& aPrincipal, const TabId& aTabId) override; virtual bool DeallocPContentPermissionRequestParent(PContentPermissionRequestParent* actor) override; + virtual bool HandleWindowsMessages(const Message& aMsg) const override; + bool HasGamepadListener() const { return mHasGamepadListener; } void SetNuwaParent(NuwaParent* aNuwaParent) { mNuwaParent = aNuwaParent; } void ForkNewProcess(bool aBlocking); protected: void OnChannelConnected(int32_t pid) override; virtual void ActorDestroy(ActorDestroyReason why) override;
--- a/dom/locales/en-US/chrome/dom/dom.properties +++ b/dom/locales/en-US/chrome/dom/dom.properties @@ -102,16 +102,18 @@ MediaLoadInvalidURI=Invalid URI. Load of # LOCALIZATION NOTE: %1$S is the media resource's format/codec type (basically equivalent to the file type, e.g. MP4,AVI,WMV,MOV etc), %2$S is the URL of the media resource which failed to load. MediaLoadUnsupportedTypeAttribute=Specified "type" attribute of "%1$S" is not supported. Load of media resource %2$S failed. # LOCALIZATION NOTE: %1$S is the "media" attribute value of the <source> element. It is a media query. %2$S is the URL of the media resource which failed to load. MediaLoadSourceMediaNotMatched=Specified "media" attribute of "%1$S" does not match the environment. Load of media resource %2$S failed. # LOCALIZATION NOTE: %1$S is the MIME type HTTP header being sent by the web server, %2$S is the URL of the media resource which failed to load. MediaLoadUnsupportedMimeType=HTTP "Content-Type" of "%1$S" is not supported. Load of media resource %2$S failed. # LOCALIZATION NOTE: %S is the URL of the media resource which failed to load because of error in decoding. MediaLoadDecodeError=Media resource %S could not be decoded. +# LOCALIZATION NOTE: %S is the ID of the MediaStreamTrack passed to MediaStream.addTrack(). Do not translate "MediaStreamTrack" and "AudioChannel". +MediaStreamAddTrackDifferentAudioChannel=MediaStreamTrack %S could not be added since it belongs to a different AudioChannel. # LOCALIZATION NOTE: Do not translate "MediaStream", "stop()" and "MediaStreamTrack" MediaStreamStopDeprecatedWarning=MediaStream.stop() is deprecated and will soon be removed. Use MediaStreamTrack.stop() instead. # LOCALIZATION NOTE: Do not translate "DOMException", "code" and "name" DOMExceptionCodeWarning=Use of DOMException's code attribute is deprecated. Use name instead. # LOCALIZATION NOTE: Do not translate "__exposedProps__" NoExposedPropsWarning=Exposing chrome JS objects to content without __exposedProps__ is insecure and deprecated. See https://developer.mozilla.org/en/XPConnect_wrappers for more information. # LOCALIZATION NOTE: Do not translate "Mutation Event" and "MutationObserver" MutationEventWarning=Use of Mutation Events is deprecated. Use MutationObserver instead.
--- a/dom/media/DOMMediaStream.cpp +++ b/dom/media/DOMMediaStream.cpp @@ -416,16 +416,82 @@ DOMMediaStream::Destroy() } JSObject* DOMMediaStream::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) { return dom::MediaStreamBinding::Wrap(aCx, this, aGivenProto); } +/* static */ already_AddRefed<DOMMediaStream> +DOMMediaStream::Constructor(const GlobalObject& aGlobal, + ErrorResult& aRv) +{ + Sequence<OwningNonNull<MediaStreamTrack>> emptyTrackSeq; + return Constructor(aGlobal, emptyTrackSeq, aRv); +} + +/* static */ already_AddRefed<DOMMediaStream> +DOMMediaStream::Constructor(const GlobalObject& aGlobal, + const DOMMediaStream& aStream, + ErrorResult& aRv) +{ + nsTArray<nsRefPtr<MediaStreamTrack>> tracks; + aStream.GetTracks(tracks); + + Sequence<OwningNonNull<MediaStreamTrack>> nonNullTrackSeq; + if (!nonNullTrackSeq.SetLength(tracks.Length(), fallible)) { + MOZ_ASSERT(false); + aRv.Throw(NS_ERROR_OUT_OF_MEMORY); + return nullptr; + } + + for (size_t i = 0; i < tracks.Length(); ++i) { + nonNullTrackSeq[i] = tracks[i]; + } + + return Constructor(aGlobal, nonNullTrackSeq, aRv); +} + +/* static */ already_AddRefed<DOMMediaStream> +DOMMediaStream::Constructor(const GlobalObject& aGlobal, + const Sequence<OwningNonNull<MediaStreamTrack>>& aTracks, + ErrorResult& aRv) +{ + nsCOMPtr<nsIDOMWindow> ownerWindow = do_QueryInterface(aGlobal.GetAsSupports()); + if (!ownerWindow) { + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; + } + + nsRefPtr<DOMMediaStream> newStream = new DOMMediaStream(); + newStream->mWindow = ownerWindow; + + for (MediaStreamTrack& track : aTracks) { + if (!newStream->GetPlaybackStream()) { + MOZ_RELEASE_ASSERT(track.GetStream()); + MOZ_RELEASE_ASSERT(track.GetStream()->GetPlaybackStream()); + MOZ_RELEASE_ASSERT(track.GetStream()->GetPlaybackStream()->Graph()); + MediaStreamGraph* graph = track.GetStream()->GetPlaybackStream()->Graph(); + newStream->InitPlaybackStreamCommon(graph); + } + newStream->AddTrack(track); + } + + if (!newStream->GetPlaybackStream()) { + MOZ_ASSERT(aTracks.IsEmpty()); + MediaStreamGraph* graph = + MediaStreamGraph::GetInstance(MediaStreamGraph::SYSTEM_THREAD_DRIVER, + AudioChannel::Normal); + newStream->InitPlaybackStreamCommon(graph); + } + + return newStream.forget(); +} + double DOMMediaStream::CurrentTime() { if (!mPlaybackStream) { return 0.0; } return mPlaybackStream-> StreamTimeToSeconds(mPlaybackStream->GetCurrentTime() - mLogicalStreamStartTime); @@ -433,57 +499,80 @@ DOMMediaStream::CurrentTime() void DOMMediaStream::GetId(nsAString& aID) const { aID = mID; } void -DOMMediaStream::GetAudioTracks(nsTArray<nsRefPtr<AudioStreamTrack> >& aTracks) +DOMMediaStream::GetAudioTracks(nsTArray<nsRefPtr<AudioStreamTrack> >& aTracks) const { for (const nsRefPtr<TrackPort>& info : mTracks) { AudioStreamTrack* t = info->GetTrack()->AsAudioStreamTrack(); if (t) { aTracks.AppendElement(t); } } } void -DOMMediaStream::GetVideoTracks(nsTArray<nsRefPtr<VideoStreamTrack> >& aTracks) +DOMMediaStream::GetVideoTracks(nsTArray<nsRefPtr<VideoStreamTrack> >& aTracks) const { for (const nsRefPtr<TrackPort>& info : mTracks) { VideoStreamTrack* t = info->GetTrack()->AsVideoStreamTrack(); if (t) { aTracks.AppendElement(t); } } } void -DOMMediaStream::GetTracks(nsTArray<nsRefPtr<MediaStreamTrack> >& aTracks) +DOMMediaStream::GetTracks(nsTArray<nsRefPtr<MediaStreamTrack> >& aTracks) const { for (const nsRefPtr<TrackPort>& info : mTracks) { aTracks.AppendElement(info->GetTrack()); } } void DOMMediaStream::AddTrack(MediaStreamTrack& aTrack) { + MOZ_RELEASE_ASSERT(mPlaybackStream); + RefPtr<ProcessedMediaStream> dest = mPlaybackStream->AsProcessedStream(); MOZ_ASSERT(dest); if (!dest) { return; } LOG(LogLevel::Info, ("DOMMediaStream %p Adding track %p (from stream %p with ID %d)", this, &aTrack, aTrack.GetStream(), aTrack.GetTrackID())); + if (mPlaybackStream->Graph() != + aTrack.GetStream()->mPlaybackStream->Graph()) { + NS_ASSERTION(false, "Cannot combine tracks from different MediaStreamGraphs"); + LOG(LogLevel::Error, ("DOMMediaStream %p Own MSG %p != aTrack's MSG %p", + this, mPlaybackStream->Graph(), + aTrack.GetStream()->mPlaybackStream->Graph())); + + nsAutoString trackId; + aTrack.GetId(trackId); + const char16_t* params[] = { trackId.get() }; + nsCOMPtr<nsPIDOMWindow> pWindow = do_QueryInterface(GetParentObject()); + nsIDocument* document = pWindow ? pWindow->GetExtantDoc() : nullptr; + nsContentUtils::ReportToConsole(nsIScriptError::errorFlag, + NS_LITERAL_CSTRING("Media"), + document, + nsContentUtils::eDOM_PROPERTIES, + "MediaStreamAddTrackDifferentAudioChannel", + params, ArrayLength(params)); + return; + } + if (HasTrack(aTrack)) { LOG(LogLevel::Debug, ("DOMMediaStream %p already contains track %p", this, &aTrack)); return; } RefPtr<DOMMediaStream> addedDOMStream = aTrack.GetStream(); MOZ_RELEASE_ASSERT(addedDOMStream); @@ -544,63 +633,86 @@ DOMMediaStream::IsFinished() return !mPlaybackStream || mPlaybackStream->IsFinished(); } void DOMMediaStream::InitSourceStream(nsIDOMWindow* aWindow, MediaStreamGraph* aGraph) { mWindow = aWindow; - InitStreamCommon(aGraph->CreateSourceStream(nullptr), aGraph); + InitInputStreamCommon(aGraph->CreateSourceStream(nullptr), aGraph); + InitOwnedStreamCommon(aGraph); + InitPlaybackStreamCommon(aGraph); } void DOMMediaStream::InitTrackUnionStream(nsIDOMWindow* aWindow, MediaStreamGraph* aGraph) { mWindow = aWindow; - InitStreamCommon(aGraph->CreateTrackUnionStream(nullptr), aGraph); + InitInputStreamCommon(aGraph->CreateTrackUnionStream(nullptr), aGraph); + InitOwnedStreamCommon(aGraph); + InitPlaybackStreamCommon(aGraph); } void DOMMediaStream::InitAudioCaptureStream(nsIDOMWindow* aWindow, MediaStreamGraph* aGraph) { mWindow = aWindow; const TrackID AUDIO_TRACK = 1; - InitStreamCommon(aGraph->CreateAudioCaptureStream(this, AUDIO_TRACK), aGraph); + InitInputStreamCommon(aGraph->CreateAudioCaptureStream(this, AUDIO_TRACK), aGraph); + InitOwnedStreamCommon(aGraph); + InitPlaybackStreamCommon(aGraph); CreateOwnDOMTrack(AUDIO_TRACK, MediaSegment::AUDIO); } void -DOMMediaStream::InitStreamCommon(MediaStream* aStream, - MediaStreamGraph* aGraph) +DOMMediaStream::InitInputStreamCommon(MediaStream* aStream, + MediaStreamGraph* aGraph) { + MOZ_ASSERT(!mOwnedStream, "Input stream must be initialized before owned stream"); + mInputStream = aStream; +} + +void +DOMMediaStream::InitOwnedStreamCommon(MediaStreamGraph* aGraph) +{ + MOZ_ASSERT(!mPlaybackStream, "Owned stream must be initialized before playback stream"); // We pass null as the wrapper since it is only used to signal finished // streams. This is only needed for the playback stream. mOwnedStream = aGraph->CreateTrackUnionStream(nullptr); mOwnedStream->SetAutofinish(true); - mOwnedPort = mOwnedStream->AllocateInputPort(mInputStream); - - mPlaybackStream = aGraph->CreateTrackUnionStream(this); - mPlaybackStream->SetAutofinish(true); - mPlaybackPort = mPlaybackStream->AllocateInputPort(mOwnedStream); - - LOG(LogLevel::Debug, ("DOMMediaStream %p Initiated with mInputStream=%p, mOwnedStream=%p, mPlaybackStream=%p", - this, mInputStream, mOwnedStream, mPlaybackStream)); + if (mInputStream) { + mOwnedPort = mOwnedStream->AllocateInputPort(mInputStream); + } // Setup track listeners mOwnedListener = new OwnedStreamListener(this); mOwnedStream->AddListener(mOwnedListener); +} + +void +DOMMediaStream::InitPlaybackStreamCommon(MediaStreamGraph* aGraph) +{ + mPlaybackStream = aGraph->CreateTrackUnionStream(this); + mPlaybackStream->SetAutofinish(true); + if (mOwnedStream) { + mPlaybackPort = mPlaybackStream->AllocateInputPort(mOwnedStream); + } + mPlaybackListener = new PlaybackStreamListener(this); mPlaybackStream->AddListener(mPlaybackListener); + + LOG(LogLevel::Debug, ("DOMMediaStream %p Initiated with mInputStream=%p, mOwnedStream=%p, mPlaybackStream=%p", + this, mInputStream, mOwnedStream, mPlaybackStream)); } already_AddRefed<DOMMediaStream> DOMMediaStream::CreateSourceStream(nsIDOMWindow* aWindow, MediaStreamGraph* aGraph) { nsRefPtr<DOMMediaStream> stream = new DOMMediaStream(); stream->InitSourceStream(aWindow, aGraph); @@ -700,16 +812,19 @@ bool DOMMediaStream::RemovePrincipalChangeObserver(PrincipalChangeObserver* aObserver) { return mPrincipalChangeObservers.RemoveElement(aObserver); } MediaStreamTrack* DOMMediaStream::CreateOwnDOMTrack(TrackID aTrackID, MediaSegment::Type aType) { + MOZ_RELEASE_ASSERT(mInputStream); + MOZ_RELEASE_ASSERT(mOwnedStream); + MOZ_ASSERT(FindOwnedDOMTrack(GetOwnedStream(), aTrackID) == nullptr); MediaStreamTrack* track; switch (aType) { case MediaSegment::AUDIO: track = new AudioStreamTrack(this, aTrackID); break; case MediaSegment::VIDEO: @@ -731,39 +846,44 @@ DOMMediaStream::CreateOwnDOMTrack(TrackI NotifyTrackAdded(track); return track; } MediaStreamTrack* DOMMediaStream::FindOwnedDOMTrack(MediaStream* aOwningStream, TrackID aTrackID) const { + MOZ_RELEASE_ASSERT(mOwnedStream); + if (aOwningStream != mOwnedStream) { return nullptr; } for (const nsRefPtr<TrackPort>& info : mOwnedTracks) { if (info->GetTrack()->GetTrackID() == aTrackID) { return info->GetTrack(); } } return nullptr; } MediaStreamTrack* DOMMediaStream::FindPlaybackDOMTrack(MediaStream* aInputStream, TrackID aInputTrackID) const { + MOZ_RELEASE_ASSERT(mPlaybackStream); + for (const nsRefPtr<TrackPort>& info : mTracks) { if (info->GetInputPort() == mPlaybackPort && aInputStream == mOwnedStream && aInputTrackID == info->GetTrack()->GetTrackID()) { // This track is in our owned and playback streams. return info->GetTrack(); } - if (info->GetInputPort()->GetSource() == aInputStream && + if (info->GetInputPort() && + info->GetInputPort()->GetSource() == aInputStream && info->GetSourceTrackId() == aInputTrackID) { // This track is owned externally but in our playback stream. MOZ_ASSERT(aInputTrackID != TRACK_NONE); MOZ_ASSERT(aInputTrackID != TRACK_INVALID); MOZ_ASSERT(aInputTrackID != TRACK_ANY); return info->GetTrack(); } }
--- a/dom/media/DOMMediaStream.h +++ b/dom/media/DOMMediaStream.h @@ -218,23 +218,38 @@ public: nsIDOMWindow* GetParentObject() const { return mWindow; } virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override; // WebIDL + + static already_AddRefed<DOMMediaStream> + Constructor(const dom::GlobalObject& aGlobal, + ErrorResult& aRv); + + static already_AddRefed<DOMMediaStream> + Constructor(const dom::GlobalObject& aGlobal, + const DOMMediaStream& aStream, + ErrorResult& aRv); + + static already_AddRefed<DOMMediaStream> + Constructor(const dom::GlobalObject& aGlobal, + const dom::Sequence<OwningNonNull<MediaStreamTrack>>& aTracks, + ErrorResult& aRv); + double CurrentTime(); void GetId(nsAString& aID) const; - void GetAudioTracks(nsTArray<nsRefPtr<AudioStreamTrack> >& aTracks); - void GetVideoTracks(nsTArray<nsRefPtr<VideoStreamTrack> >& aTracks); - void GetTracks(nsTArray<nsRefPtr<MediaStreamTrack> >& aTracks); + void GetAudioTracks(nsTArray<nsRefPtr<AudioStreamTrack> >& aTracks) const; + void GetVideoTracks(nsTArray<nsRefPtr<VideoStreamTrack> >& aTracks) const; + void GetTracks(nsTArray<nsRefPtr<MediaStreamTrack> >& aTracks) const; void AddTrack(MediaStreamTrack& aTrack); void RemoveTrack(MediaStreamTrack& aTrack); // NON-WebIDL /** * Returns true if this DOMMediaStream has aTrack in its mPlaybackStream. */ @@ -352,30 +367,30 @@ public: */ void NotifyStreamFinished(); // Webrtc allows the remote side to name a stream whatever it wants, and we // need to surface this to content. void AssignId(const nsAString& aID) { mID = aID; } /** - * Create an nsDOMMediaStream whose underlying stream is a SourceMediaStream. + * Create a DOMMediaStream whose underlying input stream is a SourceMediaStream. */ static already_AddRefed<DOMMediaStream> CreateSourceStream(nsIDOMWindow* aWindow, MediaStreamGraph* aGraph); /** - * Create an nsDOMMediaStream whose underlying stream is a TrackUnionStream. + * Create a DOMMediaStream whose underlying input stream is a TrackUnionStream. */ static already_AddRefed<DOMMediaStream> CreateTrackUnionStream(nsIDOMWindow* aWindow, MediaStreamGraph* aGraph); /** - * Create an nsDOMMediaStream whose underlying stream is an - * AudioCaptureStream + * Create an DOMMediaStream whose underlying input stream is an + * AudioCaptureStream. */ static already_AddRefed<DOMMediaStream> CreateAudioCaptureStream( nsIDOMWindow* aWindow, MediaStreamGraph* aGraph); void SetLogicalStreamStartTime(StreamTime aTime) { mLogicalStreamStartTime = aTime; } @@ -419,17 +434,33 @@ public: protected: virtual ~DOMMediaStream(); void Destroy(); void InitSourceStream(nsIDOMWindow* aWindow, MediaStreamGraph* aGraph); void InitTrackUnionStream(nsIDOMWindow* aWindow, MediaStreamGraph* aGraph); void InitAudioCaptureStream(nsIDOMWindow* aWindow, MediaStreamGraph* aGraph); - void InitStreamCommon(MediaStream* aStream, MediaStreamGraph* aGraph); + + // Sets up aStream as mInputStream. A producer may append data to a + // SourceMediaStream input stream, or connect another stream to a + // TrackUnionStream input stream. + void InitInputStreamCommon(MediaStream* aStream, MediaStreamGraph* aGraph); + + // Sets up a new TrackUnionStream as mOwnedStream and connects it to + // mInputStream with a TRACK_ANY MediaInputPort if available. + // If this DOMMediaStream should have an input stream (producing data), + // it has to be initiated before the owned stream. + void InitOwnedStreamCommon(MediaStreamGraph* aGraph); + + // Sets up a new TrackUnionStream as mPlaybackStream and connects it to + // mOwnedStream with a TRACK_ANY MediaInputPort if available. + // If this DOMMediaStream should have an owned stream (producer or clone), + // it has to be initiated before the playback stream. + void InitPlaybackStreamCommon(MediaStreamGraph* aGraph); void CheckTracksAvailable(); // Called when MediaStreamGraph has finished an iteration where tracks were // created. void NotifyTracksCreated(); // Dispatches NotifyTrackAdded() to all registered track listeners.
--- a/dom/media/MediaDecoder.cpp +++ b/dom/media/MediaDecoder.cpp @@ -343,81 +343,81 @@ MediaDecoder::SetInfinite(bool aInfinite bool MediaDecoder::IsInfinite() { MOZ_ASSERT(NS_IsMainThread()); return mInfiniteStream; } -MediaDecoder::MediaDecoder() : - mWatchManager(this, AbstractThread::MainThread()), - mDormantSupported(false), - mLogicalPosition(0.0), - mDuration(std::numeric_limits<double>::quiet_NaN()), +MediaDecoder::MediaDecoder() + : mWatchManager(this, AbstractThread::MainThread()) + , mDormantSupported(false) + , mLogicalPosition(0.0) + , mDuration(std::numeric_limits<double>::quiet_NaN()) #ifdef MOZ_EME - mCDMProxyPromise(mCDMProxyPromiseHolder.Ensure(__func__)), + , mCDMProxyPromise(mCDMProxyPromiseHolder.Ensure(__func__)) #endif - mIgnoreProgressData(false), - mInfiniteStream(false), - mOwner(nullptr), - mPlaybackStatistics(new MediaChannelStatistics()), - mPinnedForSeek(false), - mShuttingDown(false), - mPausedForPlaybackRateNull(false), - mMinimizePreroll(false), - mMediaTracksConstructed(false), - mFiredMetadataLoaded(false), - mIsDormant(false), - mWasEndedWhenEnteredDormant(false), - mIsHeuristicDormantSupported( - Preferences::GetBool("media.decoder.heuristic.dormant.enabled", false)), - mHeuristicDormantTimeout( - Preferences::GetInt("media.decoder.heuristic.dormant.timeout", - DEFAULT_HEURISTIC_DORMANT_TIMEOUT_MSECS)), - mIsHeuristicDormant(false), - mStateMachineIsShutdown(AbstractThread::MainThread(), true, - "MediaDecoder::mStateMachineIsShutdown (Mirror)"), - mBuffered(AbstractThread::MainThread(), TimeIntervals(), - "MediaDecoder::mBuffered (Mirror)"), - mNextFrameStatus(AbstractThread::MainThread(), - MediaDecoderOwner::NEXT_FRAME_UNINITIALIZED, - "MediaDecoder::mNextFrameStatus (Mirror)"), - mCurrentPosition(AbstractThread::MainThread(), 0, - "MediaDecoder::mCurrentPosition (Mirror)"), - mStateMachineDuration(AbstractThread::MainThread(), NullableTimeUnit(), - "MediaDecoder::mStateMachineDuration (Mirror)"), - mPlaybackPosition(AbstractThread::MainThread(), 0, - "MediaDecoder::mPlaybackPosition (Mirror)"), - mVolume(AbstractThread::MainThread(), 0.0, - "MediaDecoder::mVolume (Canonical)"), - mPlaybackRate(AbstractThread::MainThread(), 1.0, - "MediaDecoder::mPlaybackRate (Canonical)"), - mPreservesPitch(AbstractThread::MainThread(), true, - "MediaDecoder::mPreservesPitch (Canonical)"), - mEstimatedDuration(AbstractThread::MainThread(), NullableTimeUnit(), - "MediaDecoder::mEstimatedDuration (Canonical)"), - mExplicitDuration(AbstractThread::MainThread(), Maybe<double>(), - "MediaDecoder::mExplicitDuration (Canonical)"), - mPlayState(AbstractThread::MainThread(), PLAY_STATE_LOADING, - "MediaDecoder::mPlayState (Canonical)"), - mNextState(AbstractThread::MainThread(), PLAY_STATE_PAUSED, - "MediaDecoder::mNextState (Canonical)"), - mLogicallySeeking(AbstractThread::MainThread(), false, - "MediaDecoder::mLogicallySeeking (Canonical)"), - mSameOriginMedia(AbstractThread::MainThread(), false, - "MediaDecoder::mSameOriginMedia (Canonical)"), - mPlaybackBytesPerSecond(AbstractThread::MainThread(), 0.0, - "MediaDecoder::mPlaybackBytesPerSecond (Canonical)"), - mPlaybackRateReliable(AbstractThread::MainThread(), true, - "MediaDecoder::mPlaybackRateReliable (Canonical)"), - mDecoderPosition(AbstractThread::MainThread(), 0, - "MediaDecoder::mDecoderPosition (Canonical)"), - mMediaSeekable(AbstractThread::MainThread(), true, - "MediaDecoder::mMediaSeekable (Canonical)") + , mIgnoreProgressData(false) + , mInfiniteStream(false) + , mOwner(nullptr) + , mPlaybackStatistics(new MediaChannelStatistics()) + , mPinnedForSeek(false) + , mShuttingDown(false) + , mPausedForPlaybackRateNull(false) + , mMinimizePreroll(false) + , mMediaTracksConstructed(false) + , mFiredMetadataLoaded(false) + , mIsDormant(false) + , mWasEndedWhenEnteredDormant(false) + , mIsHeuristicDormantSupported( + Preferences::GetBool("media.decoder.heuristic.dormant.enabled", false)) + , mHeuristicDormantTimeout( + Preferences::GetInt("media.decoder.heuristic.dormant.timeout", + DEFAULT_HEURISTIC_DORMANT_TIMEOUT_MSECS)) + , mIsHeuristicDormant(false) + , mStateMachineIsShutdown(AbstractThread::MainThread(), true, + "MediaDecoder::mStateMachineIsShutdown (Mirror)") + , mBuffered(AbstractThread::MainThread(), TimeIntervals(), + "MediaDecoder::mBuffered (Mirror)") + , mNextFrameStatus(AbstractThread::MainThread(), + MediaDecoderOwner::NEXT_FRAME_UNINITIALIZED, + "MediaDecoder::mNextFrameStatus (Mirror)") + , mCurrentPosition(AbstractThread::MainThread(), 0, + "MediaDecoder::mCurrentPosition (Mirror)") + , mStateMachineDuration(AbstractThread::MainThread(), NullableTimeUnit(), + "MediaDecoder::mStateMachineDuration (Mirror)") + , mPlaybackPosition(AbstractThread::MainThread(), 0, + "MediaDecoder::mPlaybackPosition (Mirror)") + , mVolume(AbstractThread::MainThread(), 0.0, + "MediaDecoder::mVolume (Canonical)") + , mPlaybackRate(AbstractThread::MainThread(), 1.0, + "MediaDecoder::mPlaybackRate (Canonical)") + , mPreservesPitch(AbstractThread::MainThread(), true, + "MediaDecoder::mPreservesPitch (Canonical)") + , mEstimatedDuration(AbstractThread::MainThread(), NullableTimeUnit(), + "MediaDecoder::mEstimatedDuration (Canonical)") + , mExplicitDuration(AbstractThread::MainThread(), Maybe<double>(), + "MediaDecoder::mExplicitDuration (Canonical)") + , mPlayState(AbstractThread::MainThread(), PLAY_STATE_LOADING, + "MediaDecoder::mPlayState (Canonical)") + , mNextState(AbstractThread::MainThread(), PLAY_STATE_PAUSED, + "MediaDecoder::mNextState (Canonical)") + , mLogicallySeeking(AbstractThread::MainThread(), false, + "MediaDecoder::mLogicallySeeking (Canonical)") + , mSameOriginMedia(AbstractThread::MainThread(), false, + "MediaDecoder::mSameOriginMedia (Canonical)") + , mPlaybackBytesPerSecond(AbstractThread::MainThread(), 0.0, + "MediaDecoder::mPlaybackBytesPerSecond (Canonical)") + , mPlaybackRateReliable(AbstractThread::MainThread(), true, + "MediaDecoder::mPlaybackRateReliable (Canonical)") + , mDecoderPosition(AbstractThread::MainThread(), 0, + "MediaDecoder::mDecoderPosition (Canonical)") + , mMediaSeekable(AbstractThread::MainThread(), true, + "MediaDecoder::mMediaSeekable (Canonical)") { MOZ_COUNT_CTOR(MediaDecoder); MOZ_ASSERT(NS_IsMainThread()); MediaMemoryTracker::AddMediaDecoder(this); mAudioChannel = AudioChannelService::GetDefaultAudioChannel(); // @@ -1302,16 +1302,23 @@ size_t MediaDecoder::SizeOfAudioQueue() { MOZ_ASSERT(NS_IsMainThread()); if (mDecoderStateMachine) { return mDecoderStateMachine->SizeOfAudioQueue(); } return 0; } +void MediaDecoder::AddSizeOfResources(ResourceSizes* aSizes) { + MOZ_ASSERT(NS_IsMainThread()); + if (GetResource()) { + aSizes->mByteSize += GetResource()->SizeOfIncludingThis(aSizes->mMallocSizeOf); + } +} + void MediaDecoder::NotifyDataArrived(uint32_t aLength, int64_t aOffset, bool aThrottleUpdates) { MOZ_ASSERT(NS_IsMainThread()); if (mDecoderStateMachine) { mDecoderStateMachine->DispatchNotifyDataArrived(aLength, aOffset, aThrottleUpdates); @@ -1498,26 +1505,50 @@ MediaDecoder::IsAppleMP3Enabled() } #endif NS_IMETHODIMP MediaMemoryTracker::CollectReports(nsIHandleReportCallback* aHandleReport, nsISupports* aData, bool aAnonymize) { int64_t video = 0, audio = 0; - size_t resources = 0; + + // NB: When resourceSizes' ref count goes to 0 the promise will report the + // resources memory and finish the asynchronous memory report. + nsRefPtr<MediaDecoder::ResourceSizes> resourceSizes = + new MediaDecoder::ResourceSizes(MediaMemoryTracker::MallocSizeOf); + + nsCOMPtr<nsIHandleReportCallback> handleReport = aHandleReport; + nsCOMPtr<nsISupports> data = aData; + + resourceSizes->Promise()->Then( + AbstractThread::MainThread(), __func__, + [handleReport, data] (size_t size) { + handleReport->Callback( + EmptyCString(), NS_LITERAL_CSTRING("explicit/media/resources"), + KIND_HEAP, UNITS_BYTES, size, + NS_LITERAL_CSTRING("Memory used by media resources including " + "streaming buffers, caches, etc."), + data); + + nsCOMPtr<nsIMemoryReporterManager> imgr = + do_GetService("@mozilla.org/memory-reporter-manager;1"); + + if (imgr) { + imgr->EndReport(); + } + }, + [] (size_t) { /* unused reject function */ }); + DecodersArray& decoders = Decoders(); for (size_t i = 0; i < decoders.Length(); ++i) { MediaDecoder* decoder = decoders[i]; video += decoder->SizeOfVideoQueue(); audio += decoder->SizeOfAudioQueue(); - - if (decoder->GetResource()) { - resources += decoder->GetResource()->SizeOfIncludingThis(MallocSizeOf); - } + decoder->AddSizeOfResources(resourceSizes); } #define REPORT(_path, _amount, _desc) \ do { \ nsresult rv; \ rv = aHandleReport->Callback(EmptyCString(), NS_LITERAL_CSTRING(_path), \ KIND_HEAP, UNITS_BYTES, _amount, \ NS_LITERAL_CSTRING(_desc), aData); \ @@ -1525,20 +1556,16 @@ MediaMemoryTracker::CollectReports(nsIHa } while (0) REPORT("explicit/media/decoded/video", video, "Memory used by decoded video frames."); REPORT("explicit/media/decoded/audio", audio, "Memory used by decoded audio chunks."); - REPORT("explicit/media/resources", resources, - "Memory used by media resources including streaming buffers, caches, " - "etc."); - #undef REPORT return NS_OK; } MediaDecoderOwner* MediaDecoder::GetOwner() { @@ -1615,17 +1642,17 @@ MediaDecoder::RemoveMediaTracks() MediaMemoryTracker::MediaMemoryTracker() { } void MediaMemoryTracker::InitMemoryReporter() { - RegisterWeakMemoryReporter(this); + RegisterWeakAsyncMemoryReporter(this); } MediaMemoryTracker::~MediaMemoryTracker() { UnregisterWeakMemoryReporter(this); } } // namespace mozilla
--- a/dom/media/MediaDecoder.h +++ b/dom/media/MediaDecoder.h @@ -183,16 +183,17 @@ destroying the MediaDecoder object. */ #if !defined(MediaDecoder_h_) #define MediaDecoder_h_ #ifdef MOZ_EME #include "mozilla/CDMProxy.h" #endif +#include "mozilla/Atomics.h" #include "mozilla/MozPromise.h" #include "mozilla/ReentrantMonitor.h" #include "mozilla/StateMirroring.h" #include "mozilla/StateWatching.h" #include "mozilla/dom/AudioChannelBinding.h" #include "necko-config.h" @@ -525,16 +526,49 @@ public: // are buffered and playable. virtual media::TimeIntervals GetBuffered(); // Returns the size, in bytes, of the heap memory used by the currently // queued decoded video and audio data. size_t SizeOfVideoQueue(); size_t SizeOfAudioQueue(); + // Helper struct for accumulating resource sizes that need to be measured + // asynchronously. Once all references are dropped the callback will be + // invoked. + struct ResourceSizes + { + typedef MozPromise<size_t, size_t, true> SizeOfPromise; + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ResourceSizes) + explicit ResourceSizes(MallocSizeOf aMallocSizeOf) + : mMallocSizeOf(aMallocSizeOf) + , mByteSize(0) + , mCallback() + { + } + + mozilla::MallocSizeOf mMallocSizeOf; + mozilla::Atomic<size_t> mByteSize; + + nsRefPtr<SizeOfPromise> Promise() + { + return mCallback.Ensure(__func__); + } + +private: + ~ResourceSizes() + { + mCallback.ResolveIfExists(mByteSize, __func__); + } + + MozPromiseHolder<SizeOfPromise> mCallback; + }; + + virtual void AddSizeOfResources(ResourceSizes* aSizes); + VideoFrameContainer* GetVideoFrameContainer() final override { return mVideoFrameContainer; } layers::ImageContainer* GetImageContainer() override; // Fire timeupdate events if needed according to the time constraints // outlined in the specification.
--- a/dom/media/MediaDecoderStateMachine.cpp +++ b/dom/media/MediaDecoderStateMachine.cpp @@ -1,8 +1,9 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim:set ts=2 sw=2 sts=2 et cindent: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifdef XP_WIN // Include Windows headers required for enabling high precision timers. #include "windows.h" @@ -868,24 +869,26 @@ MediaDecoderStateMachine::OnVideoDecoded Push(video, MediaData::VIDEO_DATA); if (MaybeFinishDecodeFirstFrame()) { return; } if (mIsVideoPrerolling && DonePrerollingVideo()) { StopPrerollingVideo(); } - // Schedule the state machine to send stream data as soon as possible or - // the VideoQueue() is empty before the Push(). - // VideoQueue() is empty implies the state machine thread doesn't have - // precise time information about video frames. Once the first video - // frame pushed in the queue, schedule the state machine as soon as - // possible to render the video frame or delay the state machine thread - // accurately. - if (VideoQueue().GetSize() == 1) { + // Schedule the state machine to send stream data as soon as possible if + // the VideoQueue() is empty or contains one frame before the Push(). + // + // The state machine threads requires a frame in VideoQueue() that is `in + // the future` to gather precise timing information. The head of + // VideoQueue() is always `in the past`. + // + // Schedule the state machine as soon as possible to render the video + // frame or delay the state machine thread accurately. + if (VideoQueue().GetSize() <= 2) { ScheduleStateMachine(); } // For non async readers, if the requested video sample was slow to // arrive, increase the amount of audio we buffer to ensure that we // don't run out of audio. This is unnecessary for async readers, // since they decode audio and video on different threads so they // are unlikely to run out of decoded audio.
--- a/dom/media/fmp4/MP4Decoder.cpp +++ b/dom/media/fmp4/MP4Decoder.cpp @@ -171,17 +171,17 @@ MP4Decoder::CanHandleMediaType(const nsA return CanHandleMediaType(NS_ConvertUTF16toUTF8(mimeType), codecs); } /* static */ bool MP4Decoder::IsEnabled() { - return Preferences::GetBool("media.fragmented-mp4.enabled"); + return Preferences::GetBool("media.mp4.enabled"); } static const uint8_t sTestH264ExtraData[] = { 0x01, 0x64, 0x00, 0x0a, 0xff, 0xe1, 0x00, 0x17, 0x67, 0x64, 0x00, 0x0a, 0xac, 0xd9, 0x44, 0x26, 0x84, 0x00, 0x00, 0x03, 0x00, 0x04, 0x00, 0x00, 0x03, 0x00, 0xc8, 0x3c, 0x48, 0x96, 0x58, 0x01, 0x00, 0x06, 0x68, 0xeb, 0xe3, 0xcb, 0x22, 0xc0 };
--- a/dom/media/gtest/TestMP4Reader.cpp +++ b/dom/media/gtest/TestMP4Reader.cpp @@ -25,17 +25,17 @@ public: nsRefPtr<MP4Reader> reader; explicit TestBinding(const char* aFileName = "gizmo.mp4") : decoder(new MP4Decoder()) , resource(new MockMediaResource(aFileName)) , reader(new MP4Reader(decoder)) { EXPECT_EQ(NS_OK, Preferences::SetBool( - "media.fragmented-mp4.use-blank-decoder", true)); + "media.use-blank-decoder", true)); EXPECT_EQ(NS_OK, resource->Open(nullptr)); decoder->SetResource(resource); reader->Init(nullptr); // This needs to be done before invoking GetBuffered. This is normally // done by MediaDecoderStateMachine. reader->DispatchSetStartTime(0);
--- a/dom/media/mediasource/MediaSourceDecoder.cpp +++ b/dom/media/mediasource/MediaSourceDecoder.cpp @@ -172,16 +172,25 @@ void MediaSourceDecoder::Ended(bool aEnded) { MOZ_ASSERT(NS_IsMainThread()); static_cast<MediaSourceResource*>(GetResource())->SetEnded(aEnded); mEnded = true; } void +MediaSourceDecoder::AddSizeOfResources(ResourceSizes* aSizes) +{ + MOZ_ASSERT(NS_IsMainThread()); + if (GetDemuxer()) { + GetDemuxer()->AddSizeOfResources(aSizes); + } +} + +void MediaSourceDecoder::SetInitialDuration(int64_t aDuration) { MOZ_ASSERT(NS_IsMainThread()); // Only use the decoded duration if one wasn't already // set. if (!mMediaSource || !IsNaN(ExplicitDuration())) { return; }
--- a/dom/media/mediasource/MediaSourceDecoder.h +++ b/dom/media/mediasource/MediaSourceDecoder.h @@ -70,16 +70,18 @@ public: { return mDemuxer; } // Returns a string describing the state of the MediaSource internal // buffered data. Used for debugging purposes. void GetMozDebugReaderData(nsAString& aString); + void AddSizeOfResources(ResourceSizes* aSizes) override; + private: void DoSetMediaSourceDuration(double aDuration); // The owning MediaSource holds a strong reference to this decoder, and // calls Attach/DetachMediaSource on this decoder to set and clear // mMediaSource. dom::MediaSource* mMediaSource; nsRefPtr<MediaSourceDemuxer> mDemuxer;
--- a/dom/media/mediasource/MediaSourceDemuxer.cpp +++ b/dom/media/mediasource/MediaSourceDemuxer.cpp @@ -48,16 +48,34 @@ MediaSourceDemuxer::AttemptInit() return InitPromise::CreateAndResolve(NS_OK, __func__); } nsRefPtr<InitPromise> p = mInitPromise.Ensure(__func__); return p; } +void +MediaSourceDemuxer::AddSizeOfResources(MediaSourceDecoder::ResourceSizes* aSizes) +{ + MOZ_ASSERT(NS_IsMainThread()); + + // NB: The track buffers must only be accessed on the TaskQueue. + nsRefPtr<MediaSourceDemuxer> self = this; + nsRefPtr<MediaSourceDecoder::ResourceSizes> sizes = aSizes; + nsCOMPtr<nsIRunnable> task = + NS_NewRunnableFunction([self, sizes] () { + for (TrackBuffersManager* manager : self->mSourceBuffers) { + manager->AddSizeOfResources(sizes); + } + }); + + GetTaskQueue()->Dispatch(task.forget()); +} + void MediaSourceDemuxer::NotifyDataArrived() { nsRefPtr<MediaSourceDemuxer> self = this; nsCOMPtr<nsIRunnable> task = NS_NewRunnableFunction([self] () { if (self->mInitPromise.IsEmpty()) { return; }
--- a/dom/media/mediasource/MediaSourceDemuxer.h +++ b/dom/media/mediasource/MediaSourceDemuxer.h @@ -48,16 +48,18 @@ public: void AttachSourceBuffer(TrackBuffersManager* aSourceBuffer); void DetachSourceBuffer(TrackBuffersManager* aSourceBuffer); TaskQueue* GetTaskQueue() { return mTaskQueue; } // Returns a string describing the state of the MediaSource internal // buffered data. Used for debugging purposes. void GetMozDebugReaderData(nsAString& aString); + void AddSizeOfResources(MediaSourceDecoder::ResourceSizes* aSizes); + private: ~MediaSourceDemuxer(); friend class MediaSourceTrackDemuxer; // Scan source buffers and update information. bool ScanSourceBuffersForContent(); nsRefPtr<InitPromise> AttemptInit(); TrackBuffersManager* GetManager(TrackInfo::TrackType aType); TrackInfo* GetTrackInfo(TrackInfo::TrackType);
--- a/dom/media/mediasource/TrackBuffersManager.cpp +++ b/dom/media/mediasource/TrackBuffersManager.cpp @@ -2118,12 +2118,30 @@ TrackBuffersManager::GetNextRandomAccess const nsRefPtr<MediaRawData>& sample = track[i]; if (sample->mKeyframe) { return TimeUnit::FromMicroseconds(sample->mTime); } } return media::TimeUnit::FromInfinity(); } +void +TrackBuffersManager::TrackData::AddSizeOfResources(MediaSourceDecoder::ResourceSizes* aSizes) +{ + for (TrackBuffer& buffer : mBuffers) { + for (MediaRawData* data : buffer) { + aSizes->mByteSize += data->SizeOfIncludingThis(aSizes->mMallocSizeOf); + } + } +} + +void +TrackBuffersManager::AddSizeOfResources(MediaSourceDecoder::ResourceSizes* aSizes) +{ + MOZ_ASSERT(OnTaskQueue()); + mVideoTracks.AddSizeOfResources(aSizes); + mAudioTracks.AddSizeOfResources(aSizes); +} + } // namespace mozilla #undef MSE_DEBUG #undef MSE_DEBUGV #undef SAMPLE_DEBUG
--- a/dom/media/mediasource/TrackBuffersManager.h +++ b/dom/media/mediasource/TrackBuffersManager.h @@ -97,16 +97,18 @@ public: const media::TimeUnit& aFuzz, bool& aError); media::TimeUnit GetNextRandomAccessPoint(TrackInfo::TrackType aTrack); #if defined(DEBUG) void Dump(const char* aPath) override; #endif + void AddSizeOfResources(MediaSourceDecoder::ResourceSizes* aSizes); + private: // for MediaSourceDemuxer::GetMozDebugReaderData friend class MediaSourceDemuxer; virtual ~TrackBuffersManager(); // All following functions run on the taskqueue. nsRefPtr<AppendPromise> InitSegmentParserLoop(); void ScheduleSegmentParserLoop(); void SegmentParserLoop(); @@ -276,16 +278,18 @@ private: mLastDecodeTimestamp.reset(); mLastFrameDuration.reset(); mHighestEndTimestamp.reset(); mNeedRandomAccessPoint = true; mLongestFrameDuration.reset(); mNextInsertionIndex.reset(); } + + void AddSizeOfResources(MediaSourceDecoder::ResourceSizes* aSizes); }; void CheckSequenceDiscontinuity(const media::TimeUnit& aPresentationTime); void ProcessFrames(TrackBuffer& aSamples, TrackData& aTrackData); bool CheckNextInsertionIndex(TrackData& aTrackData, const media::TimeUnit& aSampleTime); void InsertFrames(TrackBuffer& aSamples, const media::TimeIntervals& aIntervals,
--- a/dom/media/mediasource/test/mochitest.ini +++ b/dom/media/mediasource/test/mochitest.ini @@ -51,16 +51,17 @@ skip-if = ((os == "win" && os_version == [test_FrameSelection.html] [test_HaveMetadataUnbufferedSeek.html] [test_HaveMetadataUnbufferedSeek_mp4.html] skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac") || (os == "win" && os_version == "6.1")) # Only supported on osx and vista+, disabling on win7 bug 1191138 [test_LoadedMetadataFired.html] [test_LoadedMetadataFired_mp4.html] skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+ [test_MediaSource.html] +[test_MediaSource_memory_reporting.html] [test_MediaSource_mp4.html] skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+ [test_MediaSource_disabled.html] [test_MultipleInitSegments.html] [test_MultipleInitSegments_mp4.html] skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+ [test_SeekableAfterEndOfStream.html] [test_SeekableAfterEndOfStream_mp4.html]
new file mode 100644 --- /dev/null +++ b/dom/media/mediasource/test/test_MediaSource_memory_reporting.html @@ -0,0 +1,51 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>MSE: memory reporting</title> + <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="text/javascript" src="mediasource.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +SimpleTest.waitForExplicitFinish(); + +runWithMSE(function (ms, v) { + // Test that memory reporting works once we've played a video. + once(v, "stalled", () => { + // Grab a memory report. + var mgr = SpecialPowers.Cc["@mozilla.org/memory-reporter-manager;1"] + .getService(SpecialPowers.Ci.nsIMemoryReporterManager); + + var amount = 0; + var resourcesPathSeen = false; + var handleReport = function(aProcess, aPath, aKind, aUnits, aAmount, aDesc) { + if (aPath == "explicit/media/resources") { + resourcePathSeen = true; + amount += aAmount; + } + } + + var finished = function () { + ok(true, "Yay didn't crash!"); + ok(resourcePathSeen, "Got media resources amount"); + ok(amount > 0, "Non-zero amount reported for media resources"); + SimpleTest.finish(); + } + + mgr.getReports(handleReport, null, finished, null, /* anonymized = */ false); + }); + + // Load a webm video and play it. + ms.addEventListener("sourceopen", () => { + var sb = ms.addSourceBuffer("video/webm"); + fetchAndLoad(sb, 'seek', [''], '.webm').then(() => v.play()); + }); +}); + +</script> +</pre> +</body> +</html>
--- a/dom/media/omx/OMXCodecWrapper.cpp +++ b/dom/media/omx/OMXCodecWrapper.cpp @@ -12,17 +12,20 @@ #include <media/ICrypto.h> #include <media/IOMX.h> #include <OMX_Component.h> #include <stagefright/MediaDefs.h> #include <stagefright/MediaErrors.h> #include "AudioChannelFormat.h" #include "GrallocImages.h" +#include "LayersLogging.h" +#include "libyuv.h" #include "mozilla/Monitor.h" +#include "mozilla/gfx/2D.h" #include "mozilla/layers/GrallocTextureClient.h" using namespace mozilla; using namespace mozilla::gfx; using namespace mozilla::layers; #define INPUT_BUFFER_TIMEOUT_US (5 * 1000ll) // AMR NB kbps @@ -375,16 +378,77 @@ ConvertGrallocImageToNV12(GrallocImage* break; default: NS_ERROR("Unsupported input gralloc image type. Should never be here."); } graphicBuffer->unlock(); } +static nsresult +ConvertSourceSurfaceToNV12(const nsRefPtr<SourceSurface>& aSurface, uint8_t* aDestination) +{ + uint32_t width = aSurface->GetSize().width; + uint32_t height = aSurface->GetSize().height; + + uint8_t* y = aDestination; + int yStride = width; + + uint8_t* uv = y + (yStride * height); + int uvStride = width / 2; + + SurfaceFormat format = aSurface->GetFormat(); + + if (!aSurface) { + CODEC_ERROR("Getting surface %s from image failed", Stringify(format).c_str()); + return NS_ERROR_FAILURE; + } + + RefPtr<DataSourceSurface> data = aSurface->GetDataSurface(); + if (!data) { + CODEC_ERROR("Getting data surface from %s image with %s (%s) surface failed", + Stringify(format).c_str(), Stringify(aSurface->GetType()).c_str(), + Stringify(aSurface->GetFormat()).c_str()); + return NS_ERROR_FAILURE; + } + + DataSourceSurface::ScopedMap map(data, DataSourceSurface::READ); + if (!map.IsMapped()) { + CODEC_ERROR("Reading DataSourceSurface from %s image with %s (%s) surface failed", + Stringify(format).c_str(), Stringify(aSurface->GetType()).c_str(), + Stringify(aSurface->GetFormat()).c_str()); + return NS_ERROR_FAILURE; + } + + int rv; + switch (aSurface->GetFormat()) { + case SurfaceFormat::B8G8R8A8: + case SurfaceFormat::B8G8R8X8: + rv = libyuv::ARGBToNV12(static_cast<uint8*>(map.GetData()), + map.GetStride(), + y, yStride, + uv, uvStride, + width, height); + break; + default: + CODEC_ERROR("Unsupported SourceSurface format %s", + Stringify(aSurface->GetFormat()).c_str()); + NS_ASSERTION(false, "Unsupported SourceSurface format"); + return NS_ERROR_NOT_IMPLEMENTED; + } + + if (rv != 0) { + CODEC_ERROR("%s to I420 conversion failed", + Stringify(aSurface->GetFormat()).c_str()); + return NS_ERROR_FAILURE; + } + + return NS_OK; +} + nsresult OMXVideoEncoder::Encode(const Image* aImage, int aWidth, int aHeight, int64_t aTimestamp, int aInputFlags, bool* aSendEOS) { MOZ_ASSERT(mStarted, "Configure() should be called before Encode()."); NS_ENSURE_TRUE(aWidth == mWidth && aHeight == mHeight && aTimestamp >= 0, NS_ERROR_INVALID_ARG); @@ -405,19 +469,20 @@ OMXVideoEncoder::Encode(const Image* aIm } else if (format == ImageFormat::GRALLOC_PLANAR_YCBCR) { // Reject unsupported gralloc-ed buffers. int halFormat = static_cast<GrallocImage*>(img)->GetGraphicBuffer()->getPixelFormat(); NS_ENSURE_TRUE(halFormat == HAL_PIXEL_FORMAT_YCrCb_420_SP || halFormat == HAL_PIXEL_FORMAT_YV12 || halFormat == GrallocImage::HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS, NS_ERROR_INVALID_ARG); } else { - // TODO: support RGB to YUV color conversion. - NS_ERROR("Unsupported input image type."); - return NS_ERROR_INVALID_ARG; + nsRefPtr<SourceSurface> surface = img->GetAsSourceSurface(); + NS_ENSURE_TRUE(surface->GetFormat() == SurfaceFormat::B8G8R8A8 || + surface->GetFormat() == SurfaceFormat::B8G8R8X8, + NS_ERROR_INVALID_ARG); } } status_t result; // Dequeue an input buffer. uint32_t index; result = mCodec->dequeueInputBuffer(&index, INPUT_BUFFER_TIMEOUT_US); @@ -445,16 +510,23 @@ OMXVideoEncoder::Encode(const Image* aIm // Fill UV plane. memset(dst + yLen, 0x80, uvLen); } else { if (format == ImageFormat::GRALLOC_PLANAR_YCBCR) { ConvertGrallocImageToNV12(static_cast<GrallocImage*>(img), dst); } else if (format == ImageFormat::PLANAR_YCBCR) { ConvertPlanarYCbCrToNV12(static_cast<PlanarYCbCrImage*>(img)->GetData(), dst); + } else { + nsRefPtr<SourceSurface> surface = img->GetAsSourceSurface(); + nsresult rv = ConvertSourceSurfaceToNV12(surface, dst); + + if (rv != NS_OK) { + return NS_ERROR_FAILURE; + } } } // Queue this input buffer. result = mCodec->queueInputBuffer(index, 0, dstSize, aTimestamp, aInputFlags); if (aSendEOS && (aInputFlags & BUFFER_EOS) && result == OK) { *aSendEOS = true;
--- a/dom/media/omx/moz.build +++ b/dom/media/omx/moz.build @@ -36,16 +36,17 @@ if CONFIG['MOZ_AUDIO_OFFLOAD']: if CONFIG['MOZ_OMX_ENCODER']: EXPORTS += [ 'OMXCodecWrapper.h', ] SOURCES += [ 'OMXCodecDescriptorUtil.cpp', 'OMXCodecWrapper.cpp', ] + LOCAL_INCLUDES += ['/media/libyuv/include'] if 'rtsp' in CONFIG['NECKO_PROTOCOLS']: EXPORTS += [ 'RtspExtractor.h', 'RtspOmxDecoder.h', 'RtspOmxReader.h', ] SOURCES += [
--- a/dom/media/platforms/PDMFactory.cpp +++ b/dom/media/platforms/PDMFactory.cpp @@ -40,21 +40,30 @@ #endif namespace mozilla { extern already_AddRefed<PlatformDecoderModule> CreateAgnosticDecoderModule(); extern already_AddRefed<PlatformDecoderModule> CreateBlankDecoderModule(); bool PDMFactory::sUseBlankDecoder = false; +#ifdef MOZ_GONK_MEDIACODEC bool PDMFactory::sGonkDecoderEnabled = false; +#endif +#ifdef MOZ_WIDGET_ANDROID bool PDMFactory::sAndroidMCDecoderEnabled = false; bool PDMFactory::sAndroidMCDecoderPreferred = false; +#endif bool PDMFactory::sGMPDecoderEnabled = false; +#ifdef MOZ_FFMPEG bool PDMFactory::sFFmpegDecoderEnabled = false; +#endif +#ifdef XP_WIN +bool PDMFactory::sWMFDecoderEnabled = false; +#endif bool PDMFactory::sEnableFuzzingWrapper = false; uint32_t PDMFactory::sVideoOutputMinimumInterval_ms = 0; bool PDMFactory::sDontDelayInputExhausted = false; /* static */ void PDMFactory::Init() @@ -62,32 +71,38 @@ PDMFactory::Init() MOZ_ASSERT(NS_IsMainThread()); static bool alreadyInitialized = false; if (alreadyInitialized) { return; } alreadyInitialized = true; Preferences::AddBoolVarCache(&sUseBlankDecoder, - "media.fragmented-mp4.use-blank-decoder"); + "media.use-blank-decoder"); #ifdef MOZ_GONK_MEDIACODEC Preferences::AddBoolVarCache(&sGonkDecoderEnabled, - "media.fragmented-mp4.gonk.enabled", false); + "media.gonk.enabled", false); #endif #ifdef MOZ_WIDGET_ANDROID Preferences::AddBoolVarCache(&sAndroidMCDecoderEnabled, - "media.fragmented-mp4.android-media-codec.enabled", false); + "media.android-media-codec.enabled", false); Preferences::AddBoolVarCache(&sAndroidMCDecoderPreferred, - "media.fragmented-mp4.android-media-codec.preferred", false); + "media.android-media-codec.preferred", false); #endif Preferences::AddBoolVarCache(&sGMPDecoderEnabled, - "media.fragmented-mp4.gmp.enabled", false); + "media.gmp.decoder.enabled", false); +#ifdef MOZ_FFMPEG Preferences::AddBoolVarCache(&sFFmpegDecoderEnabled, - "media.fragmented-mp4.ffmpeg.enabled", false); + "media.ffmpeg.enabled", false); +#endif +#ifdef XP_WIN + Preferences::AddBoolVarCache(&sWMFDecoderEnabled, + "media.wmf.enabled", false); +#endif Preferences::AddBoolVarCache(&sEnableFuzzingWrapper, "media.decoder.fuzzing.enabled", false); Preferences::AddUintVarCache(&sVideoOutputMinimumInterval_ms, "media.decoder.fuzzing.video-output-minimum-interval-ms", 0); Preferences::AddBoolVarCache(&sDontDelayInputExhausted, "media.decoder.fuzzing.dont-delay-inputexhausted", false); @@ -199,18 +214,20 @@ PDMFactory::CreatePDMs() } #ifdef MOZ_WIDGET_ANDROID if(sAndroidMCDecoderPreferred && sAndroidMCDecoderEnabled) { m = new AndroidDecoderModule(); StartupPDM(m); } #endif #ifdef XP_WIN - m = new WMFDecoderModule(); - StartupPDM(m); + if (sWMFDecoderEnabled) { + m = new WMFDecoderModule(); + StartupPDM(m); + } #endif #ifdef MOZ_FFMPEG if (sFFmpegDecoderEnabled) { m = FFmpegRuntimeLinker::CreateDecoderModule(); StartupPDM(m); } #endif #ifdef MOZ_APPLEMEDIA
--- a/dom/media/platforms/PDMFactory.h +++ b/dom/media/platforms/PDMFactory.h @@ -49,23 +49,32 @@ public: private: virtual ~PDMFactory(); void CreatePDMs(); // Startup the provided PDM and add it to our list if successful. bool StartupPDM(PlatformDecoderModule* aPDM); // Returns the first PDM in our list supporting the mimetype. already_AddRefed<PlatformDecoderModule> GetDecoder(const nsACString& aMimeType); - // Caches pref media.fragmented-mp4.use-blank-decoder + // PDM pref caches... static bool sUseBlankDecoder; +#ifdef MOZ_GONK_MEDIACODEC static bool sGonkDecoderEnabled; +#endif +#ifdef MOZ_WIDGET_ANDROID static bool sAndroidMCDecoderPreferred; static bool sAndroidMCDecoderEnabled; +#endif static bool sGMPDecoderEnabled; +#ifdef MOZ_FFMPEG static bool sFFmpegDecoderEnabled; +#endif +#ifdef XP_WIN + static bool sWMFDecoderEnabled; +#endif static bool sEnableFuzzingWrapper; static uint32_t sVideoOutputMinimumInterval_ms; static bool sDontDelayInputExhausted; nsTArray<nsRefPtr<PlatformDecoderModule>> mCurrentPDMs; nsRefPtr<PlatformDecoderModule> mEMEPDM; };
--- a/dom/media/platforms/PlatformDecoderModule.h +++ b/dom/media/platforms/PlatformDecoderModule.h @@ -37,17 +37,17 @@ class CDMProxy; // PlatformDecoderModule to provide access to its decoders in order to get // decompressed H.264/AAC from the MediaFormatReader. // // Decoding is asynchronous, and should be performed on the task queue // provided if the underlying platform isn't already exposing an async API. // // A cross-platform decoder module that discards input and produces "blank" // output samples exists for testing, and is created when the pref -// "media.fragmented-mp4.use-blank-decoder" is true. +// "media.use-blank-decoder" is true. class PlatformDecoderModule { public: NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PlatformDecoderModule) // Perform any per-instance initialization. // This is called on the decode task queue. virtual nsresult Startup() { return NS_OK; };
--- a/dom/media/platforms/agnostic/gmp/GMPDecoderModule.cpp +++ b/dom/media/platforms/agnostic/gmp/GMPDecoderModule.cpp @@ -92,19 +92,19 @@ GMPDecoderModule::DecoderNeedsConversion static uint32_t sPreferredAacGmp = 0; static uint32_t sPreferredH264Gmp = 0; /* static */ void GMPDecoderModule::Init() { Preferences::AddUintVarCache(&sPreferredAacGmp, - "media.fragmented-mp4.gmp.aac", 0); + "media.gmp.decoder.aac", 0); Preferences::AddUintVarCache(&sPreferredH264Gmp, - "media.fragmented-mp4.gmp.h264", 0); + "media.gmp.decoder.h264", 0); } /* static */ const Maybe<nsCString> GMPDecoderModule::PreferredGMP(const nsACString& aMimeType) { Maybe<nsCString> rv; if (aMimeType.EqualsLiteral("audio/mp4a-latm")) {
--- a/dom/media/test/eme.js +++ b/dom/media/test/eme.js @@ -419,13 +419,13 @@ function SetupEMEPref(callback) { var prefs = [ [ "media.mediasource.enabled", true ], [ "media.eme.apiVisible", true ], ]; if (SpecialPowers.Services.appinfo.name == "B2G" || !manifestVideo().canPlayType("video/mp4")) { // XXX remove once we have mp4 PlatformDecoderModules on all platforms. - prefs.push([ "media.fragmented-mp4.use-blank-decoder", true ]); + prefs.push([ "media.use-blank-decoder", true ]); } SpecialPowers.pushPrefEnv({ "set" : prefs }, callback); }
--- a/dom/media/test/mochitest.ini +++ b/dom/media/test/mochitest.ini @@ -612,36 +612,36 @@ skip-if = (toolkit == 'android' && proce [test_decode_error.html] [test_decoder_disable.html] [test_defaultMuted.html] [test_delay_load.html] skip-if = buildapp == 'b2g' && toolkit != 'gonk' # bug 1082984 [test_dormant_playback.html] skip-if = (os == 'win' && os_version == '5.1') || (os != 'win' && toolkit != 'gonk') [test_eme_canvas_blocked.html] -skip-if = toolkit == 'android' || (os == 'win') # bug 1043403, bug 1140675, win debug : Bug 1202683 +skip-if = toolkit == 'android' # bug 1149374 [test_eme_non_mse_fails.html] -skip-if = toolkit == 'android' || (os == 'win' && debug) # bug 1043403, win debug : Bug 1202683 +skip-if = toolkit == 'android' # bug 1149374 [test_eme_request_notifications.html] -skip-if = toolkit == 'android' || (os == 'win' && debug) # bug 1043403, win debug : Bug 1202683 +skip-if = toolkit == 'android' # bug 1149374 [test_eme_persistent_sessions.html] -skip-if = toolkit == 'android' || (os == 'win' && debug) # bug 1043403, win debug : Bug 1202683 +skip-if = toolkit == 'android' # bug 1149374 [test_eme_playback.html] -skip-if = toolkit == 'android' || toolkit == 'gonk' || os == 'win' # bug 1043403, bug 1187903, bug 1186406, bug 1193351 +skip-if = toolkit == 'android' || toolkit == 'gonk' # android: bug 1149374; gonk: bug 1193351 [test_eme_requestKeySystemAccess.html] -skip-if = toolkit == 'android' || (os == 'win' && debug) # bug 1043403, win debug : Bug 1202683 +skip-if = toolkit == 'android' # bug 1149374 [test_eme_stream_capture_blocked_case1.html] tags=msg capturestream -skip-if = toolkit == 'android' || toolkit == 'gonk' || os == 'win' # bug 1043403, bug 1140675, bug 1187903, bug 1193351 +skip-if = toolkit == 'android' || toolkit == 'gonk' # android: bug 1149374; gonk: bug 1193351 [test_eme_stream_capture_blocked_case2.html] tags=msg capturestream -skip-if = toolkit == 'android' || toolkit == 'gonk' || os == 'win' # bug 1043403, bug 1140675, bug 1187903, bug 1193351 +skip-if = toolkit == 'android' || toolkit == 'gonk' # android: bug 1149374; gonk: bug 1193351 [test_eme_stream_capture_blocked_case3.html] tags=msg capturestream -skip-if = toolkit == 'android' || toolkit == 'gonk' || os == 'win' # bug 1043403, bug 1140675, bug 1187903, bug 1193351 +skip-if = toolkit == 'android' || toolkit == 'gonk' # android: bug 1149374; gonk: bug 1193351 [test_empty_resource.html] skip-if = os == 'win' && debug #win debug : Bug 1202683 [test_error_in_video_document.html] skip-if = toolkit == 'android' || (os == 'win' && !debug) || (os == 'mac' && !debug) # bug 608634 [test_error_on_404.html] [test_fastSeek.html] skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439 [test_fastSeek-forwards.html] @@ -680,20 +680,20 @@ tags=msg tags=msg [test_mediarecorder_record_audiocontext.html] tags=msg [test_mediarecorder_record_audiocontext_mlk.html] tags=msg [test_mediarecorder_record_audionode.html] tags=msg [test_mediarecorder_record_canvas_captureStream.html] -skip-if = (toolkit == 'android' || toolkit == 'gonk') # Bug 1210286 to fix canvas capturestream support in the OMX backend +skip-if = android_version < '17' # Android/Gonk before SDK version 17 does not have the OMX Encoder API. tags=msg [test_mediarecorder_record_changing_video_resolution.html] -skip-if = (toolkit == 'android' || toolkit == 'gonk') # Bug 1210286 to fix canvas capturestream support in the OMX backend +skip-if = android_version < '17' # Android/Gonk before SDK version 17 does not have the OMX Encoder API. tags=msg [test_mediarecorder_record_gum_video_timeslice.html] tags=msg [test_mediarecorder_record_immediate_stop.html] tags=msg capturestream [test_mediarecorder_record_no_timeslice.html] tags=msg capturestream [test_mediarecorder_record_nosrc.html]
--- a/dom/media/test/test_can_play_type_mpeg.html +++ b/dom/media/test/test_can_play_type_mpeg.html @@ -119,33 +119,29 @@ function getPref(name) { } catch(ex) { } return pref; } function IsJellyBeanOrLater() { return androidVersion >= 16; } -// Check whether we should expect the new MP4Reader-based support to work. -function IsMP4ReaderAvailable() { - var prefs = getPref("media.fragmented-mp4.enabled"); - return prefs && (IsWindowsVistaOrLater() || IsMacOSSnowLeopardOrLater() || IsJellyBeanOrLater()); -} - -var haveMp4 = IsWindowsVistaOrLater() || +var haveMp4 = (getPref("media.wmf.enabled") && IsWindowsVistaOrLater()) || + IsMacOSSnowLeopardOrLater() || + IsJellyBeanOrLater() || getPref("media.omx.enabled") || getPref("media.gstreamer.enabled") || - IsMP4ReaderAvailable(); -// TODO: Add "getPref("media.plugins.enabled")" once MP4 works on Gingerbread. + getPref("media.ffmpeg.enabled"); check_mp4(document.getElementById('v'), haveMp4); var haveMp3 = getPref("media.directshow.enabled") || - (getPref("media.windows-media-foundation.enabled") && IsWindowsVistaOrLater()) || - getPref("media.gstreamer.enabled") || - getPref("media.apple.mp3.enabled"); + (getPref("media.wmf.enabled") && IsWindowsVistaOrLater()) || + getPref("media.gstreamer.enabled") || + getPref("media.ffmpeg.enabled") || + getPref("media.apple.mp3.enabled"); check_mp3(document.getElementById('v'), haveMp3); mediaTestCleanup(); </script> </pre> </body> </html>
--- a/dom/media/test/test_gmp_playback.html +++ b/dom/media/test/test_gmp_playback.html @@ -22,19 +22,19 @@ function startTest() { ok(true, "Reached end"); SimpleTest.finish(); }); document.body.appendChild(v); v.play(); } var testPrefs = [ - ['media.fragmented-mp4.gmp.aac', 1], // gmp-clearkey - ['media.fragmented-mp4.gmp.h264', 1], // gmp-clearkey - ['media.fragmented-mp4.gmp.enabled', true] + ['media.gmp.decoder.aac', 1], // gmp-clearkey + ['media.gmp.decoder.h264', 1], // gmp-clearkey + ['media.gmp.decoder.enabled', true] ]; SpecialPowers.pushPrefEnv({'set': testPrefs}, startTest); </script> </pre> </body> </html>
--- a/dom/media/tests/mochitest/head.js +++ b/dom/media/tests/mochitest/head.js @@ -24,19 +24,16 @@ try { * This class provides helpers around analysing the audio content in a stream * using WebAudio AnalyserNodes. * * @constructor * @param {object} stream * A MediaStream object whose audio track we shall analyse. */ function AudioStreamAnalyser(ac, stream) { - if (stream.getAudioTracks().length === 0) { - throw new Error("No audio track in stream"); - } this.audioContext = ac; this.stream = stream; this.sourceNode = this.audioContext.createMediaStreamSource(this.stream); this.analyser = this.audioContext.createAnalyser(); this.sourceNode.connect(this.analyser); this.data = new Uint8Array(this.analyser.frequencyBinCount); } @@ -51,39 +48,54 @@ AudioStreamAnalyser.prototype = { return this.data; }, /** * Append a canvas to the DOM where the frequency data are drawn. * Useful to debug tests. */ enableDebugCanvas: function() { - var cvs = document.createElement("canvas"); + var cvs = this.debugCanvas = document.createElement("canvas"); document.getElementById("content").appendChild(cvs); // Easy: 1px per bin cvs.width = this.analyser.frequencyBinCount; cvs.height = 256; cvs.style.border = "1px solid red"; var c = cvs.getContext('2d'); var self = this; function render() { c.clearRect(0, 0, cvs.width, cvs.height); var array = self.getByteFrequencyData(); for (var i = 0; i < array.length; i++) { c.fillRect(i, (256 - (array[i])), 1, 256); } - requestAnimationFrame(render); + if (!cvs.stopDrawing) { + requestAnimationFrame(render); + } } requestAnimationFrame(render); }, /** + * Stop drawing of and remove the debug canvas from the DOM if it was + * previously added. + */ + disableDebugCanvas: function() { + if (!this.debugCanvas || !this.debugCanvas.parentElement) { + return; + } + + this.debugCanvas.stopDrawing = true; + this.debugCanvas.parentElement.removeChild(this.debugCanvas); + }, + + /** * Return a Promise, that will be resolved when the function passed as * argument, when called, returns true (meaning the analysis was a * success). * * @param {function} analysisFunction * A fonction that performs an analysis, and returns true if the * analysis was a success (i.e. it found what it was looking for) */ @@ -125,16 +137,36 @@ AudioStreamAnalyser.prototype = { frequencyForBinIndex: function(index) { return (index - 1) * this.audioContext.sampleRate / this.analyser.fftSize; } }; /** + * Creates a MediaStream with an audio track containing a sine tone at the + * given frequency. + * + * @param {AudioContext} ac + * AudioContext in which to create the OscillatorNode backing the stream + * @param {double} frequency + * The frequency in Hz of the generated sine tone + * @returns {MediaStream} the MediaStream containing sine tone audio track + */ +function createOscillatorStream(ac, frequency) { + var osc = ac.createOscillator(); + osc.frequency.value = frequency; + + var oscDest = ac.createMediaStreamDestination(); + osc.connect(oscDest); + osc.start(); + return oscDest.stream; +} + +/** * Create the necessary HTML elements for head and body as used by Mochitests * * @param {object} meta * Meta information of the test * @param {string} meta.title * Description of the test * @param {string} [meta.bug] * Bug the test was created for
--- a/dom/media/tests/mochitest/mochitest.ini +++ b/dom/media/tests/mochitest/mochitest.ini @@ -46,16 +46,17 @@ skip-if = buildapp == 'mulet' || buildap [test_getUserMedia_basicWindowshare.html] skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' # no windowshare on b2g/android # Bug 1141029 Mulet parity with B2G Desktop for TC [test_getUserMedia_basicVideoAudio.html] skip-if = (toolkit == 'gonk' || buildapp == 'mulet' && debug) # debug-only failure, turned an intermittent (bug 962579) into a permanant orange [test_getUserMedia_constraints.html] [test_getUserMedia_callbacks.html] skip-if = toolkit == 'gonk' || buildapp == 'mulet' || buildapp == 'mulet' # Bug 1063290, intermittent timeout # TC: Bug 1144079 - Re-enable Mulet mochitests and reftests taskcluster-specific disables. [test_getUserMedia_gumWithinGum.html] +[test_getUserMedia_mediaStreamConstructors.html] [test_getUserMedia_playAudioTwice.html] [test_getUserMedia_playVideoAudioTwice.html] [test_getUserMedia_playVideoTwice.html] [test_getUserMedia_spinEventLoop.html] skip-if = (toolkit == 'gonk' || buildapp == 'mulet' && debug) # copied from basicAudio [test_getUserMedia_stopAudioStream.html] [test_getUserMedia_stopAudioStreamWithFollowupAudio.html] [test_getUserMedia_stopVideoAudioStream.html]
--- a/dom/media/tests/mochitest/test_getUserMedia_addTrackRemoveTrack.html +++ b/dom/media/tests/mochitest/test_getUserMedia_addTrackRemoveTrack.html @@ -100,26 +100,16 @@ var elem = createMediaElement('video', 'testAddRemoveOriginalTrackVideo'); var playback = new LocalMediaStreamPlayback(elem, audioStream); return playback.playMediaWithMediaStreamTracksStop(false); })) .then(() => { var ac = new AudioContext(); - function createOscillatorStream(ac, frequency) { - var osc = ac.createOscillator(); - osc.frequency.value = frequency; - - var oscDest = ac.createMediaStreamDestination(); - osc.connect(oscDest); - osc.start(); - return oscDest.stream; - } - var osc1k = createOscillatorStream(ac, 1000); var audioTrack1k = osc1k.getTracks()[0]; var osc5k = createOscillatorStream(ac, 5000); var audioTrack5k = osc5k.getTracks()[0]; var osc10k = createOscillatorStream(ac, 10000); var audioTrack10k = osc10k.getTracks()[0];
new file mode 100644 --- /dev/null +++ b/dom/media/tests/mochitest/test_getUserMedia_mediaStreamConstructors.html @@ -0,0 +1,142 @@ +<!DOCTYPE HTML> +<html> +<head> + <script type="application/javascript" src="mediaStreamPlayback.js"></script> +</head> +<body> +<pre id="test"> +<script type="application/javascript"> + "use strict"; + + createHTML({ + title: "MediaStream constructors with getUserMedia streams Test", + bug: "1070216", + visible: true + }); + + var audioContext = new AudioContext(); + var videoElement; + + runTest(() => Promise.resolve() + .then(() => videoElement = createMediaElement('video', 'constructorsTest')) + .then(() => getUserMedia({video: true})).then(gUMStream => { + info("Test default constructor with video"); + var track = gUMStream.getTracks()[0]; + + var stream = new MediaStream(); + checkMediaStreamContains(stream, [], "Default constructed stream"); + + stream.addTrack(track); + checkMediaStreamContains(stream, [track], "Added video track"); + + var playback = new MediaStreamPlayback(videoElement, stream); + return playback.playMedia(false).then(() => gUMStream.stop()); + }) + .then(() => getUserMedia({video: true})).then(gUMStream => { + info("Test copy constructor with gUM stream"); + var track = gUMStream.getTracks()[0]; + + var stream = new MediaStream(gUMStream); + checkMediaStreamContains(stream, [track], "Copy constructed video track"); + + var playback = new MediaStreamPlayback(videoElement, stream); + return playback.playMedia(false).then(() => gUMStream.stop()); + }) + .then(() => getUserMedia({video: true})).then(gUMStream => { + info("Test list constructor with empty list"); + var track = gUMStream.getTracks()[0]; + + var stream = new MediaStream([]); + checkMediaStreamContains(stream, [], "Empty-list constructed stream"); + + stream.addTrack(track); + checkMediaStreamContains(stream, [track], "Added video track"); + + var playback = new MediaStreamPlayback(videoElement, stream); + return playback.playMedia(false).then(() => gUMStream.stop()); + }) + .then(() => getUserMedia({audio: true, video: true})).then(gUMStream => { + info("Test list constructor with a gUM audio/video stream"); + var audioTrack = gUMStream.getAudioTracks()[0]; + var videoTrack = gUMStream.getVideoTracks()[0]; + + var stream = new MediaStream([audioTrack, videoTrack]); + checkMediaStreamContains(stream, [audioTrack, videoTrack], + "List constructed audio and video tracks"); + + var playback = new MediaStreamPlayback(videoElement, stream); + return playback.playMedia(false).then(() => gUMStream.stop()); + }) + .then(() => getUserMedia({video: true})).then(gUMStream => { + info("Test list constructor with gUM-video and WebAudio tracks"); + var audioStream = createOscillatorStream(audioContext, 2000); + var audioTrack = audioStream.getTracks()[0]; + var videoTrack = gUMStream.getTracks()[0]; + + var stream = new MediaStream([audioTrack, videoTrack]); + checkMediaStreamContains(stream, [audioTrack, videoTrack], + "List constructed WebAudio and gUM-video tracks"); + + var playback = new MediaStreamPlayback(videoElement, stream); + return playback.playMedia(false).then(() => gUMStream.stop()); + }) + .then(() => { + var osc1k = createOscillatorStream(audioContext, 1000); + var audioTrack1k = osc1k.getTracks()[0]; + + var osc5k = createOscillatorStream(audioContext, 5000); + var audioTrack5k = osc5k.getTracks()[0]; + + var osc10k = createOscillatorStream(audioContext, 10000); + var audioTrack10k = osc10k.getTracks()[0]; + + return Promise.resolve().then(() => { + info("Analysing audio output with empty default constructed stream"); + var stream = new MediaStream(); + var analyser = new AudioStreamAnalyser(audioContext, stream); + analyser.enableDebugCanvas(); + return analyser.waitForAnalysisSuccess(array => + array[analyser.binIndexForFrequency(1000)] < 50 && + array[analyser.binIndexForFrequency(5000)] < 50 && + array[analyser.binIndexForFrequency(10000)] < 50) + .then(() => analyser.disableDebugCanvas()); + }).then(() => { + info("Analysing audio output with copy constructed 5k stream"); + var stream = new MediaStream(osc5k); + var analyser = new AudioStreamAnalyser(audioContext, stream); + analyser.enableDebugCanvas(); + return analyser.waitForAnalysisSuccess(array => + array[analyser.binIndexForFrequency(1000)] < 50 && + array[analyser.binIndexForFrequency(5000)] > 200 && + array[analyser.binIndexForFrequency(10000)] < 50) + .then(() => analyser.disableDebugCanvas()); + }).then(() => { + info("Analysing audio output with empty-list constructed stream"); + var stream = new MediaStream([]); + var analyser = new AudioStreamAnalyser(audioContext, stream); + analyser.enableDebugCanvas(); + return analyser.waitForAnalysisSuccess(array => + array[analyser.binIndexForFrequency(1000)] < 50 && + array[analyser.binIndexForFrequency(5000)] < 50 && + array[analyser.binIndexForFrequency(10000)] < 50) + .then(() => analyser.disableDebugCanvas()); + }).then(() => { + info("Analysing audio output with list constructed 1k, 5k and 10k tracks"); + var stream = new MediaStream([audioTrack1k, audioTrack5k, audioTrack10k]); + var analyser = new AudioStreamAnalyser(audioContext, stream); + analyser.enableDebugCanvas(); + return analyser.waitForAnalysisSuccess(array => + array[analyser.binIndexForFrequency(50)] < 50 && + array[analyser.binIndexForFrequency(1000)] > 200 && + array[analyser.binIndexForFrequency(2500)] < 50 && + array[analyser.binIndexForFrequency(5000)] > 200 && + array[analyser.binIndexForFrequency(7500)] < 50 && + array[analyser.binIndexForFrequency(10000)] > 200 && + array[analyser.binIndexForFrequency(11000)] < 50) + .then(() => analyser.disableDebugCanvas()); + }); + })); +</script> +</pre> +</body> +</html>
--- a/dom/media/webrtc/MediaEngine.h +++ b/dom/media/webrtc/MediaEngine.h @@ -183,19 +183,31 @@ public: virtual uint32_t GetBestFitnessDistance( const nsTArray<const dom::MediaTrackConstraintSet*>& aConstraintSets, const nsString& aDeviceId) = 0; protected: // Only class' own members can be initialized in constructor initializer list. explicit MediaEngineSource(MediaEngineState aState) : mState(aState) +#ifdef DEBUG + , mOwningThread(PR_GetCurrentThread()) +#endif , mHasFakeTracks(false) {} + + void AssertIsOnOwningThread() + { + MOZ_ASSERT(PR_GetCurrentThread() == mOwningThread); + } + MediaEngineState mState; +#ifdef DEBUG + PRThread* mOwningThread; +#endif bool mHasFakeTracks; }; /** * Video source and friends. */ class MediaEnginePrefs { public:
--- a/dom/media/webrtc/MediaEngineCameraVideoSource.h +++ b/dom/media/webrtc/MediaEngineCameraVideoSource.h @@ -23,16 +23,17 @@ public: explicit MediaEngineCameraVideoSource(int aIndex, const char* aMonitorName = "Camera.Monitor") : MediaEngineVideoSource(kReleased) , mMonitor(aMonitorName) , mWidth(0) , mHeight(0) , mInitDone(false) , mHasDirectListeners(false) + , mNrAllocations(0) , mCaptureIndex(aIndex) , mTrackID(0) {} virtual void GetName(nsAString& aName) override; virtual void GetUUID(nsACString& aUUID) override; virtual void SetDirectListeners(bool aHasListeners) override; @@ -110,16 +111,17 @@ static void LogCapability(const char* aH nsRefPtr<layers::Image> mImage; nsRefPtr<layers::ImageContainer> mImageContainer; int mWidth, mHeight; // protected with mMonitor on Gonk due to different threading // end of data protected by mMonitor bool mInitDone; bool mHasDirectListeners; + int mNrAllocations; // When this becomes 0, we shut down HW int mCaptureIndex; TrackID mTrackID; webrtc::CaptureCapability mCapability; nsTArray<webrtc::CaptureCapability> mHardcodedCapabilities; // For OSX & B2G private: nsString mDeviceName;
--- a/dom/media/webrtc/MediaEngineRemoteVideoSource.cpp +++ b/dom/media/webrtc/MediaEngineRemoteVideoSource.cpp @@ -91,18 +91,24 @@ MediaEngineRemoteVideoSource::Shutdown() } nsresult MediaEngineRemoteVideoSource::Allocate(const dom::MediaTrackConstraints& aConstraints, const MediaEnginePrefs& aPrefs, const nsString& aDeviceId) { LOG((__PRETTY_FUNCTION__)); + AssertIsOnOwningThread(); - if (mState == kReleased && mInitDone) { + if (!mInitDone) { + LOG(("Init not done")); + return NS_ERROR_FAILURE; + } + + if (mState == kReleased) { // Note: if shared, we don't allow a later opener to affect the resolution. // (This may change depending on spec changes for Constraints/settings) if (!ChooseCapability(aConstraints, aPrefs, aDeviceId)) { return NS_ERROR_UNEXPECTED; } if (mozilla::camera::AllocateCaptureDevice(mCapEngine, @@ -116,45 +122,48 @@ MediaEngineRemoteVideoSource::Allocate(c MonitorAutoLock lock(mMonitor); if (mSources.IsEmpty()) { LOG(("Video device %d reallocated", mCaptureIndex)); } else { LOG(("Video device %d allocated shared", mCaptureIndex)); } } + ++mNrAllocations; + return NS_OK; } nsresult MediaEngineRemoteVideoSource::Deallocate() { - LOG((__FUNCTION__)); - bool empty; - { - MonitorAutoLock lock(mMonitor); - empty = mSources.IsEmpty(); - } - if (empty) { + LOG((__PRETTY_FUNCTION__)); + AssertIsOnOwningThread(); + + --mNrAllocations; + MOZ_ASSERT(mNrAllocations >= 0, "Double-deallocations are prohibited"); + + if (mNrAllocations == 0) { if (mState != kStopped && mState != kAllocated) { return NS_ERROR_FAILURE; } mozilla::camera::ReleaseCaptureDevice(mCapEngine, mCaptureIndex); mState = kReleased; LOG(("Video device %d deallocated", mCaptureIndex)); } else { LOG(("Video device %d deallocated but still in use", mCaptureIndex)); } return NS_OK; } nsresult MediaEngineRemoteVideoSource::Start(SourceMediaStream* aStream, TrackID aID) { LOG((__PRETTY_FUNCTION__)); + AssertIsOnOwningThread(); if (!mInitDone || !aStream) { LOG(("No stream or init not done")); return NS_ERROR_FAILURE; } { MonitorAutoLock lock(mMonitor); mSources.AppendElement(aStream); @@ -179,16 +188,17 @@ MediaEngineRemoteVideoSource::Start(Sour return NS_OK; } nsresult MediaEngineRemoteVideoSource::Stop(mozilla::SourceMediaStream* aSource, mozilla::TrackID aID) { LOG((__PRETTY_FUNCTION__)); + AssertIsOnOwningThread(); { MonitorAutoLock lock(mMonitor); if (!mSources.RemoveElement(aSource)) { // Already stopped - this is allowed return NS_OK; } @@ -212,16 +222,17 @@ MediaEngineRemoteVideoSource::Stop(mozil return NS_OK; } nsresult MediaEngineRemoteVideoSource::Restart(const dom::MediaTrackConstraints& aConstraints, const MediaEnginePrefs& aPrefs, const nsString& aDeviceId) { + AssertIsOnOwningThread(); if (!mInitDone) { LOG(("Init not done")); return NS_ERROR_FAILURE; } if (!ChooseCapability(aConstraints, aPrefs, aDeviceId)) { return NS_ERROR_NOT_AVAILABLE; } if (mState != kStarted) { @@ -387,16 +398,17 @@ MediaEngineRemoteVideoSource::NumCapabil return mHardcodedCapabilities.Length(); } bool MediaEngineRemoteVideoSource::ChooseCapability(const MediaTrackConstraints &aConstraints, const MediaEnginePrefs &aPrefs, const nsString& aDeviceId) { + AssertIsOnOwningThread(); switch(mMediaSource) { case dom::MediaSourceEnum::Screen: case dom::MediaSourceEnum::Window: case dom::MediaSourceEnum::Application: { FlattenedConstraints c(aConstraints); mCapability.width = c.mWidth.Clamp(c.mWidth.mIdeal.WasPassed() ? c.mWidth.mIdeal.Value() : aPrefs.mWidth);
--- a/dom/media/webrtc/MediaEngineWebRTC.h +++ b/dom/media/webrtc/MediaEngineWebRTC.h @@ -130,16 +130,17 @@ public: const char* name, const char* uuid) : MediaEngineAudioSource(kReleased) , mVoiceEngine(aVoiceEnginePtr) , mMonitor("WebRTCMic.Monitor") , mThread(aThread) , mCapIndex(aIndex) , mChannel(-1) + , mNrAllocations(0) , mInitDone(false) , mStarted(false) , mSampleFrequency(MediaEngine::DEFAULT_SAMPLE_RATE) , mEchoOn(false), mAgcOn(false), mNoiseOn(false) , mEchoCancel(webrtc::kEcDefault) , mAGC(webrtc::kAgcDefault) , mNoiseSuppress(webrtc::kNsDefault) , mPlayoutDelay(0) @@ -210,20 +211,21 @@ private: ScopedCustomReleasePtr<webrtc::VoEExternalMedia> mVoERender; ScopedCustomReleasePtr<webrtc::VoENetwork> mVoENetwork; ScopedCustomReleasePtr<webrtc::VoEAudioProcessing> mVoEProcessing; // mMonitor protects mSources[] access/changes, and transitions of mState // from kStarted to kStopped (which are combined with EndTrack()). // mSources[] is accessed from webrtc threads. Monitor mMonitor; - nsTArray<nsRefPtr<SourceMediaStream>> mSources; // When this goes empty, we shut down HW + nsTArray<nsRefPtr<SourceMediaStream>> mSources; nsCOMPtr<nsIThread> mThread; int mCapIndex; int mChannel; + int mNrAllocations; // When this becomes 0, we shut down HW TrackID mTrackID; bool mInitDone; bool mStarted; nsString mDeviceName; nsCString mDeviceUUID; uint32_t mSampleFrequency;
--- a/dom/media/webrtc/MediaEngineWebRTCAudio.cpp +++ b/dom/media/webrtc/MediaEngineWebRTCAudio.cpp @@ -280,16 +280,17 @@ uint32_t MediaEngineWebRTCMicrophoneSour return distance; } nsresult MediaEngineWebRTCMicrophoneSource::Allocate(const dom::MediaTrackConstraints &aConstraints, const MediaEnginePrefs &aPrefs, const nsString& aDeviceId) { + AssertIsOnOwningThread(); if (mState == kReleased) { if (mInitDone) { ScopedCustomReleasePtr<webrtc::VoEHardware> ptrVoEHw(webrtc::VoEHardware::GetInterface(mVoiceEngine)); if (!ptrVoEHw || ptrVoEHw->SetRecordingDevice(mCapIndex)) { return NS_ERROR_FAILURE; } mState = kAllocated; LOG(("Audio device %d allocated", mCapIndex)); @@ -300,28 +301,27 @@ MediaEngineWebRTCMicrophoneSource::Alloc } else if (MOZ_LOG_TEST(GetMediaManagerLog(), LogLevel::Debug)) { MonitorAutoLock lock(mMonitor); if (mSources.IsEmpty()) { LOG(("Audio device %d reallocated", mCapIndex)); } else { LOG(("Audio device %d allocated shared", mCapIndex)); } } + ++mNrAllocations; return NS_OK; } nsresult MediaEngineWebRTCMicrophoneSource::Deallocate() { - bool empty; - { - MonitorAutoLock lock(mMonitor); - empty = mSources.IsEmpty(); - } - if (empty) { + AssertIsOnOwningThread(); + --mNrAllocations; + MOZ_ASSERT(mNrAllocations >= 0, "Double-deallocations are prohibited"); + if (mNrAllocations == 0) { // If empty, no callbacks to deliver data should be occuring if (mState != kStopped && mState != kAllocated) { return NS_ERROR_FAILURE; } mState = kReleased; LOG(("Audio device %d deallocated", mCapIndex)); } else { @@ -329,16 +329,17 @@ MediaEngineWebRTCMicrophoneSource::Deall } return NS_OK; } nsresult MediaEngineWebRTCMicrophoneSource::Start(SourceMediaStream *aStream, TrackID aID) { + AssertIsOnOwningThread(); if (!mInitDone || !aStream) { return NS_ERROR_FAILURE; } { MonitorAutoLock lock(mMonitor); mSources.AppendElement(aStream); } @@ -382,16 +383,17 @@ MediaEngineWebRTCMicrophoneSource::Start mVoERender->RegisterExternalMediaProcessing(mChannel, webrtc::kRecordingPerChannel, *this); return NS_OK; } nsresult MediaEngineWebRTCMicrophoneSource::Stop(SourceMediaStream *aSource, TrackID aID) { + AssertIsOnOwningThread(); { MonitorAutoLock lock(mMonitor); if (!mSources.RemoveElement(aSource)) { // Already stopped - this is allowed return NS_OK; } @@ -658,24 +660,26 @@ MediaEngineWebRTCAudioCaptureSource::Get // Remove {} and the null terminator aUUID.Assign(Substring(asciiString, 1, NSID_LENGTH - 3)); } nsresult MediaEngineWebRTCAudioCaptureSource::Start(SourceMediaStream *aMediaStream, TrackID aId) { + AssertIsOnOwningThread(); aMediaStream->AddTrack(aId, 0, new AudioSegment()); return NS_OK; } nsresult MediaEngineWebRTCAudioCaptureSource::Stop(SourceMediaStream *aMediaStream, TrackID aId) { + AssertIsOnOwningThread(); aMediaStream->EndAllTrackAndFinish(); return NS_OK; } nsresult MediaEngineWebRTCAudioCaptureSource::Restart( const dom::MediaTrackConstraints& aConstraints, const MediaEnginePrefs &aPrefs,
--- a/dom/network/TCPSocket.cpp +++ b/dom/network/TCPSocket.cpp @@ -1035,17 +1035,17 @@ TCPSocket::OnDataAvailable(nsIRequest* a AutoJSAPI api; if (!api.Init(GetOwnerGlobal())) { return NS_ERROR_FAILURE; } JSContext* cx = api.cx(); JS::Rooted<JS::Value> value(cx); - if (!ToJSValue(cx, TypedArrayCreator<Uint8Array>(buffer), &value)) { + if (!ToJSValue(cx, TypedArrayCreator<ArrayBuffer>(buffer), &value)) { return NS_ERROR_FAILURE; } FireDataEvent(cx, NS_LITERAL_STRING("data"), value); return NS_OK; } nsCString data; nsresult rv = mInputStreamScriptable->ReadBytes(aCount, data);
--- a/dom/network/tests/tcpsocket_test.jsm +++ b/dom/network/tests/tcpsocket_test.jsm @@ -1,13 +1,20 @@ -this.EXPORTED_SYMBOLS = ['createSocket', 'createServer', 'enablePrefsAndPermissions']; +this.EXPORTED_SYMBOLS = [ + 'createSocket', 'createServer', 'enablePrefsAndPermissions', + 'socketCompartmentInstanceOfArrayBuffer']; this.createSocket = function(host, port, options) { return new TCPSocket(host, port, options); } this.createServer = function(port, options, backlog) { return new TCPServerSocket(port, options, backlog); } this.enablePrefsAndPermissions = function() { return false; } + +// See test_tcpsocket_client_and_server_basics.html's version for rationale. +this.socketCompartmentInstanceOfArrayBuffer = function(obj) { + return obj instanceof ArrayBuffer; +}
--- a/dom/network/tests/test_tcpsocket_client_and_server_basics.html +++ b/dom/network/tests/test_tcpsocket_client_and_server_basics.html @@ -20,16 +20,27 @@ https://bugzilla.mozilla.org/show_bug.cg function createSocket(host, port, options) { return new TCPSocket(host, port, options); } function enablePrefsAndPermissions() { return true; } + + // In the JSM case, ArrayBuffers will be created in the compartment of the + // JSM with different globals than the + // test_tcpsocket_client_and_server_basics.js test logic sees, so we (and + // tcpsocket_test.jsm) need to do something. To avoid complexity relating + // to wrappers and the varying nuances of the module scope and global scope + // in JSM's (they differ on B2G), we hardcode ArrayBuffer rather than taking + // a string that we look up, etc. + function socketCompartmentInstanceOfArrayBuffer(obj) { + return obj instanceof ArrayBuffer; + } </script> <script type="application/javascript;version=1.7" src="test_tcpsocket_client_and_server_basics.js"></script> </head> <body> <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1084245">Mozilla Bug 1084245</a> <p id="display"></p> <div id="content" style="display: none">
--- a/dom/network/tests/test_tcpsocket_client_and_server_basics.js +++ b/dom/network/tests/test_tcpsocket_client_and_server_basics.js @@ -50,16 +50,18 @@ function listenForEventsOnSocket(socket, socket.onopen = handleGenericEvent; socket.ondrain = handleGenericEvent; socket.onerror = handleGenericEvent; socket.onclose = handleGenericEvent; socket.ondata = function(event) { dump('(' + socketType + ' event: ' + event.type + ' length: ' + event.data.byteLength + ')\n'); + ok(socketCompartmentInstanceOfArrayBuffer(event.data), + 'payload is ArrayBuffer'); var arr = new Uint8Array(event.data); if (receivedData === null) { receivedData = arr; } else { receivedData = concatUint8Arrays(receivedData, arr); } if (wantDataLength !== null && receivedData.length >= wantDataLength) {
--- a/dom/webidl/MediaStream.webidl +++ b/dom/webidl/MediaStream.webidl @@ -22,20 +22,20 @@ dictionary MediaStreamConstraints { // wave if audio is enabled. boolean fakeTracks; // For testing purpose, works only if fake is // enabled. Enable fakeTracks returns a stream // with two extra empty video tracks and three // extra empty audio tracks. DOMString? peerIdentity = null; }; -// [Exposed=Window, -// Constructor, -// Constructor (MediaStream stream), -// Constructor (sequence<MediaStreamTrack> tracks)] +[Exposed=Window, + Constructor, + Constructor (MediaStream stream), + Constructor (sequence<MediaStreamTrack> tracks)] interface MediaStream : EventTarget { readonly attribute DOMString id; sequence<AudioStreamTrack> getAudioTracks (); sequence<VideoStreamTrack> getVideoTracks (); sequence<MediaStreamTrack> getTracks (); // MediaStreamTrack? getTrackById (DOMString trackId); void addTrack (MediaStreamTrack track); void removeTrack (MediaStreamTrack track);
--- a/gfx/harfbuzz/src/hb-blob.cc +++ b/gfx/harfbuzz/src/hb-blob.cc @@ -86,17 +86,17 @@ static void * @destroy: Callback to call when @data is not needed anymore. * * Creates a new "blob" object wrapping @data. The @mode parameter is used * to negotiate ownership and lifecycle of @data. * * Return value: New blob, or the empty blob if something failed or if @length is * zero. Destroy with hb_blob_destroy(). * - * Since: 1.0 + * Since: 0.9.2 **/ hb_blob_t * hb_blob_create (const char *data, unsigned int length, hb_memory_mode_t mode, void *user_data, hb_destroy_func_t destroy) { @@ -142,17 +142,17 @@ hb_blob_create (const char *data, * is. * * Makes @parent immutable. * * Return value: New blob, or the empty blob if something failed or if * @length is zero or @offset is beyond the end of @parent's data. Destroy * with hb_blob_destroy(). * - * Since: 1.0 + * Since: 0.9.2 **/ hb_blob_t * hb_blob_create_sub_blob (hb_blob_t *parent, unsigned int offset, unsigned int length) { hb_blob_t *blob; @@ -174,17 +174,17 @@ hb_blob_create_sub_blob (hb_blob_t *p * hb_blob_get_empty: * * Returns the singleton empty blob. * * See TODO:link object types for more information. * * Return value: (transfer full): the empty blob. * - * Since: 1.0 + * Since: 0.9.2 **/ hb_blob_t * hb_blob_get_empty (void) { static const hb_blob_t _hb_blob_nil = { HB_OBJECT_HEADER_STATIC, true, /* immutable */ @@ -205,17 +205,17 @@ hb_blob_get_empty (void) * @blob: a blob. * * Increases the reference count on @blob. * * See TODO:link object types for more information. * * Return value: @blob. * - * Since: 1.0 + * Since: 0.9.2 **/ hb_blob_t * hb_blob_reference (hb_blob_t *blob) { return hb_object_reference (blob); } /** @@ -223,17 +223,17 @@ hb_blob_reference (hb_blob_t *blob) * @blob: a blob. * * Descreases the reference count on @blob, and if it reaches zero, destroys * @blob, freeing all memory, possibly calling the destroy-callback the blob * was created for if it has not been called already. * * See TODO:link object types for more information. * - * Since: 1.0 + * Since: 0.9.2 **/ void hb_blob_destroy (hb_blob_t *blob) { if (!hb_object_destroy (blob)) return; _hb_blob_destroy_user_data (blob); @@ -245,17 +245,17 @@ hb_blob_destroy (hb_blob_t *blob) * @blob: a blob. * @key: key for data to set. * @data: data to set. * @destroy: callback to call when @data is not needed anymore. * @replace: whether to replace an existing data with the same key. * * Return value: * - * Since: 1.0 + * Since: 0.9.2 **/ hb_bool_t hb_blob_set_user_data (hb_blob_t *blob, hb_user_data_key_t *key, void * data, hb_destroy_func_t destroy, hb_bool_t replace) { @@ -266,33 +266,33 @@ hb_blob_set_user_data (hb_blob_t * hb_blob_get_user_data: (skip) * @blob: a blob. * @key: key for data to get. * * * * Return value: (transfer none): * - * Since: 1.0 + * Since: 0.9.2 **/ void * hb_blob_get_user_data (hb_blob_t *blob, hb_user_data_key_t *key) { return hb_object_get_user_data (blob, key); } /** * hb_blob_make_immutable: * @blob: a blob. * * * - * Since: 1.0 + * Since: 0.9.2 **/ void hb_blob_make_immutable (hb_blob_t *blob) { if (hb_object_is_inert (blob)) return; blob->immutable = true; @@ -301,51 +301,51 @@ hb_blob_make_immutable (hb_blob_t *blob) /** * hb_blob_is_immutable: * @blob: a blob. * * * * Return value: TODO * - * Since: 1.0 + * Since: 0.9.2 **/ hb_bool_t hb_blob_is_immutable (hb_blob_t *blob) { return blob->immutable; } /** * hb_blob_get_length: * @blob: a blob. * * * * Return value: the length of blob data in bytes. * - * Since: 1.0 + * Since: 0.9.2 **/ unsigned int hb_blob_get_length (hb_blob_t *blob) { return blob->length; } /** * hb_blob_get_data: * @blob: a blob. * @length: (out): * * * * Returns: (transfer none) (array length=length): * - * Since: 1.0 + * Since: 0.9.2 **/ const char * hb_blob_get_data (hb_blob_t *blob, unsigned int *length) { if (length) *length = blob->length; return blob->data; @@ -360,17 +360,17 @@ hb_blob_get_data (hb_blob_t *blob, unsig * return pointer to data. * * Fails if blob has been made immutable, or if memory allocation * fails. * * Returns: (transfer none) (array length=length): Writable blob data, * or %NULL if failed. * - * Since: 1.0 + * Since: 0.9.2 **/ char * hb_blob_get_data_writable (hb_blob_t *blob, unsigned int *length) { if (!_try_writable (blob)) { if (length) *length = 0;
--- a/gfx/harfbuzz/src/hb-buffer-serialize.cc +++ b/gfx/harfbuzz/src/hb-buffer-serialize.cc @@ -35,51 +35,51 @@ static const char *serialize_formats[] = /** * hb_buffer_serialize_list_formats: * * * * Return value: (transfer none): * - * Since: 1.0 + * Since: 0.9.2 **/ const char ** hb_buffer_serialize_list_formats (void) { return serialize_formats; } /** * hb_buffer_serialize_format_from_string: * @str: * @len: * * * * Return value: * - * Since: 1.0 + * Since: 0.9.2 **/ hb_buffer_serialize_format_t hb_buffer_serialize_format_from_string (const char *str, int len) { /* Upper-case it. */ return (hb_buffer_serialize_format_t) (hb_tag_from_string (str, len) & ~0x20202020u); } /** * hb_buffer_serialize_format_to_string: * @format: * * * * Return value: * - * Since: 1.0 + * Since: 0.9.2 **/ const char * hb_buffer_serialize_format_to_string (hb_buffer_serialize_format_t format) { switch (format) { case HB_BUFFER_SERIALIZE_FORMAT_TEXT: return serialize_formats[0]; case HB_BUFFER_SERIALIZE_FORMAT_JSON: return serialize_formats[1]; @@ -254,17 +254,17 @@ static unsigned int * @font: * @format: * @flags: * * * * Return value: * - * Since: 1.0 + * Since: 0.9.2 **/ unsigned int hb_buffer_serialize_glyphs (hb_buffer_t *buffer, unsigned int start, unsigned int end, char *buf, unsigned int buf_size, unsigned int *buf_consumed, /* May be NULL */ @@ -361,17 +361,17 @@ parse_int (const char *pp, const char *e * @end_ptr: (out): * @font: * @format: * * * * Return value: * - * Since: 1.0 + * Since: 0.9.2 **/ hb_bool_t hb_buffer_deserialize_glyphs (hb_buffer_t *buffer, const char *buf, int buf_len, /* -1 means nul-terminated */ const char **end_ptr, /* May be NULL */ hb_font_t *font, /* May be NULL */ hb_buffer_serialize_format_t format)
--- a/gfx/harfbuzz/src/hb-buffer.cc +++ b/gfx/harfbuzz/src/hb-buffer.cc @@ -699,17 +699,17 @@ void hb_buffer_t::deallocate_var_all (vo /** * hb_buffer_create: (Xconstructor) * * * * Return value: (transfer full) * - * Since: 1.0 + * Since: 0.9.2 **/ hb_buffer_t * hb_buffer_create (void) { hb_buffer_t *buffer; if (!(buffer = hb_object_create<hb_buffer_t> ())) return hb_buffer_get_empty (); @@ -721,17 +721,17 @@ hb_buffer_create (void) /** * hb_buffer_get_empty: * * * * Return value: (transfer full): * - * Since: 1.0 + * Since: 0.9.2 **/ hb_buffer_t * hb_buffer_get_empty (void) { static const hb_buffer_t _hb_buffer_nil = { HB_OBJECT_HEADER_STATIC, const_cast<hb_unicode_funcs_t *> (&_hb_unicode_funcs_nil), @@ -754,31 +754,31 @@ hb_buffer_get_empty (void) /** * hb_buffer_reference: (skip) * @buffer: a buffer. * * * * Return value: (transfer full): * - * Since: 1.0 + * Since: 0.9.2 **/ hb_buffer_t * hb_buffer_reference (hb_buffer_t *buffer) { return hb_object_reference (buffer); } /** * hb_buffer_destroy: (skip) * @buffer: a buffer. * * * - * Since: 1.0 + * Since: 0.9.2 **/ void hb_buffer_destroy (hb_buffer_t *buffer) { if (!hb_object_destroy (buffer)) return; hb_unicode_funcs_destroy (buffer->unicode); @@ -795,17 +795,17 @@ hb_buffer_destroy (hb_buffer_t *buffer) * @data: * @destroy: * @replace: * * * * Return value: * - * Since: 1.0 + * Since: 0.9.2 **/ hb_bool_t hb_buffer_set_user_data (hb_buffer_t *buffer, hb_user_data_key_t *key, void * data, hb_destroy_func_t destroy, hb_bool_t replace) { @@ -816,17 +816,17 @@ hb_buffer_set_user_data (hb_buffer_t * hb_buffer_get_user_data: (skip) * @buffer: a buffer. * @key: * * * * Return value: * - * Since: 1.0 + * Since: 0.9.2 **/ void * hb_buffer_get_user_data (hb_buffer_t *buffer, hb_user_data_key_t *key) { return hb_object_get_user_data (buffer, key); } @@ -866,17 +866,17 @@ hb_buffer_get_content_type (hb_buffer_t /** * hb_buffer_set_unicode_funcs: * @buffer: a buffer. * @unicode_funcs: * * * - * Since: 1.0 + * Since: 0.9.2 **/ void hb_buffer_set_unicode_funcs (hb_buffer_t *buffer, hb_unicode_funcs_t *unicode_funcs) { if (unlikely (hb_object_is_inert (buffer))) return; @@ -892,32 +892,32 @@ hb_buffer_set_unicode_funcs (hb_buffer_t /** * hb_buffer_get_unicode_funcs: * @buffer: a buffer. * * * * Return value: * - * Since: 1.0 + * Since: 0.9.2 **/ hb_unicode_funcs_t * hb_buffer_get_unicode_funcs (hb_buffer_t *buffer) { return buffer->unicode; } /** * hb_buffer_set_direction: * @buffer: a buffer. * @direction: * * * - * Since: 1.0 + * Since: 0.9.2 **/ void hb_buffer_set_direction (hb_buffer_t *buffer, hb_direction_t direction) { if (unlikely (hb_object_is_inert (buffer))) return; @@ -928,32 +928,32 @@ hb_buffer_set_direction (hb_buffer_t /** * hb_buffer_get_direction: * @buffer: a buffer. * * * * Return value: * - * Since: 1.0 + * Since: 0.9.2 **/ hb_direction_t hb_buffer_get_direction (hb_buffer_t *buffer) { return buffer->props.direction; } /** * hb_buffer_set_script: * @buffer: a buffer. * @script: * * * - * Since: 1.0 + * Since: 0.9.2 **/ void hb_buffer_set_script (hb_buffer_t *buffer, hb_script_t script) { if (unlikely (hb_object_is_inert (buffer))) return; @@ -963,32 +963,32 @@ hb_buffer_set_script (hb_buffer_t *buffe /** * hb_buffer_get_script: * @buffer: a buffer. * * * * Return value: * - * Since: 1.0 + * Since: 0.9.2 **/ hb_script_t hb_buffer_get_script (hb_buffer_t *buffer) { return buffer->props.script; } /** * hb_buffer_set_language: * @buffer: a buffer. * @language: * * * - * Since: 1.0 + * Since: 0.9.2 **/ void hb_buffer_set_language (hb_buffer_t *buffer, hb_language_t language) { if (unlikely (hb_object_is_inert (buffer))) return; @@ -998,17 +998,17 @@ hb_buffer_set_language (hb_buffer_t *b /** * hb_buffer_get_language: * @buffer: a buffer. * * * * Return value: (transfer none): * - * Since: 1.0 + * Since: 0.9.2 **/ hb_language_t hb_buffer_get_language (hb_buffer_t *buffer) { return buffer->props.language; } /** @@ -1155,17 +1155,17 @@ hb_buffer_get_replacement_codepoint (hb_ /** * hb_buffer_reset: * @buffer: a buffer. * * * - * Since: 1.0 + * Since: 0.9.2 **/ void hb_buffer_reset (hb_buffer_t *buffer) { buffer->reset (); } /** @@ -1186,49 +1186,49 @@ hb_buffer_clear_contents (hb_buffer_t *b * hb_buffer_pre_allocate: * @buffer: a buffer. * @size: * * * * Return value: * - * Since: 1.0 + * Since: 0.9.2 **/ hb_bool_t hb_buffer_pre_allocate (hb_buffer_t *buffer, unsigned int size) { return buffer->ensure (size); } /** * hb_buffer_allocation_successful: * @buffer: a buffer. * * * * Return value: * - * Since: 1.0 + * Since: 0.9.2 **/ hb_bool_t hb_buffer_allocation_successful (hb_buffer_t *buffer) { return !buffer->in_error; } /** * hb_buffer_add: * @buffer: a buffer. * @codepoint: * @cluster: * * * - * Since: 1.0 + * Since: 0.9.7 **/ void hb_buffer_add (hb_buffer_t *buffer, hb_codepoint_t codepoint, unsigned int cluster) { buffer->add (codepoint, cluster); buffer->clear_context (1); @@ -1238,17 +1238,17 @@ hb_buffer_add (hb_buffer_t *buffer, * hb_buffer_set_length: * @buffer: a buffer. * @length: * * * * Return value: * - * Since: 1.0 + * Since: 0.9.2 **/ hb_bool_t hb_buffer_set_length (hb_buffer_t *buffer, unsigned int length) { if (unlikely (hb_object_is_inert (buffer))) return length == 0; @@ -1277,17 +1277,17 @@ hb_buffer_set_length (hb_buffer_t *buff /** * hb_buffer_get_length: * @buffer: a buffer. * * Returns the number of items in the buffer. * * Return value: buffer length. * - * Since: 1.0 + * Since: 0.9.2 **/ unsigned int hb_buffer_get_length (hb_buffer_t *buffer) { return buffer->len; } /** @@ -1295,17 +1295,17 @@ hb_buffer_get_length (hb_buffer_t *buffe * @buffer: a buffer. * @length: (out): output array length. * * Returns buffer glyph information array. Returned pointer * is valid as long as buffer contents are not modified. * * Return value: (transfer none) (array length=length): buffer glyph information array. * - * Since: 1.0 + * Since: 0.9.2 **/ hb_glyph_info_t * hb_buffer_get_glyph_infos (hb_buffer_t *buffer, unsigned int *length) { if (length) *length = buffer->len; @@ -1317,17 +1317,17 @@ hb_buffer_get_glyph_infos (hb_buffer_t * @buffer: a buffer. * @length: (out): output length. * * Returns buffer glyph position array. Returned pointer * is valid as long as buffer contents are not modified. * * Return value: (transfer none) (array length=length): buffer glyph position array. * - * Since: 1.0 + * Since: 0.9.2 **/ hb_glyph_position_t * hb_buffer_get_glyph_positions (hb_buffer_t *buffer, unsigned int *length) { if (!buffer->have_positions) buffer->clear_positions (); @@ -1338,50 +1338,50 @@ hb_buffer_get_glyph_positions (hb_buffer } /** * hb_buffer_reverse: * @buffer: a buffer. * * Reverses buffer contents. * - * Since: 1.0 + * Since: 0.9.2 **/ void hb_buffer_reverse (hb_buffer_t *buffer) { buffer->reverse (); } /** * hb_buffer_reverse_range: * @buffer: a buffer. * @start: start index. * @end: end index. * - * Reverses buffer contents between start to end. + * Reverses buffer contents between start to end. * - * Since: 1.0 + * Since: 0.9.41 **/ void hb_buffer_reverse_range (hb_buffer_t *buffer, unsigned int start, unsigned int end) { buffer->reverse_range (start, end); } /** * hb_buffer_reverse_clusters: * @buffer: a buffer. * * Reverses buffer clusters. That is, the buffer contents are * reversed, then each cluster (consecutive items having the * same cluster number) are reversed again. * - * Since: 1.0 + * Since: 0.9.2 **/ void hb_buffer_reverse_clusters (hb_buffer_t *buffer) { buffer->reverse_clusters (); } /** @@ -1488,17 +1488,17 @@ hb_buffer_add_utf (hb_buffer_t *buffer, * @buffer: a buffer. * @text: (array length=text_length) (element-type uint8_t): * @text_length: * @item_offset: * @item_length: * * * - * Since: 1.0 + * Since: 0.9.2 **/ void hb_buffer_add_utf8 (hb_buffer_t *buffer, const char *text, int text_length, unsigned int item_offset, int item_length) { @@ -1510,17 +1510,17 @@ hb_buffer_add_utf8 (hb_buffer_t *buffer * @buffer: a buffer. * @text: (array length=text_length): * @text_length: * @item_offset: * @item_length: * * * - * Since: 1.0 + * Since: 0.9.2 **/ void hb_buffer_add_utf16 (hb_buffer_t *buffer, const uint16_t *text, int text_length, unsigned int item_offset, int item_length) { @@ -1532,17 +1532,17 @@ hb_buffer_add_utf16 (hb_buffer_t *buf * @buffer: a buffer. * @text: (array length=text_length): * @text_length: * @item_offset: * @item_length: * * * - * Since: 1.0 + * Since: 0.9.2 **/ void hb_buffer_add_utf32 (hb_buffer_t *buffer, const uint32_t *text, int text_length, unsigned int item_offset, int item_length) {
--- a/gfx/harfbuzz/src/hb-buffer.h +++ b/gfx/harfbuzz/src/hb-buffer.h @@ -166,30 +166,36 @@ hb_buffer_set_segment_properties (hb_buf void hb_buffer_get_segment_properties (hb_buffer_t *buffer, hb_segment_properties_t *props); void hb_buffer_guess_segment_properties (hb_buffer_t *buffer); +/* + * Since: 0.9.20 + */ typedef enum { /*< flags >*/ HB_BUFFER_FLAG_DEFAULT = 0x00000000u, HB_BUFFER_FLAG_BOT = 0x00000001u, /* Beginning-of-text */ HB_BUFFER_FLAG_EOT = 0x00000002u, /* End-of-text */ HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES = 0x00000004u } hb_buffer_flags_t; void hb_buffer_set_flags (hb_buffer_t *buffer, hb_buffer_flags_t flags); hb_buffer_flags_t hb_buffer_get_flags (hb_buffer_t *buffer); +/* + * Since: 0.9.42 + */ typedef enum { HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES = 0, HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS = 1, HB_BUFFER_CLUSTER_LEVEL_CHARACTERS = 2, HB_BUFFER_CLUSTER_LEVEL_DEFAULT = HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES } hb_buffer_cluster_level_t; void @@ -314,16 +320,19 @@ hb_buffer_get_glyph_positions (hb_buffer void hb_buffer_normalize_glyphs (hb_buffer_t *buffer); /* * Serialize */ +/* + * Since: 0.9.20 + */ typedef enum { /*< flags >*/ HB_BUFFER_SERIALIZE_FLAG_DEFAULT = 0x00000000u, HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS = 0x00000001u, HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS = 0x00000002u, HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES = 0x00000004u, HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS = 0x00000008u } hb_buffer_serialize_flags_t;
--- a/gfx/harfbuzz/src/hb-common.cc +++ b/gfx/harfbuzz/src/hb-common.cc @@ -59,17 +59,17 @@ void * hb_tag_from_string: * @str: (array length=len) (element-type uint8_t): * @len: * * * * Return value: * - * Since: 1.0 + * Since: 0.9.2 **/ hb_tag_t hb_tag_from_string (const char *str, int len) { char tag[4]; unsigned int i; if (!str || !len || !*str) @@ -117,17 +117,17 @@ const char direction_strings[][4] = { * hb_direction_from_string: * @str: (array length=len) (element-type uint8_t): * @len: * * * * Return value: * - * Since: 1.0 + * Since: 0.9.2 **/ hb_direction_t hb_direction_from_string (const char *str, int len) { if (unlikely (!str || !len || !*str)) return HB_DIRECTION_INVALID; /* Lets match loosely: just match the first letter, such that @@ -144,17 +144,17 @@ hb_direction_from_string (const char *st /** * hb_direction_to_string: * @direction: * * * * Return value: (transfer none): * - * Since: 1.0 + * Since: 0.9.2 **/ const char * hb_direction_to_string (hb_direction_t direction) { if (likely ((unsigned int) (direction - HB_DIRECTION_LTR) < ARRAY_LENGTH (direction_strings))) return direction_strings[direction - HB_DIRECTION_LTR]; @@ -283,65 +283,65 @@ retry: * hb_language_from_string: * @str: (array length=len) (element-type uint8_t): * @len: * * * * Return value: (transfer none): * - * Since: 1.0 + * Since: 0.9.2 **/ hb_language_t hb_language_from_string (const char *str, int len) { - char strbuf[64]; - if (!str || !len || !*str) return HB_LANGUAGE_INVALID; + hb_language_item_t *item = NULL; if (len >= 0) { /* NUL-terminate it. */ + char strbuf[64]; len = MIN (len, (int) sizeof (strbuf) - 1); memcpy (strbuf, str, len); strbuf[len] = '\0'; - str = strbuf; + item = lang_find_or_insert (strbuf); } - - hb_language_item_t *item = lang_find_or_insert (str); + else + item = lang_find_or_insert (str); return likely (item) ? item->lang : HB_LANGUAGE_INVALID; } /** * hb_language_to_string: * @language: * * * * Return value: (transfer none): * - * Since: 1.0 + * Since: 0.9.2 **/ const char * hb_language_to_string (hb_language_t language) { /* This is actually NULL-safe! */ return language->s; } /** * hb_language_get_default: * * * * Return value: (transfer none): * - * Since: 1.0 + * Since: 0.9.2 **/ hb_language_t hb_language_get_default (void) { static hb_language_t default_language = HB_LANGUAGE_INVALID; hb_language_t language = (hb_language_t) hb_atomic_ptr_get (&default_language); if (unlikely (language == HB_LANGUAGE_INVALID)) { @@ -358,17 +358,17 @@ hb_language_get_default (void) /** * hb_script_from_iso15924_tag: * @tag: * * * * Return value: * - * Since: 1.0 + * Since: 0.9.2 **/ hb_script_t hb_script_from_iso15924_tag (hb_tag_t tag) { if (unlikely (tag == HB_TAG_NONE)) return HB_SCRIPT_INVALID; /* Be lenient, adjust case (one capital letter followed by three small letters) */ @@ -403,49 +403,49 @@ hb_script_from_iso15924_tag (hb_tag_t ta * hb_script_from_string: * @s: (array length=len) (element-type uint8_t): * @len: * * * * Return value: * - * Since: 1.0 + * Since: 0.9.2 **/ hb_script_t hb_script_from_string (const char *s, int len) { return hb_script_from_iso15924_tag (hb_tag_from_string (s, len)); } /** * hb_script_to_iso15924_tag: * @script: * * * * Return value: * - * Since: 1.0 + * Since: 0.9.2 **/ hb_tag_t hb_script_to_iso15924_tag (hb_script_t script) { return (hb_tag_t) script; } /** * hb_script_get_horizontal_direction: * @script: * * * * Return value: * - * Since: 1.0 + * Since: 0.9.2 **/ hb_direction_t hb_script_get_horizontal_direction (hb_script_t script) { /* http://goo.gl/x9ilM */ switch ((hb_tag_t) script) { /* Unicode-1.1 additions */ @@ -540,17 +540,17 @@ hb_user_data_array_t::get (hb_user_data_ /** * hb_version: * @major: (out): Library major version component. * @minor: (out): Library minor version component. * @micro: (out): Library micro version component. * * Returns library version as three integer components. * - * Since: 1.0 + * Since: 0.9.2 **/ void hb_version (unsigned int *major, unsigned int *minor, unsigned int *micro) { *major = HB_VERSION_MAJOR; *minor = HB_VERSION_MINOR; @@ -559,17 +559,17 @@ hb_version (unsigned int *major, /** * hb_version_string: * * Returns library version as a string with three components. * * Return value: library version string. * - * Since: 1.0 + * Since: 0.9.2 **/ const char * hb_version_string (void) { return HB_VERSION_STRING; } /**
--- a/gfx/harfbuzz/src/hb-common.h +++ b/gfx/harfbuzz/src/hb-common.h @@ -267,16 +267,19 @@ typedef enum /*6.1*/ HB_SCRIPT_CHAKMA = HB_TAG ('C','a','k','m'), /*6.1*/ HB_SCRIPT_MEROITIC_CURSIVE = HB_TAG ('M','e','r','c'), /*6.1*/ HB_SCRIPT_MEROITIC_HIEROGLYPHS = HB_TAG ('M','e','r','o'), /*6.1*/ HB_SCRIPT_MIAO = HB_TAG ('P','l','r','d'), /*6.1*/ HB_SCRIPT_SHARADA = HB_TAG ('S','h','r','d'), /*6.1*/ HB_SCRIPT_SORA_SOMPENG = HB_TAG ('S','o','r','a'), /*6.1*/ HB_SCRIPT_TAKRI = HB_TAG ('T','a','k','r'), + /* + * Since: 0.9.30 + */ /*7.0*/ HB_SCRIPT_BASSA_VAH = HB_TAG ('B','a','s','s'), /*7.0*/ HB_SCRIPT_CAUCASIAN_ALBANIAN = HB_TAG ('A','g','h','b'), /*7.0*/ HB_SCRIPT_DUPLOYAN = HB_TAG ('D','u','p','l'), /*7.0*/ HB_SCRIPT_ELBASAN = HB_TAG ('E','l','b','a'), /*7.0*/ HB_SCRIPT_GRANTHA = HB_TAG ('G','r','a','n'), /*7.0*/ HB_SCRIPT_KHOJKI = HB_TAG ('K','h','o','j'), /*7.0*/ HB_SCRIPT_KHUDAWADI = HB_TAG ('S','i','n','d'), /*7.0*/ HB_SCRIPT_LINEAR_A = HB_TAG ('L','i','n','a'),
--- a/gfx/harfbuzz/src/hb-coretext.cc +++ b/gfx/harfbuzz/src/hb-coretext.cc @@ -120,16 +120,19 @@ hb_coretext_shaper_face_data_t * } void _hb_coretext_shaper_face_data_destroy (hb_coretext_shaper_face_data_t *data) { CFRelease (data); } +/* + * Since: 0.9.10 + */ CGFontRef hb_coretext_face_get_cg_font (hb_face_t *face) { if (unlikely (!hb_coretext_shaper_face_data_ensure (face))) return NULL; hb_coretext_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face); return face_data; }
--- a/gfx/harfbuzz/src/hb-face.cc +++ b/gfx/harfbuzz/src/hb-face.cc @@ -72,17 +72,17 @@ const hb_face_t _hb_face_nil = { * @reference_table_func: (closure user_data) (destroy destroy) (scope notified): * @user_data: * @destroy: * * * * Return value: (transfer full) * - * Since: 1.0 + * Since: 0.9.2 **/ hb_face_t * hb_face_create_for_tables (hb_reference_table_func_t reference_table_func, void *user_data, hb_destroy_func_t destroy) { hb_face_t *face; @@ -108,17 +108,17 @@ typedef struct hb_face_for_data_closure_ unsigned int index; } hb_face_for_data_closure_t; static hb_face_for_data_closure_t * _hb_face_for_data_closure_create (hb_blob_t *blob, unsigned int index) { hb_face_for_data_closure_t *closure; - closure = (hb_face_for_data_closure_t *) malloc (sizeof (hb_face_for_data_closure_t)); + closure = (hb_face_for_data_closure_t *) calloc (1, sizeof (hb_face_for_data_closure_t)); if (unlikely (!closure)) return NULL; closure->blob = blob; closure->index = index; return closure; } @@ -152,17 +152,17 @@ static hb_blob_t * * hb_face_create: (Xconstructor) * @blob: * @index: * * * * Return value: (transfer full): * - * Since: 1.0 + * Since: 0.9.2 **/ hb_face_t * hb_face_create (hb_blob_t *blob, unsigned int index) { hb_face_t *face; if (unlikely (!blob)) @@ -184,48 +184,48 @@ hb_face_create (hb_blob_t *blob, /** * hb_face_get_empty: * * * * Return value: (transfer full) * - * Since: 1.0 + * Since: 0.9.2 **/ hb_face_t * hb_face_get_empty (void) { return const_cast<hb_face_t *> (&_hb_face_nil); } /** * hb_face_reference: (skip) * @face: a face. * * * * Return value: * - * Since: 1.0 + * Since: 0.9.2 **/ hb_face_t * hb_face_reference (hb_face_t *face) { return hb_object_reference (face); } /** * hb_face_destroy: (skip) * @face: a face. * * * - * Since: 1.0 + * Since: 0.9.2 **/ void hb_face_destroy (hb_face_t *face) { if (!hb_object_destroy (face)) return; for (hb_face_t::plan_node_t *node = face->shape_plans; node; ) { @@ -252,17 +252,17 @@ hb_face_destroy (hb_face_t *face) * @data: * @destroy: * @replace: * * * * Return value: * - * Since: 1.0 + * Since: 0.9.2 **/ hb_bool_t hb_face_set_user_data (hb_face_t *face, hb_user_data_key_t *key, void * data, hb_destroy_func_t destroy, hb_bool_t replace) { @@ -273,32 +273,32 @@ hb_face_set_user_data (hb_face_t * hb_face_get_user_data: (skip) * @face: a face. * @key: * * * * Return value: (transfer none): * - * Since: 1.0 + * Since: 0.9.2 **/ void * hb_face_get_user_data (hb_face_t *face, hb_user_data_key_t *key) { return hb_object_get_user_data (face, key); } /** * hb_face_make_immutable: * @face: a face. * * * - * Since: 1.0 + * Since: 0.9.2 **/ void hb_face_make_immutable (hb_face_t *face) { if (unlikely (hb_object_is_inert (face))) return; face->immutable = true; @@ -307,17 +307,17 @@ hb_face_make_immutable (hb_face_t *face) /** * hb_face_is_immutable: * @face: a face. * * * * Return value: * - * Since: 1.0 + * Since: 0.9.2 **/ hb_bool_t hb_face_is_immutable (hb_face_t *face) { return face->immutable; } @@ -325,17 +325,17 @@ hb_face_is_immutable (hb_face_t *face) * hb_face_reference_table: * @face: a face. * @tag: * * * * Return value: (transfer full): * - * Since: 1.0 + * Since: 0.9.2 **/ hb_blob_t * hb_face_reference_table (hb_face_t *face, hb_tag_t tag) { return face->reference_table (tag); } @@ -412,17 +412,17 @@ hb_face_set_upem (hb_face_t *face, /** * hb_face_get_upem: * @face: a face. * * * * Return value: * - * Since: 1.0 + * Since: 0.9.2 **/ unsigned int hb_face_get_upem (hb_face_t *face) { return face->get_upem (); } void
--- a/gfx/harfbuzz/src/hb-font-private.hh +++ b/gfx/harfbuzz/src/hb-font-private.hh @@ -263,17 +263,17 @@ struct hb_font_t { } /* Internal only */ inline void guess_v_origin_minus_h_origin (hb_codepoint_t glyph, hb_position_t *x, hb_position_t *y) { *x = get_glyph_h_advance (glyph) / 2; - /* TODO use font_metics.ascent */ + /* TODO use font_metrics.ascent */ *y = y_scale; } inline void get_glyph_origin_for_direction (hb_codepoint_t glyph, hb_direction_t direction, hb_position_t *x, hb_position_t *y) { if (likely (HB_DIRECTION_IS_HORIZONTAL (direction)))
--- a/gfx/harfbuzz/src/hb-font.cc +++ b/gfx/harfbuzz/src/hb-font.cc @@ -231,17 +231,17 @@ static const hb_font_funcs_t _hb_font_fu /** * hb_font_funcs_create: (Xconstructor) * * * * Return value: (transfer full): * - * Since: 1.0 + * Since: 0.9.2 **/ hb_font_funcs_t * hb_font_funcs_create (void) { hb_font_funcs_t *ffuncs; if (!(ffuncs = hb_object_create<hb_font_funcs_t> ())) return hb_font_funcs_get_empty (); @@ -253,47 +253,47 @@ hb_font_funcs_create (void) /** * hb_font_funcs_get_empty: * * * * Return value: (transfer full): * - * Since: 1.0 + * Since: 0.9.2 **/ hb_font_funcs_t * hb_font_funcs_get_empty (void) { return const_cast<hb_font_funcs_t *> (&_hb_font_funcs_nil); } /** * hb_font_funcs_reference: (skip) * @ffuncs: font functions. * * * * Return value: * - * Since: 1.0 + * Since: 0.9.2 **/ hb_font_funcs_t * hb_font_funcs_reference (hb_font_funcs_t *ffuncs) { return hb_object_reference (ffuncs); } /** * hb_font_funcs_destroy: (skip) * @ffuncs: font functions. * * * - * Since: 1.0 + * Since: 0.9.2 **/ void hb_font_funcs_destroy (hb_font_funcs_t *ffuncs) { if (!hb_object_destroy (ffuncs)) return; #define HB_FONT_FUNC_IMPLEMENT(name) if (ffuncs->destroy.name) \ ffuncs->destroy.name (ffuncs->user_data.name); @@ -310,17 +310,17 @@ hb_font_funcs_destroy (hb_font_funcs_t * * @data: * @destroy: * @replace: * * * * Return value: * - * Since: 1.0 + * Since: 0.9.2 **/ hb_bool_t hb_font_funcs_set_user_data (hb_font_funcs_t *ffuncs, hb_user_data_key_t *key, void * data, hb_destroy_func_t destroy, hb_bool_t replace) { @@ -331,33 +331,33 @@ hb_font_funcs_set_user_data (hb_font_fun * hb_font_funcs_get_user_data: (skip) * @ffuncs: font functions. * @key: * * * * Return value: (transfer none): * - * Since: 1.0 + * Since: 0.9.2 **/ void * hb_font_funcs_get_user_data (hb_font_funcs_t *ffuncs, hb_user_data_key_t *key) { return hb_object_get_user_data (ffuncs, key); } /** * hb_font_funcs_make_immutable: * @ffuncs: font functions. * * * - * Since: 1.0 + * Since: 0.9.2 **/ void hb_font_funcs_make_immutable (hb_font_funcs_t *ffuncs) { if (unlikely (hb_object_is_inert (ffuncs))) return; ffuncs->immutable = true; @@ -366,17 +366,17 @@ hb_font_funcs_make_immutable (hb_font_fu /** * hb_font_funcs_is_immutable: * @ffuncs: font functions. * * * * Return value: * - * Since: 1.0 + * Since: 0.9.2 **/ hb_bool_t hb_font_funcs_is_immutable (hb_font_funcs_t *ffuncs) { return ffuncs->immutable; } @@ -420,17 +420,17 @@ HB_FONT_FUNCS_IMPLEMENT_CALLBACKS * @unicode: * @variation_selector: * @glyph: (out): * * * * Return value: * - * Since: 1.0 + * Since: 0.9.2 **/ hb_bool_t hb_font_get_glyph (hb_font_t *font, hb_codepoint_t unicode, hb_codepoint_t variation_selector, hb_codepoint_t *glyph) { return font->get_glyph (unicode, variation_selector, glyph); } @@ -439,17 +439,17 @@ hb_font_get_glyph (hb_font_t *font, * hb_font_get_glyph_h_advance: * @font: a font. * @glyph: * * * * Return value: * - * Since: 1.0 + * Since: 0.9.2 **/ hb_position_t hb_font_get_glyph_h_advance (hb_font_t *font, hb_codepoint_t glyph) { return font->get_glyph_h_advance (glyph); } @@ -457,17 +457,17 @@ hb_font_get_glyph_h_advance (hb_font_t * * hb_font_get_glyph_v_advance: * @font: a font. * @glyph: * * * * Return value: * - * Since: 1.0 + * Since: 0.9.2 **/ hb_position_t hb_font_get_glyph_v_advance (hb_font_t *font, hb_codepoint_t glyph) { return font->get_glyph_v_advance (glyph); } @@ -477,17 +477,17 @@ hb_font_get_glyph_v_advance (hb_font_t * * @glyph: * @x: (out): * @y: (out): * * * * Return value: * - * Since: 1.0 + * Since: 0.9.2 **/ hb_bool_t hb_font_get_glyph_h_origin (hb_font_t *font, hb_codepoint_t glyph, hb_position_t *x, hb_position_t *y) { return font->get_glyph_h_origin (glyph, x, y); } @@ -498,17 +498,17 @@ hb_font_get_glyph_h_origin (hb_font_t *f * @glyph: * @x: (out): * @y: (out): * * * * Return value: * - * Since: 1.0 + * Since: 0.9.2 **/ hb_bool_t hb_font_get_glyph_v_origin (hb_font_t *font, hb_codepoint_t glyph, hb_position_t *x, hb_position_t *y) { return font->get_glyph_v_origin (glyph, x, y); } @@ -518,17 +518,17 @@ hb_font_get_glyph_v_origin (hb_font_t *f * @font: a font. * @left_glyph: * @right_glyph: * * * * Return value: * - * Since: 1.0 + * Since: 0.9.2 **/ hb_position_t hb_font_get_glyph_h_kerning (hb_font_t *font, hb_codepoint_t left_glyph, hb_codepoint_t right_glyph) { return font->get_glyph_h_kerning (left_glyph, right_glyph); } @@ -537,17 +537,17 @@ hb_font_get_glyph_h_kerning (hb_font_t * * @font: a font. * @top_glyph: * @bottom_glyph: * * * * Return value: * - * Since: 1.0 + * Since: 0.9.2 **/ hb_position_t hb_font_get_glyph_v_kerning (hb_font_t *font, hb_codepoint_t top_glyph, hb_codepoint_t bottom_glyph) { return font->get_glyph_v_kerning (top_glyph, bottom_glyph); } @@ -556,17 +556,17 @@ hb_font_get_glyph_v_kerning (hb_font_t * * @font: a font. * @glyph: * @extents: (out): * * * * Return value: * - * Since: 1.0 + * Since: 0.9.2 **/ hb_bool_t hb_font_get_glyph_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) { return font->get_glyph_extents (glyph, extents); } @@ -578,17 +578,17 @@ hb_font_get_glyph_extents (hb_font_t *fo * @point_index: * @x: (out): * @y: (out): * * * * Return value: * - * Since: 1.0 + * Since: 0.9.2 **/ hb_bool_t hb_font_get_glyph_contour_point (hb_font_t *font, hb_codepoint_t glyph, unsigned int point_index, hb_position_t *x, hb_position_t *y) { return font->get_glyph_contour_point (glyph, point_index, x, y); } @@ -643,17 +643,17 @@ hb_font_get_glyph_from_name (hb_font_t * * @font: a font. * @glyph: * @direction: * @x: (out): * @y: (out): * * * - * Since: 1.0 + * Since: 0.9.2 **/ void hb_font_get_glyph_advance_for_direction (hb_font_t *font, hb_codepoint_t glyph, hb_direction_t direction, hb_position_t *x, hb_position_t *y) { return font->get_glyph_advance_for_direction (glyph, direction, x, y); @@ -664,17 +664,17 @@ hb_font_get_glyph_advance_for_direction * @font: a font. * @glyph: * @direction: * @x: (out): * @y: (out): * * * - * Since: 1.0 + * Since: 0.9.2 **/ void hb_font_get_glyph_origin_for_direction (hb_font_t *font, hb_codepoint_t glyph, hb_direction_t direction, hb_position_t *x, hb_position_t *y) { return font->get_glyph_origin_for_direction (glyph, direction, x, y); @@ -685,17 +685,17 @@ hb_font_get_glyph_origin_for_direction ( * @font: a font. * @glyph: * @direction: * @x: (out): * @y: (out): * * * - * Since: 1.0 + * Since: 0.9.2 **/ void hb_font_add_glyph_origin_for_direction (hb_font_t *font, hb_codepoint_t glyph, hb_direction_t direction, hb_position_t *x, hb_position_t *y) { return font->add_glyph_origin_for_direction (glyph, direction, x, y); @@ -706,17 +706,17 @@ hb_font_add_glyph_origin_for_direction ( * @font: a font. * @glyph: * @direction: * @x: (out): * @y: (out): * * * - * Since: 1.0 + * Since: 0.9.2 **/ void hb_font_subtract_glyph_origin_for_direction (hb_font_t *font, hb_codepoint_t glyph, hb_direction_t direction, hb_position_t *x, hb_position_t *y) { return font->subtract_glyph_origin_for_direction (glyph, direction, x, y); @@ -728,17 +728,17 @@ hb_font_subtract_glyph_origin_for_direct * @first_glyph: * @second_glyph: * @direction: * @x: (out): * @y: (out): * * * - * Since: 1.0 + * Since: 0.9.2 **/ void hb_font_get_glyph_kerning_for_direction (hb_font_t *font, hb_codepoint_t first_glyph, hb_codepoint_t second_glyph, hb_direction_t direction, hb_position_t *x, hb_position_t *y) { return font->get_glyph_kerning_for_direction (first_glyph, second_glyph, direction, x, y); @@ -750,17 +750,17 @@ hb_font_get_glyph_kerning_for_direction * @glyph: * @direction: * @extents: (out): * * * * Return value: * - * Since: 1.0 + * Since: 0.9.2 **/ hb_bool_t hb_font_get_glyph_extents_for_origin (hb_font_t *font, hb_codepoint_t glyph, hb_direction_t direction, hb_glyph_extents_t *extents) { return font->get_glyph_extents_for_origin (glyph, direction, extents); @@ -774,17 +774,17 @@ hb_font_get_glyph_extents_for_origin (hb * @direction: * @x: (out): * @y: (out): * * * * Return value: * - * Since: 1.0 + * Since: 0.9.2 **/ hb_bool_t hb_font_get_glyph_contour_point_for_origin (hb_font_t *font, hb_codepoint_t glyph, unsigned int point_index, hb_direction_t direction, hb_position_t *x, hb_position_t *y) { return font->get_glyph_contour_point_for_origin (glyph, point_index, direction, x, y); @@ -840,57 +840,58 @@ hb_font_glyph_from_string (hb_font_t *fo /** * hb_font_create: (Xconstructor) * @face: a face. * * * * Return value: (transfer full): * - * Since: 1.0 + * Since: 0.9.2 **/ hb_font_t * hb_font_create (hb_face_t *face) { hb_font_t *font; if (unlikely (!face)) face = hb_face_get_empty (); if (!(font = hb_object_create<hb_font_t> ())) return hb_font_get_empty (); hb_face_make_immutable (face); font->face = hb_face_reference (face); font->klass = hb_font_funcs_get_empty (); + font->x_scale = font->y_scale = hb_face_get_upem (face); + return font; } /** * hb_font_create_sub_font: * @parent: parent font. * * * * Return value: (transfer full): * - * Since: 1.0 + * Since: 0.9.2 **/ hb_font_t * hb_font_create_sub_font (hb_font_t *parent) { if (unlikely (!parent)) parent = hb_font_get_empty (); hb_font_t *font = hb_font_create (parent->face); if (unlikely (hb_object_is_inert (font))) return font; - hb_font_make_immutable (parent); font->parent = hb_font_reference (parent); font->x_scale = parent->x_scale; font->y_scale = parent->y_scale; font->x_ppem = parent->x_ppem; font->y_ppem = parent->y_ppem; return font; @@ -898,17 +899,17 @@ hb_font_create_sub_font (hb_font_t *pare /** * hb_font_get_empty: * * * * Return value: (transfer full) * - * Since: 1.0 + * Since: 0.9.2 **/ hb_font_t * hb_font_get_empty (void) { static const hb_font_t _hb_font_nil = { HB_OBJECT_HEADER_STATIC, true, /* immutable */ @@ -939,31 +940,31 @@ hb_font_get_empty (void) /** * hb_font_reference: (skip) * @font: a font. * * * * Return value: (transfer full): * - * Since: 1.0 + * Since: 0.9.2 **/ hb_font_t * hb_font_reference (hb_font_t *font) { return hb_object_reference (font); } /** * hb_font_destroy: (skip) * @font: a font. * * * - * Since: 1.0 + * Since: 0.9.2 **/ void hb_font_destroy (hb_font_t *font) { if (!hb_object_destroy (font)) return; #define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_DESTROY(shaper, font); #include "hb-shaper-list.hh" @@ -986,17 +987,17 @@ hb_font_destroy (hb_font_t *font) * @data: * @destroy: * @replace: * * * * Return value: * - * Since: 1.0 + * Since: 0.9.2 **/ hb_bool_t hb_font_set_user_data (hb_font_t *font, hb_user_data_key_t *key, void * data, hb_destroy_func_t destroy, hb_bool_t replace) { @@ -1007,67 +1008,96 @@ hb_font_set_user_data (hb_font_t * hb_font_get_user_data: (skip) * @font: a font. * @key: * * * * Return value: (transfer none): * - * Since: 1.0 + * Since: 0.9.2 **/ void * hb_font_get_user_data (hb_font_t *font, hb_user_data_key_t *key) { return hb_object_get_user_data (font, key); } /** * hb_font_make_immutable: * @font: a font. * * * - * Since: 1.0 + * Since: 0.9.2 **/ void hb_font_make_immutable (hb_font_t *font) { if (unlikely (hb_object_is_inert (font))) return; + if (font->parent) + hb_font_make_immutable (font->parent); + font->immutable = true; } /** * hb_font_is_immutable: * @font: a font. * * * * Return value: * - * Since: 1.0 + * Since: 0.9.2 **/ hb_bool_t hb_font_is_immutable (hb_font_t *font) { return font->immutable; } /** + * hb_font_set_parent: + * @font: a font. + * @parent: new parent. + * + * Sets parent font of @font. + * + * Since: 1.0.5 + **/ +void +hb_font_set_parent (hb_font_t *font, + hb_font_t *parent) +{ + if (font->immutable) + return; + + if (!parent) + parent = hb_font_get_empty (); + + hb_font_t *old = font->parent; + + font->parent = hb_font_reference (parent); + + hb_font_destroy (old); +} + +/** * hb_font_get_parent: * @font: a font. * * * * Return value: (transfer none): * - * Since: 1.0 + * Since: 0.9.2 **/ hb_font_t * hb_font_get_parent (hb_font_t *font) { return font->parent; } /** @@ -1156,17 +1186,17 @@ hb_font_set_funcs_data (hb_font_t /** * hb_font_set_scale: * @font: a font. * @x_scale: * @y_scale: * * * - * Since: 1.0 + * Since: 0.9.2 **/ void hb_font_set_scale (hb_font_t *font, int x_scale, int y_scale) { if (font->immutable) return; @@ -1178,17 +1208,17 @@ hb_font_set_scale (hb_font_t *font, /** * hb_font_get_scale: * @font: a font. * @x_scale: (out): * @y_scale: (out): * * * - * Since: 1.0 + * Since: 0.9.2 **/ void hb_font_get_scale (hb_font_t *font, int *x_scale, int *y_scale) { if (x_scale) *x_scale = font->x_scale; if (y_scale) *y_scale = font->y_scale; @@ -1197,17 +1227,17 @@ hb_font_get_scale (hb_font_t *font, /** * hb_font_set_ppem: * @font: a font. * @x_ppem: * @y_ppem: * * * - * Since: 1.0 + * Since: 0.9.2 **/ void hb_font_set_ppem (hb_font_t *font, unsigned int x_ppem, unsigned int y_ppem) { if (font->immutable) return; @@ -1219,17 +1249,17 @@ hb_font_set_ppem (hb_font_t *font, /** * hb_font_get_ppem: * @font: a font. * @x_ppem: (out): * @y_ppem: (out): * * * - * Since: 1.0 + * Since: 0.9.2 **/ void hb_font_get_ppem (hb_font_t *font, unsigned int *x_ppem, unsigned int *y_ppem) { if (x_ppem) *x_ppem = font->x_ppem; if (y_ppem) *y_ppem = font->y_ppem;
--- a/gfx/harfbuzz/src/hb-font.h +++ b/gfx/harfbuzz/src/hb-font.h @@ -144,145 +144,145 @@ typedef hb_bool_t (*hb_font_get_glyph_fr * hb_font_funcs_set_glyph_func: * @ffuncs: font functions. * @func: (closure user_data) (destroy destroy) (scope notified): * @user_data: * @destroy: * * * - * Since: 1.0 + * Since: 0.9.2 **/ void hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs, hb_font_get_glyph_func_t func, void *user_data, hb_destroy_func_t destroy); /** * hb_font_funcs_set_glyph_h_advance_func: * @ffuncs: font functions. * @func: (closure user_data) (destroy destroy) (scope notified): * @user_data: * @destroy: * * * - * Since: 1.0 + * Since: 0.9.2 **/ void hb_font_funcs_set_glyph_h_advance_func (hb_font_funcs_t *ffuncs, hb_font_get_glyph_h_advance_func_t func, void *user_data, hb_destroy_func_t destroy); /** * hb_font_funcs_set_glyph_v_advance_func: * @ffuncs: font functions. * @func: (closure user_data) (destroy destroy) (scope notified): * @user_data: * @destroy: * * * - * Since: 1.0 + * Since: 0.9.2 **/ void hb_font_funcs_set_glyph_v_advance_func (hb_font_funcs_t *ffuncs, hb_font_get_glyph_v_advance_func_t func, void *user_data, hb_destroy_func_t destroy); /** * hb_font_funcs_set_glyph_h_origin_func: * @ffuncs: font functions. * @func: (closure user_data) (destroy destroy) (scope notified): * @user_data: * @destroy: * * * - * Since: 1.0 + * Since: 0.9.2 **/ void hb_font_funcs_set_glyph_h_origin_func (hb_font_funcs_t *ffuncs, hb_font_get_glyph_h_origin_func_t func, void *user_data, hb_destroy_func_t destroy); /** * hb_font_funcs_set_glyph_v_origin_func: * @ffuncs: font functions. * @func: (closure user_data) (destroy destroy) (scope notified): * @user_data: * @destroy: * * * - * Since: 1.0 + * Since: 0.9.2 **/ void hb_font_funcs_set_glyph_v_origin_func (hb_font_funcs_t *ffuncs, hb_font_get_glyph_v_origin_func_t func, void *user_data, hb_destroy_func_t destroy); /** * hb_font_funcs_set_glyph_h_kerning_func: * @ffuncs: font functions. * @func: (closure user_data) (destroy destroy) (scope notified): * @user_data: * @destroy: * * * - * Since: 1.0 + * Since: 0.9.2 **/ void hb_font_funcs_set_glyph_h_kerning_func (hb_font_funcs_t *ffuncs, hb_font_get_glyph_h_kerning_func_t func, void *user_data, hb_destroy_func_t destroy); /** * hb_font_funcs_set_glyph_v_kerning_func: * @ffuncs: font functions. * @func: (closure user_data) (destroy destroy) (scope notified): * @user_data: * @destroy: * * * - * Since: 1.0 + * Since: 0.9.2 **/ void hb_font_funcs_set_glyph_v_kerning_func (hb_font_funcs_t *ffuncs, hb_font_get_glyph_v_kerning_func_t func, void *user_data, hb_destroy_func_t destroy); /** * hb_font_funcs_set_glyph_extents_func: * @ffuncs: font functions. * @func: (closure user_data) (destroy destroy) (scope notified): * @user_data: * @destroy: * * * - * Since: 1.0 + * Since: 0.9.2 **/ void hb_font_funcs_set_glyph_extents_func (hb_font_funcs_t *ffuncs, hb_font_get_glyph_extents_func_t func, void *user_data, hb_destroy_func_t destroy); /** * hb_font_funcs_set_glyph_contour_point_func: * @ffuncs: font functions. * @func: (closure user_data) (destroy destroy) (scope notified): * @user_data: * @destroy: * * * - * Since: 1.0 + * Since: 0.9.2 **/ void hb_font_funcs_set_glyph_contour_point_func (hb_font_funcs_t *ffuncs, hb_font_get_glyph_contour_point_func_t func, void *user_data, hb_destroy_func_t destroy); /** * hb_font_funcs_set_glyph_name_func: @@ -454,16 +454,20 @@ hb_font_get_user_data (hb_font_t hb_user_data_key_t *key); void hb_font_make_immutable (hb_font_t *font); hb_bool_t hb_font_is_immutable (hb_font_t *font); +void +hb_font_set_parent (hb_font_t *font, + hb_font_t *parent); + hb_font_t * hb_font_get_parent (hb_font_t *font); hb_face_t * hb_font_get_face (hb_font_t *font); void
--- a/gfx/harfbuzz/src/hb-ft.cc +++ b/gfx/harfbuzz/src/hb-ft.cc @@ -1,11 +1,12 @@ /* * Copyright © 2009 Red Hat, Inc. * Copyright © 2009 Keith Stribley + * Copyright © 2015 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * * Permission is hereby granted, without written agreement and without * license or royalty fees, to use, copy, modify, and distribute this * software and its documentation for any purpose, provided that the * above copyright notice and the following two paragraphs appear in * all copies of this software. @@ -18,16 +19,17 @@ * * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. * * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod */ #include "hb-private.hh" #include "hb-ft.h" #include "hb-font-private.hh" @@ -41,90 +43,174 @@ #endif /* TODO: * * In general, this file does a fine job of what it's supposed to do. * There are, however, things that need more work: * - * - We don't handle any load_flags. That definitely has API implications. :( - * I believe hb_ft_font_create() should take load_flags input. - * In particular, FT_Get_Advance() without the NO_HINTING flag seems to be - * buggy. + * - I remember seeing FT_Get_Advance() without the NO_HINTING flag to be buggy. + * Have not investigated. * - * FreeType works in 26.6 mode. Clients can decide to use that mode, and everything + * - FreeType works in 26.6 mode. Clients can decide to use that mode, and everything * would work fine. However, we also abuse this API for performing in font-space, * but don't pass the correct flags to FreeType. We just abuse the no-hinting mode * for that, such that no rounding etc happens. As such, we don't set ppem, and - * pass NO_HINTING around. This seems to work best, until we go ahead and add a full - * load_flags API. + * pass NO_HINTING as load_flags. Would be much better to use NO_SCALE, and scale + * ourselves, like we do in uniscribe, etc. * * - We don't handle / allow for emboldening / obliqueing. * * - In the future, we should add constructors to create fonts in font space? * * - FT_Load_Glyph() is exteremely costly. Do something about it? */ +struct hb_ft_font_t +{ + FT_Face ft_face; + int load_flags; + bool unref; /* Whether to destroy ft_face when done. */ +}; + +static hb_ft_font_t * +_hb_ft_font_create (FT_Face ft_face, bool unref) +{ + hb_ft_font_t *ft_font = (hb_ft_font_t *) calloc (1, sizeof (hb_ft_font_t)); + + if (unlikely (!ft_font)) + return NULL; + + ft_font->ft_face = ft_face; + ft_font->unref = unref; + + ft_font->load_flags = FT_LOAD_DEFAULT; + + return ft_font; +} + +static void +_hb_ft_font_destroy (hb_ft_font_t *ft_font) +{ + if (ft_font->unref) + FT_Done_Face (ft_font->ft_face); + + free (ft_font); +} + +/** + * hb_ft_font_set_load_flags: + * @font: + * @load_flags: + * + * + * + * Since: 1.0.5 + **/ +void +hb_ft_font_set_load_flags (hb_font_t *font, int load_flags) +{ + if (font->immutable) + return; + + if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy) + return; + + hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data; + + ft_font->load_flags = load_flags; +} + +/** + * hb_ft_font_get_load_flags: + * @font: + * + * + * + * Return value: + * Since: 1.0.5 + **/ +int +hb_ft_font_get_load_flags (hb_font_t *font) +{ + if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy) + return 0; + + const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data; + + return ft_font->load_flags; +} + +FT_Face +hb_ft_font_get_face (hb_font_t *font) +{ + if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy) + return NULL; + + const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data; + + return ft_font->ft_face; +} + + + static hb_bool_t hb_ft_get_glyph (hb_font_t *font HB_UNUSED, void *font_data, hb_codepoint_t unicode, hb_codepoint_t variation_selector, hb_codepoint_t *glyph, void *user_data HB_UNUSED) { + const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; unsigned int g; - FT_Face ft_face = (FT_Face) font_data; if (likely (!variation_selector)) - g = FT_Get_Char_Index (ft_face, unicode); + g = FT_Get_Char_Index (ft_font->ft_face, unicode); else - g = FT_Face_GetCharVariantIndex (ft_face, unicode, variation_selector); + g = FT_Face_GetCharVariantIndex (ft_font->ft_face, unicode, variation_selector); if (unlikely (!g)) return false; *glyph = g; return true; } static hb_position_t hb_ft_get_glyph_h_advance (hb_font_t *font HB_UNUSED, void *font_data, hb_codepoint_t glyph, void *user_data HB_UNUSED) { - FT_Face ft_face = (FT_Face) font_data; - int load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING; + const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; FT_Fixed v; - if (unlikely (FT_Get_Advance (ft_face, glyph, load_flags, &v))) + if (unlikely (FT_Get_Advance (ft_font->ft_face, glyph, ft_font->load_flags, &v))) return 0; if (font->x_scale < 0) v = -v; return (v + (1<<9)) >> 10; } static hb_position_t hb_ft_get_glyph_v_advance (hb_font_t *font HB_UNUSED, void *font_data, hb_codepoint_t glyph, void *user_data HB_UNUSED) { - FT_Face ft_face = (FT_Face) font_data; - int load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING | FT_LOAD_VERTICAL_LAYOUT; + const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; FT_Fixed v; - if (unlikely (FT_Get_Advance (ft_face, glyph, load_flags, &v))) + if (unlikely (FT_Get_Advance (ft_font->ft_face, glyph, ft_font->load_flags | FT_LOAD_VERTICAL_LAYOUT, &v))) return 0; if (font->y_scale < 0) v = -v; /* Note: FreeType's vertical metrics grows downward while other FreeType coordinates * have a Y growing upward. Hence the extra negation. */ return (-v + (1<<9)) >> 10; @@ -145,20 +231,20 @@ hb_ft_get_glyph_h_origin (hb_font_t *fon static hb_bool_t hb_ft_get_glyph_v_origin (hb_font_t *font HB_UNUSED, void *font_data, hb_codepoint_t glyph, hb_position_t *x, hb_position_t *y, void *user_data HB_UNUSED) { - FT_Face ft_face = (FT_Face) font_data; - int load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING; + const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + FT_Face ft_face = ft_font->ft_face; - if (unlikely (FT_Load_Glyph (ft_face, glyph, load_flags))) + if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags))) return false; /* Note: FreeType's vertical metrics grows downward while other FreeType coordinates * have a Y growing upward. Hence the extra negation. */ *x = ft_face->glyph->metrics.horiBearingX - ft_face->glyph->metrics.vertBearingX; *y = ft_face->glyph->metrics.horiBearingY - (-ft_face->glyph->metrics.vertBearingY); if (font->x_scale < 0) @@ -171,21 +257,21 @@ hb_ft_get_glyph_v_origin (hb_font_t *fon static hb_position_t hb_ft_get_glyph_h_kerning (hb_font_t *font, void *font_data, hb_codepoint_t left_glyph, hb_codepoint_t right_glyph, void *user_data HB_UNUSED) { - FT_Face ft_face = (FT_Face) font_data; + const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; FT_Vector kerningv; FT_Kerning_Mode mode = font->x_ppem ? FT_KERNING_DEFAULT : FT_KERNING_UNFITTED; - if (FT_Get_Kerning (ft_face, left_glyph, right_glyph, mode, &kerningv)) + if (FT_Get_Kerning (ft_font->ft_face, left_glyph, right_glyph, mode, &kerningv)) return 0; return kerningv.x; } static hb_position_t hb_ft_get_glyph_v_kerning (hb_font_t *font HB_UNUSED, void *font_data HB_UNUSED, @@ -199,20 +285,20 @@ hb_ft_get_glyph_v_kerning (hb_font_t *fo static hb_bool_t hb_ft_get_glyph_extents (hb_font_t *font HB_UNUSED, void *font_data, hb_codepoint_t glyph, hb_glyph_extents_t *extents, void *user_data HB_UNUSED) { - FT_Face ft_face = (FT_Face) font_data; - int load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING; + const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + FT_Face ft_face = ft_font->ft_face; - if (unlikely (FT_Load_Glyph (ft_face, glyph, load_flags))) + if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags))) return false; extents->x_bearing = ft_face->glyph->metrics.horiBearingX; extents->y_bearing = ft_face->glyph->metrics.horiBearingY; extents->width = ft_face->glyph->metrics.width; extents->height = -ft_face->glyph->metrics.height; return true; } @@ -221,20 +307,20 @@ static hb_bool_t hb_ft_get_glyph_contour_point (hb_font_t *font HB_UNUSED, void *font_data, hb_codepoint_t glyph, unsigned int point_index, hb_position_t *x, hb_position_t *y, void *user_data HB_UNUSED) { - FT_Face ft_face = (FT_Face) font_data; - int load_flags = FT_LOAD_DEFAULT; + const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + FT_Face ft_face = ft_font->ft_face; - if (unlikely (FT_Load_Glyph (ft_face, glyph, load_flags))) + if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags))) return false; if (unlikely (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)) return false; if (unlikely (point_index >= (unsigned int) ft_face->glyph->outline.n_points)) return false; @@ -246,33 +332,34 @@ hb_ft_get_glyph_contour_point (hb_font_t static hb_bool_t hb_ft_get_glyph_name (hb_font_t *font HB_UNUSED, void *font_data, hb_codepoint_t glyph, char *name, unsigned int size, void *user_data HB_UNUSED) { - FT_Face ft_face = (FT_Face) font_data; + const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; - hb_bool_t ret = !FT_Get_Glyph_Name (ft_face, glyph, name, size); + hb_bool_t ret = !FT_Get_Glyph_Name (ft_font->ft_face, glyph, name, size); if (ret && (size && !*name)) ret = false; return ret; } static hb_bool_t hb_ft_get_glyph_from_name (hb_font_t *font HB_UNUSED, void *font_data, const char *name, int len, /* -1 means nul-terminated */ hb_codepoint_t *glyph, void *user_data HB_UNUSED) { - FT_Face ft_face = (FT_Face) font_data; + const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + FT_Face ft_face = ft_font->ft_face; if (len < 0) *glyph = FT_Get_Name_Index (ft_face, (FT_String *) name); else { /* Make a nul-terminated version. */ char buf[128]; len = MIN (len, (int) sizeof (buf) - 1); strncpy (buf, name, len); @@ -288,32 +375,35 @@ hb_ft_get_glyph_from_name (hb_font_t *fo len < 0 ? !strcmp (buf, name) : !strncmp (buf, name, len)) return true; } return *glyph != 0; } -static hb_font_funcs_t * -_hb_ft_get_font_funcs (void) +static void +_hb_ft_font_set_funcs (hb_font_t *font, FT_Face ft_face, bool unref) { static const hb_font_funcs_t ft_ffuncs = { HB_OBJECT_HEADER_STATIC, true, /* immutable */ { #define HB_FONT_FUNC_IMPLEMENT(name) hb_ft_get_##name, HB_FONT_FUNCS_IMPLEMENT_CALLBACKS #undef HB_FONT_FUNC_IMPLEMENT } }; - return const_cast<hb_font_funcs_t *> (&ft_ffuncs); + hb_font_set_funcs (font, + const_cast<hb_font_funcs_t *> (&ft_ffuncs), + _hb_ft_font_create (ft_face, unref), + (hb_destroy_func_t) _hb_ft_font_destroy); } static hb_blob_t * reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data) { FT_Face ft_face = (FT_Face) user_data; FT_Byte *buffer; @@ -342,17 +432,17 @@ reference_table (hb_face_t *face HB_UNU /** * hb_ft_face_create: * @ft_face: (destroy destroy) (scope notified): * @destroy: * * * * Return value: (transfer full): - * Since: 1.0 + * Since: 0.9.2 **/ hb_face_t * hb_ft_face_create (FT_Face ft_face, hb_destroy_func_t destroy) { hb_face_t *face; if (ft_face->stream->read == NULL) { @@ -398,62 +488,55 @@ hb_ft_face_finalize (FT_Face ft_face) /** * hb_ft_face_create_cached: * @ft_face: * * * * Return value: (transfer full): - * Since: 1.0 + * Since: 0.9.2 **/ hb_face_t * hb_ft_face_create_cached (FT_Face ft_face) { if (unlikely (!ft_face->generic.data || ft_face->generic.finalizer != (FT_Generic_Finalizer) hb_ft_face_finalize)) { if (ft_face->generic.finalizer) ft_face->generic.finalizer (ft_face); ft_face->generic.data = hb_ft_face_create (ft_face, NULL); ft_face->generic.finalizer = (FT_Generic_Finalizer) hb_ft_face_finalize; } return hb_face_reference ((hb_face_t *) ft_face->generic.data); } -static void -_do_nothing (void) -{ -} - /** * hb_ft_font_create: * @ft_face: (destroy destroy) (scope notified): * @destroy: * * * * Return value: (transfer full): - * Since: 1.0 + * Since: 0.9.2 **/ hb_font_t * hb_ft_font_create (FT_Face ft_face, hb_destroy_func_t destroy) { hb_font_t *font; hb_face_t *face; face = hb_ft_face_create (ft_face, destroy); font = hb_font_create (face); hb_face_destroy (face); - hb_font_set_funcs (font, - _hb_ft_get_font_funcs (), - ft_face, (hb_destroy_func_t) _do_nothing); + _hb_ft_font_set_funcs (font, ft_face, false); hb_font_set_scale (font, (int) (((uint64_t) ft_face->size->metrics.x_scale * (uint64_t) ft_face->units_per_EM + (1<<15)) >> 16), (int) (((uint64_t) ft_face->size->metrics.y_scale * (uint64_t) ft_face->units_per_EM + (1<<15)) >> 16)); #if 0 /* hb-ft works in no-hinting model */ hb_font_set_ppem (font, ft_face->size->metrics.x_ppem, ft_face->size->metrics.y_ppem); #endif @@ -557,23 +640,11 @@ hb_ft_font_set_funcs (hb_font_t *font) FT_Matrix matrix = { font->x_scale < 0 ? -1 : +1, 0, 0, font->y_scale < 0 ? -1 : +1}; FT_Set_Transform (ft_face, &matrix, NULL); } ft_face->generic.data = blob; ft_face->generic.finalizer = (FT_Generic_Finalizer) _release_blob; - hb_font_set_funcs (font, - _hb_ft_get_font_funcs (), - ft_face, - (hb_destroy_func_t) FT_Done_Face); + _hb_ft_font_set_funcs (font, ft_face, true); + hb_ft_font_set_load_flags (font, FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING); } - -FT_Face -hb_ft_font_get_face (hb_font_t *font) -{ - if (font->destroy == (hb_destroy_func_t) FT_Done_Face || - font->destroy == (hb_destroy_func_t) _do_nothing) - return (FT_Face) font->user_data; - - return NULL; -}
--- a/gfx/harfbuzz/src/hb-ft.h +++ b/gfx/harfbuzz/src/hb-ft.h @@ -1,10 +1,11 @@ /* * Copyright © 2009 Red Hat, Inc. + * Copyright © 2015 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * * Permission is hereby granted, without written agreement and without * license or royalty fees, to use, copy, modify, and distribute this * software and its documentation for any purpose, provided that the * above copyright notice and the following two paragraphs appear in * all copies of this software. @@ -17,16 +18,17 @@ * * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. * * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod */ #ifndef HB_FT_H #define HB_FT_H #include "hb.h" #include <ft2build.h> @@ -100,20 +102,25 @@ hb_font_t * hb_ft_font_create (FT_Face ft_face, hb_destroy_func_t destroy); /* See notes on hb_ft_face_create_referenced() re lifecycle-management * issues. */ hb_font_t * hb_ft_font_create_referenced (FT_Face ft_face); +FT_Face +hb_ft_font_get_face (hb_font_t *font); + +void +hb_ft_font_set_load_flags (hb_font_t *font, int load_flags); + +int +hb_ft_font_get_load_flags (hb_font_t *font); /* Makes an hb_font_t use FreeType internally to implement font functions. */ void hb_ft_font_set_funcs (hb_font_t *font); -FT_Face -hb_ft_font_get_face (hb_font_t *font); - HB_END_DECLS #endif /* HB_FT_H */
--- a/gfx/harfbuzz/src/hb-graphite2.cc +++ b/gfx/harfbuzz/src/hb-graphite2.cc @@ -133,16 +133,19 @@ void free (old); } gr_face_destroy (data->grface); free (data); } +/* + * Since: 0.9.10 + */ gr_face * hb_graphite2_face_get_gr_face (hb_face_t *face) { if (unlikely (!hb_graphite2_shaper_face_data_ensure (face))) return NULL; return HB_SHAPER_DATA_GET (face)->grface; } @@ -167,16 +170,19 @@ hb_graphite2_shaper_font_data_t * } void _hb_graphite2_shaper_font_data_destroy (hb_graphite2_shaper_font_data_t *data) { gr_font_destroy (data); } +/* + * Since: 0.9.10 + */ gr_font * hb_graphite2_font_get_gr_font (hb_font_t *font) { if (unlikely (!hb_graphite2_shaper_font_data_ensure (font))) return NULL; return HB_SHAPER_DATA_GET (font); }
--- a/gfx/harfbuzz/src/hb-open-file-private.hh +++ b/gfx/harfbuzz/src/hb-open-file-private.hh @@ -51,17 +51,17 @@ struct OffsetTable; struct TTCHeader; typedef struct TableRecord { inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return TRACE_RETURN (c->check_struct (this)); + return_trace (c->check_struct (this)); } Tag tag; /* 4-byte identifier. */ CheckSum checkSum; /* CheckSum for this table. */ ULONG offset; /* Offset from beginning of TrueType font * file. */ ULONG length; /* Length of this table. */ public: @@ -101,17 +101,17 @@ typedef struct OffsetTable find_table_index (tag, &table_index); return get_table (table_index); } public: inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return TRACE_RETURN (c->check_struct (this) && c->check_array (tables, TableRecord::static_size, numTables)); + return_trace (c->check_struct (this) && c->check_array (tables, TableRecord::static_size, numTables)); } protected: Tag sfnt_version; /* '\0\001\0\00' if TrueType / 'OTTO' if CFF */ USHORT numTables; /* Number of tables. */ USHORT searchRangeZ; /* (Maximum power of 2 <= numTables) x 16 */ USHORT entrySelectorZ; /* Log2(maximum power of 2 <= numTables). */ USHORT rangeShiftZ; /* NumTables x 16-searchRange. */ @@ -130,17 +130,17 @@ struct TTCHeaderVersion1 friend struct TTCHeader; inline unsigned int get_face_count (void) const { return table.len; } inline const OpenTypeFontFace& get_face (unsigned int i) const { return this+table[i]; } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return TRACE_RETURN (table.sanitize (c, this)); + return_trace (table.sanitize (c, this)); } protected: Tag ttcTag; /* TrueType Collection ID string: 'ttcf' */ FixedVersion version; /* Version of the TTC Header (1.0), * 0x00010000u */ ArrayOf<OffsetTo<OffsetTable, ULONG>, ULONG> table; /* Array of offsets to the OffsetTable for each font @@ -170,21 +170,21 @@ struct TTCHeader case 1: return u.version1.get_face (i); default:return Null(OpenTypeFontFace); } } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - if (unlikely (!u.header.version.sanitize (c))) return TRACE_RETURN (false); + if (unlikely (!u.header.version.sanitize (c))) return_trace (false); switch (u.header.version.major) { case 2: /* version 2 is compatible with version 1 */ - case 1: return TRACE_RETURN (u.version1.sanitize (c)); - default:return TRACE_RETURN (true); + case 1: return_trace (u.version1.sanitize (c)); + default:return_trace (true); } } protected: union { struct { Tag ttcTag; /* TrueType Collection ID string: 'ttcf' */ FixedVersion version; /* Version of the TTC Header (1.0 or 2.0), @@ -235,24 +235,24 @@ struct OpenTypeFontFile case TTCTag: return u.ttcHeader.get_face (i); default: return Null(OpenTypeFontFace); } } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - if (unlikely (!u.tag.sanitize (c))) return TRACE_RETURN (false); + if (unlikely (!u.tag.sanitize (c))) return_trace (false); switch (u.tag) { case CFFTag: /* All the non-collection tags */ case TrueTag: case Typ1Tag: - case TrueTypeTag: return TRACE_RETURN (u.fontFace.sanitize (c)); - case TTCTag: return TRACE_RETURN (u.ttcHeader.sanitize (c)); - default: return TRACE_RETURN (true); + case TrueTypeTag: return_trace (u.fontFace.sanitize (c)); + case TTCTag: return_trace (u.ttcHeader.sanitize (c)); + default: return_trace (true); } } protected: union { Tag tag; /* 4-byte identifier. */ OpenTypeFontFace fontFace; TTCHeader ttcHeader;
--- a/gfx/harfbuzz/src/hb-open-type-private.hh +++ b/gfx/harfbuzz/src/hb-open-type-private.hh @@ -149,16 +149,30 @@ template <> \ return *CastP<Type> (_Null##Type); \ } /* The following line really exists such that we end in a place needing semicolon */ \ ASSERT_STATIC (Type::min_size + 1 <= sizeof (_Null##Type)) /* Accessor macro. */ #define Null(Type) Null<Type>() +/* + * Dispatch + */ + +template <typename Context, typename Return, unsigned int MaxDebugDepth> +struct hb_dispatch_context_t +{ + static const unsigned int max_debug_depth = MaxDebugDepth; + typedef Return return_t; + template <typename T, typename F> + inline bool may_dispatch (const T *obj, const F *format) { return true; } + static return_t no_dispatch_return_value (void) { return Context::default_return_value (); } +}; + /* * Sanitize */ #ifndef HB_DEBUG_SANITIZE #define HB_DEBUG_SANITIZE (HB_DEBUG+0) #endif @@ -169,27 +183,33 @@ ASSERT_STATIC (Type::min_size + 1 <= siz (&c->debug_depth, c->get_name (), this, HB_FUNC, \ ""); /* This limits sanitizing time on really broken fonts. */ #ifndef HB_SANITIZE_MAX_EDITS #define HB_SANITIZE_MAX_EDITS 100 #endif -struct hb_sanitize_context_t +struct hb_sanitize_context_t : + hb_dispatch_context_t<hb_sanitize_context_t, bool, HB_DEBUG_SANITIZE> { + inline hb_sanitize_context_t (void) : + debug_depth (0), + start (NULL), end (NULL), + writable (false), edit_count (0), + blob (NULL) {} + inline const char *get_name (void) { return "SANITIZE"; } - static const unsigned int max_debug_depth = HB_DEBUG_SANITIZE; - typedef bool return_t; template <typename T, typename F> inline bool may_dispatch (const T *obj, const F *format) { return format->sanitize (this); } template <typename T> inline return_t dispatch (const T &obj) { return obj.sanitize (this); } static return_t default_return_value (void) { return true; } + static return_t no_dispatch_return_value (void) { return false; } bool stop_sublookup_iteration (const return_t r) const { return !r; } inline void init (hb_blob_t *b) { this->blob = hb_blob_reference (b); this->writable = false; } @@ -290,17 +310,17 @@ struct hb_sanitize_context_t /* Template to sanitize an object. */ template <typename Type> struct Sanitizer { static hb_blob_t *sanitize (hb_blob_t *blob) { - hb_sanitize_context_t c[1] = {{0, NULL, NULL, false, 0, NULL}}; + hb_sanitize_context_t c[1]; bool sane; /* TODO is_sane() stuff */ c->init (blob); retry: DEBUG_MSG_FUNC (SANITIZE, c->start, "start"); @@ -619,17 +639,17 @@ struct IntType if (sizeof (Type) < sizeof (int)) return (int) a - (int) b; else return a < b ? -1 : a == b ? 0 : +1; } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return TRACE_RETURN (likely (c->check_struct (this))); + return_trace (likely (c->check_struct (this))); } protected: BEInt<Type, Size> v; public: DEFINE_SIZE_STATIC (Size); }; typedef IntType<uint8_t , 1> BYTE; /* 8-bit unsigned integer. */ @@ -647,17 +667,17 @@ typedef USHORT UFWORD; /* Date represented in number of seconds since 12:00 midnight, January 1, * 1904. The value is represented as a signed 64-bit integer. */ struct LONGDATETIME { inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return TRACE_RETURN (likely (c->check_struct (this))); + return_trace (likely (c->check_struct (this))); } protected: LONG major; ULONG minor; public: DEFINE_SIZE_STATIC (8); }; @@ -724,17 +744,17 @@ struct CheckSum : ULONG struct FixedVersion { inline uint32_t to_int (void) const { return (major << 16) + minor; } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return TRACE_RETURN (c->check_struct (this)); + return_trace (c->check_struct (this)); } USHORT major; USHORT minor; public: DEFINE_SIZE_STATIC (4); }; @@ -760,31 +780,31 @@ struct OffsetTo : Offset<OffsetType> Type *t = c->start_embed<Type> (); this->set ((char *) t - (char *) base); /* TODO(serialize) Overflow? */ return *t; } inline bool sanitize (hb_sanitize_context_t *c, const void *base) const { TRACE_SANITIZE (this); - if (unlikely (!c->check_struct (this))) return TRACE_RETURN (false); + if (unlikely (!c->check_struct (this))) return_trace (false); unsigned int offset = *this; - if (unlikely (!offset)) return TRACE_RETURN (true); + if (unlikely (!offset)) return_trace (true); const Type &obj = StructAtOffset<Type> (base, offset); - return TRACE_RETURN (likely (obj.sanitize (c)) || neuter (c)); + return_trace (likely (obj.sanitize (c)) || neuter (c)); } template <typename T> inline bool sanitize (hb_sanitize_context_t *c, const void *base, T user_data) const { TRACE_SANITIZE (this); - if (unlikely (!c->check_struct (this))) return TRACE_RETURN (false); + if (unlikely (!c->check_struct (this))) return_trace (false); unsigned int offset = *this; - if (unlikely (!offset)) return TRACE_RETURN (true); + if (unlikely (!offset)) return_trace (true); const Type &obj = StructAtOffset<Type> (base, offset); - return TRACE_RETURN (likely (obj.sanitize (c, user_data)) || neuter (c)); + return_trace (likely (obj.sanitize (c, user_data)) || neuter (c)); } /* Set the offset to Null */ inline bool neuter (hb_sanitize_context_t *c) const { return c->try_set (this, 0); } DEFINE_SIZE_STATIC (sizeof(OffsetType)); }; @@ -825,87 +845,87 @@ struct ArrayOf } inline unsigned int get_size (void) const { return len.static_size + len * Type::static_size; } inline bool serialize (hb_serialize_context_t *c, unsigned int items_len) { TRACE_SERIALIZE (this); - if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false); + if (unlikely (!c->extend_min (*this))) return_trace (false); len.set (items_len); /* TODO(serialize) Overflow? */ - if (unlikely (!c->extend (*this))) return TRACE_RETURN (false); - return TRACE_RETURN (true); + if (unlikely (!c->extend (*this))) return_trace (false); + return_trace (true); } inline bool serialize (hb_serialize_context_t *c, Supplier<Type> &items, unsigned int items_len) { TRACE_SERIALIZE (this); - if (unlikely (!serialize (c, items_len))) return TRACE_RETURN (false); + if (unlikely (!serialize (c, items_len))) return_trace (false); for (unsigned int i = 0; i < items_len; i++) array[i] = items[i]; items.advance (items_len); - return TRACE_RETURN (true); + return_trace (true); } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false); + if (unlikely (!sanitize_shallow (c))) return_trace (false); /* Note: for structs that do not reference other structs, * we do not need to call their sanitize() as we already did * a bound check on the aggregate array size. We just include * a small unreachable expression to make sure the structs * pointed to do have a simple sanitize(), ie. they do not * reference other structs via offsets. */ (void) (false && array[0].sanitize (c)); - return TRACE_RETURN (true); + return_trace (true); } inline bool sanitize (hb_sanitize_context_t *c, const void *base) const { TRACE_SANITIZE (this); - if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false); + if (unlikely (!sanitize_shallow (c))) return_trace (false); unsigned int count = len; for (unsigned int i = 0; i < count; i++) if (unlikely (!array[i].sanitize (c, base))) - return TRACE_RETURN (false); - return TRACE_RETURN (true); + return_trace (false); + return_trace (true); } template <typename T> inline bool sanitize (hb_sanitize_context_t *c, const void *base, T user_data) const { TRACE_SANITIZE (this); - if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false); + if (unlikely (!sanitize_shallow (c))) return_trace (false); unsigned int count = len; for (unsigned int i = 0; i < count; i++) if (unlikely (!array[i].sanitize (c, base, user_data))) - return TRACE_RETURN (false); - return TRACE_RETURN (true); + return_trace (false); + return_trace (true); } template <typename SearchType> inline int lsearch (const SearchType &x) const { unsigned int count = len; for (unsigned int i = 0; i < count; i++) if (!this->array[i].cmp (x)) return i; return -1; } private: inline bool sanitize_shallow (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return TRACE_RETURN (c->check_struct (this) && c->check_array (this, Type::static_size, len)); + return_trace (c->check_struct (this) && c->check_array (array, Type::static_size, len)); } public: LenType len; Type array[VAR]; public: DEFINE_SIZE_ARRAY (sizeof (LenType), array); }; @@ -922,23 +942,23 @@ struct OffsetListOf : OffsetArrayOf<Type { if (unlikely (i >= this->len)) return Null(Type); return this+this->array[i]; } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return TRACE_RETURN (OffsetArrayOf<Type>::sanitize (c, this)); + return_trace (OffsetArrayOf<Type>::sanitize (c, this)); } template <typename T> inline bool sanitize (hb_sanitize_context_t *c, T user_data) const { TRACE_SANITIZE (this); - return TRACE_RETURN (OffsetArrayOf<Type>::sanitize (c, this, user_data)); + return_trace (OffsetArrayOf<Type>::sanitize (c, this, user_data)); } }; /* An array starting at second element. */ template <typename Type, typename LenType=USHORT> struct HeadlessArrayOf { @@ -950,47 +970,47 @@ struct HeadlessArrayOf inline unsigned int get_size (void) const { return len.static_size + (len ? len - 1 : 0) * Type::static_size; } inline bool serialize (hb_serialize_context_t *c, Supplier<Type> &items, unsigned int items_len) { TRACE_SERIALIZE (this); - if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false); + if (unlikely (!c->extend_min (*this))) return_trace (false); len.set (items_len); /* TODO(serialize) Overflow? */ - if (unlikely (!items_len)) return TRACE_RETURN (true); - if (unlikely (!c->extend (*this))) return TRACE_RETURN (false); + if (unlikely (!items_len)) return_trace (true); + if (unlikely (!c->extend (*this))) return_trace (false); for (unsigned int i = 0; i < items_len - 1; i++) array[i] = items[i]; items.advance (items_len - 1); - return TRACE_RETURN (true); + return_trace (true); } inline bool sanitize_shallow (hb_sanitize_context_t *c) const { return c->check_struct (this) && c->check_array (this, Type::static_size, len); } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false); + if (unlikely (!sanitize_shallow (c))) return_trace (false); /* Note: for structs that do not reference other structs, * we do not need to call their sanitize() as we already did * a bound check on the aggregate array size. We just include * a small unreachable expression to make sure the structs * pointed to do have a simple sanitize(), ie. they do not * reference other structs via offsets. */ (void) (false && array[0].sanitize (c)); - return TRACE_RETURN (true); + return_trace (true); } LenType len; Type array[VAR]; public: DEFINE_SIZE_ARRAY (sizeof (LenType), array); };
--- a/gfx/harfbuzz/src/hb-ot-cmap-table.hh +++ b/gfx/harfbuzz/src/hb-ot-cmap-table.hh @@ -49,17 +49,17 @@ struct CmapSubtableFormat0 return false; *glyph = gid; return true; } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return TRACE_RETURN (c->check_struct (this)); + return_trace (c->check_struct (this)); } protected: USHORT format; /* Format number is set to 0. */ USHORT lengthZ; /* Byte length of this subtable. */ USHORT languageZ; /* Ignore. */ BYTE glyphIdArray[256];/* An array that maps character * code to glyph index values. */ @@ -125,31 +125,31 @@ struct CmapSubtableFormat4 *glyph = gid & 0xFFFFu; return true; } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); if (unlikely (!c->check_struct (this))) - return TRACE_RETURN (false); + return_trace (false); if (unlikely (!c->check_range (this, length))) { /* Some broken fonts have too long of a "length" value. * If that is the case, just change the value to truncate * the subtable at the end of the blob. */ uint16_t new_length = (uint16_t) MIN ((uintptr_t) 65535, (uintptr_t) (c->end - (char *) this)); if (!c->try_set (&length, new_length)) - return TRACE_RETURN (false); + return_trace (false); } - return TRACE_RETURN (16 + 4 * (unsigned int) segCountX2 <= length); + return_trace (16 + 4 * (unsigned int) segCountX2 <= length); } protected: USHORT format; /* Format number is set to 4. */ USHORT length; /* This is the length in bytes of the * subtable. */ USHORT languageZ; /* Ignore. */ USHORT segCountX2; /* 2 x segCount. */ @@ -182,17 +182,17 @@ struct CmapSubtableLongGroup if (codepoint < startCharCode) return -1; if (codepoint > endCharCode) return +1; return 0; } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return TRACE_RETURN (c->check_struct (this)); + return_trace (c->check_struct (this)); } private: ULONG startCharCode; /* First character code in this group. */ ULONG endCharCode; /* Last character code in this group. */ ULONG glyphID; /* Glyph index; interpretation depends on * subtable format. */ public: @@ -210,17 +210,17 @@ struct CmapSubtableTrimmed return false; *glyph = gid; return true; } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return TRACE_RETURN (c->check_struct (this) && glyphIdArray.sanitize (c)); + return_trace (c->check_struct (this) && glyphIdArray.sanitize (c)); } protected: UINT formatReserved; /* Subtable format and (maybe) padding. */ UINT lengthZ; /* Byte length of this subtable. */ UINT languageZ; /* Ignore. */ UINT startCharCode; /* First character code covered. */ ArrayOf<GlyphID, UINT> @@ -243,17 +243,17 @@ struct CmapSubtableLongSegmented return false; *glyph = T::group_get_glyph (groups[i], codepoint); return true; } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return TRACE_RETURN (c->check_struct (this) && groups.sanitize (c)); + return_trace (c->check_struct (this) && groups.sanitize (c)); } protected: USHORT format; /* Subtable format; set to 12. */ USHORT reservedZ; /* Reserved; set to 0. */ ULONG lengthZ; /* Byte length of this subtable. */ ULONG languageZ; /* Ignore. */ SortedArrayOf<CmapSubtableLongGroup, ULONG> @@ -290,17 +290,17 @@ struct UnicodeValueRange if (codepoint < startUnicodeValue) return -1; if (codepoint > startUnicodeValue + additionalCount) return +1; return 0; } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return TRACE_RETURN (c->check_struct (this)); + return_trace (c->check_struct (this)); } UINT24 startUnicodeValue; /* First value in this range. */ BYTE additionalCount; /* Number of additional values in this * range. */ public: DEFINE_SIZE_STATIC (4); }; @@ -312,17 +312,17 @@ struct UVSMapping inline int cmp (const hb_codepoint_t &codepoint) const { return unicodeValue.cmp (codepoint); } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return TRACE_RETURN (c->check_struct (this)); + return_trace (c->check_struct (this)); } UINT24 unicodeValue; /* Base Unicode value of the UVS */ GlyphID glyphID; /* Glyph ID of the UVS */ public: DEFINE_SIZE_STATIC (5); }; @@ -352,19 +352,19 @@ struct VariationSelectorRecord inline int cmp (const hb_codepoint_t &variation_selector) const { return varSelector.cmp (variation_selector); } inline bool sanitize (hb_sanitize_context_t *c, const void *base) const { TRACE_SANITIZE (this); - return TRACE_RETURN (c->check_struct (this) && - defaultUVS.sanitize (c, base) && - nonDefaultUVS.sanitize (c, base)); + return_trace (c->check_struct (this) && + defaultUVS.sanitize (c, base) && + nonDefaultUVS.sanitize (c, base)); } UINT24 varSelector; /* Variation selector. */ OffsetTo<DefaultUVS, ULONG> defaultUVS; /* Offset to Default UVS Table. May be 0. */ OffsetTo<NonDefaultUVS, ULONG> nonDefaultUVS; /* Offset to Non-Default UVS Table. May be 0. */ public: @@ -378,18 +378,18 @@ struct CmapSubtableFormat14 hb_codepoint_t *glyph) const { return record[record.bsearch(variation_selector)].get_glyph (codepoint, glyph, this); } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return TRACE_RETURN (c->check_struct (this) && - record.sanitize (c, this)); + return_trace (c->check_struct (this) && + record.sanitize (c, this)); } protected: USHORT format; /* Format number is set to 0. */ ULONG lengthZ; /* Byte length of this subtable. */ SortedArrayOf<VariationSelectorRecord, ULONG> record; /* Variation selector records; sorted * in increasing order of `varSelector'. */ @@ -424,26 +424,26 @@ struct CmapSubtable case 14: return u.format14.get_glyph_variant(codepoint, variation_selector, glyph); default: return GLYPH_VARIANT_NOT_FOUND; } } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - if (!u.format.sanitize (c)) return TRACE_RETURN (false); + if (!u.format.sanitize (c)) return_trace (false); switch (u.format) { - case 0: return TRACE_RETURN (u.format0 .sanitize (c)); - case 4: return TRACE_RETURN (u.format4 .sanitize (c)); - case 6: return TRACE_RETURN (u.format6 .sanitize (c)); - case 10: return TRACE_RETURN (u.format10.sanitize (c)); - case 12: return TRACE_RETURN (u.format12.sanitize (c)); - case 13: return TRACE_RETURN (u.format13.sanitize (c)); - case 14: return TRACE_RETURN (u.format14.sanitize (c)); - default:return TRACE_RETURN (true); + case 0: return_trace (u.format0 .sanitize (c)); + case 4: return_trace (u.format4 .sanitize (c)); + case 6: return_trace (u.format6 .sanitize (c)); + case 10: return_trace (u.format10.sanitize (c)); + case 12: return_trace (u.format12.sanitize (c)); + case 13: return_trace (u.format13.sanitize (c)); + case 14: return_trace (u.format14.sanitize (c)); + default:return_trace (true); } } protected: union { USHORT format; /* Format identifier */ CmapSubtableFormat0 format0; CmapSubtableFormat4 format4; @@ -468,18 +468,18 @@ struct EncodingRecord ret = encodingID.cmp (other.encodingID); if (ret) return ret; return 0; } inline bool sanitize (hb_sanitize_context_t *c, const void *base) const { TRACE_SANITIZE (this); - return TRACE_RETURN (c->check_struct (this) && - subtable.sanitize (c, base)); + return_trace (c->check_struct (this) && + subtable.sanitize (c, base)); } USHORT platformID; /* Platform ID. */ USHORT encodingID; /* Platform-specific encoding ID. */ OffsetTo<CmapSubtable, ULONG> subtable; /* Byte offset from beginning of table to the subtable for this encoding. */ public: DEFINE_SIZE_STATIC (8); @@ -504,19 +504,19 @@ struct cmap return NULL; return &(this+encodingRecord[result].subtable); } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return TRACE_RETURN (c->check_struct (this) && - likely (version == 0) && - encodingRecord.sanitize (c, this)); + return_trace (c->check_struct (this) && + likely (version == 0) && + encodingRecord.sanitize (c, this)); } USHORT version; /* Table version number (0). */ SortedArrayOf<EncodingRecord> encodingRecord; /* Encoding tables. */ public: DEFINE_SIZE_ARRAY (4, encodingRecord); };
--- a/gfx/harfbuzz/src/hb-ot-font.cc +++ b/gfx/harfbuzz/src/hb-ot-font.cc @@ -233,20 +233,19 @@ struct hb_ot_font_t hb_ot_face_cmap_accelerator_t cmap; hb_ot_face_metrics_accelerator_t h_metrics; hb_ot_face_metrics_accelerator_t v_metrics; hb_ot_face_glyf_accelerator_t glyf; }; static hb_ot_font_t * -_hb_ot_font_create (hb_font_t *font) +_hb_ot_font_create (hb_face_t *face) { hb_ot_font_t *ot_font = (hb_ot_font_t *) calloc (1, sizeof (hb_ot_font_t)); - hb_face_t *face = font->face; if (unlikely (!ot_font)) return NULL; unsigned int upem = face->get_upem (); ot_font->cmap.init (face); ot_font->h_metrics.init (face, HB_OT_TAG_hhea, HB_OT_TAG_hmtx, upem>>1); @@ -257,16 +256,17 @@ static hb_ot_font_t * } static void _hb_ot_font_destroy (hb_ot_font_t *ot_font) { ot_font->cmap.fini (); ot_font->h_metrics.fini (); ot_font->v_metrics.fini (); + ot_font->glyf.fini (); free (ot_font); } static hb_bool_t hb_ot_get_glyph (hb_font_t *font HB_UNUSED, void *font_data, @@ -418,17 +418,17 @@ static hb_font_funcs_t * /** * Since: 0.9.28 **/ void hb_ot_font_set_funcs (hb_font_t *font) { - hb_ot_font_t *ot_font = _hb_ot_font_create (font); + hb_ot_font_t *ot_font = _hb_ot_font_create (font->face); if (unlikely (!ot_font)) return; hb_font_set_funcs (font, _hb_ot_get_font_funcs (), ot_font, (hb_destroy_func_t) _hb_ot_font_destroy); }
new file mode 100644 --- /dev/null +++ b/gfx/harfbuzz/src/hb-ot-glyf-table.hh @@ -0,0 +1,104 @@ +/* + * Copyright © 2015 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_OT_GLYF_TABLE_HH +#define HB_OT_GLYF_TABLE_HH + +#include "hb-open-type-private.hh" + + +namespace OT { + + +/* + * loca -- Index to Location + */ + +#define HB_OT_TAG_loca HB_TAG('l','o','c','a') + + +struct loca +{ + static const hb_tag_t tableTag = HB_OT_TAG_loca; + + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (true); + } + + public: + union { + USHORT shortsZ[VAR]; /* Location offset divided by 2. */ + ULONG longsZ[VAR]; /* Location offset. */ + } u; + DEFINE_SIZE_ARRAY (0, u.longsZ); +}; + + +/* + * glyf -- TrueType Glyph Data + */ + +#define HB_OT_TAG_glyf HB_TAG('g','l','y','f') + + +struct glyf +{ + static const hb_tag_t tableTag = HB_OT_TAG_glyf; + + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + /* We don't check for anything specific here. The users of the + * struct do all the hard work... */ + return_trace (true); + } + + public: + BYTE dataX[VAR]; /* Glyphs data. */ + + DEFINE_SIZE_ARRAY (0, dataX); +}; + +struct glyfGlyphHeader +{ + SHORT numberOfContours; /* If the number of contours is + * greater than or equal to zero, + * this is a simple glyph; if negative, + * this is a composite glyph. */ + SHORT xMin; /* Minimum x for coordinate data. */ + SHORT yMin; /* Minimum y for coordinate data. */ + SHORT xMax; /* Maximum x for coordinate data. */ + SHORT yMax; /* Maximum y for coordinate data. */ + + DEFINE_SIZE_STATIC (10); +}; + +} /* namespace OT */ + + +#endif /* HB_OT_GLYF_TABLE_HH */
--- a/gfx/harfbuzz/src/hb-ot-head-table.hh +++ b/gfx/harfbuzz/src/hb-ot-head-table.hh @@ -50,17 +50,17 @@ struct head unsigned int upem = unitsPerEm; /* If no valid head table found, assume 1000, which matches typical Type1 usage. */ return 16 <= upem && upem <= 16384 ? upem : 1000; } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return TRACE_RETURN (c->check_struct (this) && likely (version.major == 1)); + return_trace (c->check_struct (this) && likely (version.major == 1)); } protected: FixedVersion version; /* Version of the head table--currently * 0x00010000u for version 1.0. */ FixedVersion fontRevision; /* Set by font manufacturer. */ ULONG checkSumAdjustment; /* To compute: set it to 0, sum the * entire font as ULONG, then store
--- a/gfx/harfbuzz/src/hb-ot-hhea-table.hh +++ b/gfx/harfbuzz/src/hb-ot-hhea-table.hh @@ -47,17 +47,17 @@ struct _hea static const hb_tag_t tableTag = HB_TAG('_','h','e','a'); static const hb_tag_t hheaTag = HB_OT_TAG_hhea; static const hb_tag_t vheaTag = HB_OT_TAG_vhea; inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return TRACE_RETURN (c->check_struct (this) && likely (version.major == 1)); + return_trace (c->check_struct (this) && likely (version.major == 1)); } public: FixedVersion version; /* 0x00010000u for version 1.0. */ FWORD ascender; /* Typographic ascent. */ FWORD descender; /* Typographic descent. */ FWORD lineGap; /* Typographic line gap. */ UFWORD advanceMax; /* Maximum advance width/height value in
--- a/gfx/harfbuzz/src/hb-ot-hmtx-table.hh +++ b/gfx/harfbuzz/src/hb-ot-hmtx-table.hh @@ -57,17 +57,17 @@ struct _mtx static const hb_tag_t hmtxTag = HB_OT_TAG_hmtx; static const hb_tag_t vmtxTag = HB_OT_TAG_vmtx; inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); /* We don't check for anything specific here. The users of the * struct do all the hard work... */ - return TRACE_RETURN (true); + return_trace (true); } public: LongMetric longMetric[VAR]; /* Paired advance width and leading * bearing values for each glyph. The * value numOfHMetrics comes from * the 'hhea' table. If the font is * monospaced, only one entry need
--- a/gfx/harfbuzz/src/hb-ot-layout-common-private.hh +++ b/gfx/harfbuzz/src/hb-ot-layout-common-private.hh @@ -39,17 +39,17 @@ namespace OT { #define TRACE_DISPATCH(this, format) \ hb_auto_trace_t<context_t::max_debug_depth, typename context_t::return_t> trace \ (&c->debug_depth, c->get_name (), this, HB_FUNC, \ "format %d", (int) format); #define NOT_COVERED ((unsigned int) -1) -#define MAX_NESTING_LEVEL 8 +#define MAX_NESTING_LEVEL 6 #define MAX_CONTEXT_LENGTH 64 /* * * OpenType Layout Common Table Formats * @@ -70,17 +70,17 @@ struct Record struct sanitize_closure_t { hb_tag_t tag; const void *list_base; }; inline bool sanitize (hb_sanitize_context_t *c, const void *base) const { TRACE_SANITIZE (this); const sanitize_closure_t closure = {tag, base}; - return TRACE_RETURN (c->check_struct (this) && offset.sanitize (c, base, &closure)); + return_trace (c->check_struct (this) && offset.sanitize (c, base, &closure)); } Tag tag; /* 4-byte Tag identifier */ OffsetTo<Type> offset; /* Offset from beginning of object holding * the Record */ public: DEFINE_SIZE_STATIC (6); @@ -126,31 +126,31 @@ template <typename Type> struct RecordListOf : RecordArrayOf<Type> { inline const Type& operator [] (unsigned int i) const { return this+RecordArrayOf<Type>::operator [](i).offset; } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return TRACE_RETURN (RecordArrayOf<Type>::sanitize (c, this)); + return_trace (RecordArrayOf<Type>::sanitize (c, this)); } }; struct RangeRecord { inline int cmp (hb_codepoint_t g) const { return g < start ? -1 : g <= end ? 0 : +1 ; } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return TRACE_RETURN (c->check_struct (this)); + return_trace (c->check_struct (this)); } inline bool intersects (const hb_set_t *glyphs) const { return glyphs->intersects (start, end); } template <typename set_t> inline void add_coverage (set_t *glyphs) const { @@ -206,17 +206,17 @@ struct LangSys return Index::NOT_FOUND_INDEX; return reqFeatureIndex;; } inline bool sanitize (hb_sanitize_context_t *c, const Record<LangSys>::sanitize_closure_t * = NULL) const { TRACE_SANITIZE (this); - return TRACE_RETURN (c->check_struct (this) && featureIndex.sanitize (c)); + return_trace (c->check_struct (this) && featureIndex.sanitize (c)); } Offset<> lookupOrderZ; /* = Null (reserved for an offset to a * reordering table) */ USHORT reqFeatureIndex;/* Index of a feature required for this * language system--if no required features * = 0xFFFFu */ IndexArray featureIndex; /* Array of indices into the FeatureList */ @@ -246,17 +246,17 @@ struct Script inline bool has_default_lang_sys (void) const { return defaultLangSys != 0; } inline const LangSys& get_default_lang_sys (void) const { return this+defaultLangSys; } inline bool sanitize (hb_sanitize_context_t *c, const Record<Script>::sanitize_closure_t * = NULL) const { TRACE_SANITIZE (this); - return TRACE_RETURN (defaultLangSys.sanitize (c, this) && langSys.sanitize (c, this)); + return_trace (defaultLangSys.sanitize (c, this) && langSys.sanitize (c, this)); } protected: OffsetTo<LangSys> defaultLangSys; /* Offset to DefaultLangSys table--from * beginning of Script table--may be Null */ RecordArrayOf<LangSys> langSys; /* Array of LangSysRecords--listed @@ -269,17 +269,17 @@ typedef RecordListOf<Script> ScriptList; /* http://www.microsoft.com/typography/otspec/features_pt.htm#size */ struct FeatureParamsSize { inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - if (unlikely (!c->check_struct (this))) return TRACE_RETURN (false); + if (unlikely (!c->check_struct (this))) return_trace (false); /* This subtable has some "history", if you will. Some earlier versions of * Adobe tools calculated the offset of the FeatureParams sutable from the * beginning of the FeatureList table! Now, that is dealt with in the * Feature implementation. But we still need to be able to tell junk from * real data. Note: We don't check that the nameID actually exists. * * Read Roberts wrote on 9/15/06 on opentype-list@indx.co.uk : @@ -321,29 +321,29 @@ struct FeatureParamsSize * "menu name ID" > 32767 or * menu name ID is not a name ID which is actually in the name table) * fails test * Else * passes test. */ if (!designSize) - return TRACE_RETURN (false); + return_trace (false); else if (subfamilyID == 0 && subfamilyNameID == 0 && rangeStart == 0 && rangeEnd == 0) - return TRACE_RETURN (true); + return_trace (true); else if (designSize < rangeStart || designSize > rangeEnd || subfamilyNameID < 256 || subfamilyNameID > 32767) - return TRACE_RETURN (false); + return_trace (false); else - return TRACE_RETURN (true); + return_trace (true); } USHORT designSize; /* Represents the design size in 720/inch * units (decipoints). The design size entry * must be non-zero. When there is a design * size but no recommended size range, the * rest of the array will consist of zeros. */ USHORT subfamilyID; /* Has no independent meaning, but serves @@ -383,17 +383,17 @@ struct FeatureParamsSize /* http://www.microsoft.com/typography/otspec/features_pt.htm#ssxx */ struct FeatureParamsStylisticSet { inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); /* Right now minorVersion is at zero. Which means, any table supports * the uiNameID field. */ - return TRACE_RETURN (c->check_struct (this)); + return_trace (c->check_struct (this)); } USHORT version; /* (set to 0): This corresponds to a “minor” * version number. Additional data may be * added to the end of this Feature Parameters * table in the future. */ USHORT uiNameID; /* The 'name' table name ID that specifies a @@ -415,18 +415,18 @@ struct FeatureParamsStylisticSet }; /* http://www.microsoft.com/typography/otspec/features_ae.htm#cv01-cv99 */ struct FeatureParamsCharacterVariants { inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return TRACE_RETURN (c->check_struct (this) && - characters.sanitize (c)); + return_trace (c->check_struct (this) && + characters.sanitize (c)); } USHORT format; /* Format number is set to 0. */ USHORT featUILableNameID; /* The ‘name’ table name ID that * specifies a string (or strings, * for multiple languages) for a * user-interface label for this * feature. (May be NULL.) */ @@ -457,22 +457,22 @@ struct FeatureParamsCharacterVariants }; struct FeatureParams { inline bool sanitize (hb_sanitize_context_t *c, hb_tag_t tag) const { TRACE_SANITIZE (this); if (tag == HB_TAG ('s','i','z','e')) - return TRACE_RETURN (u.size.sanitize (c)); + return_trace (u.size.sanitize (c)); if ((tag & 0xFFFF0000u) == HB_TAG ('s','s','\0','\0')) /* ssXX */ - return TRACE_RETURN (u.stylisticSet.sanitize (c)); + return_trace (u.stylisticSet.sanitize (c)); if ((tag & 0xFFFF0000u) == HB_TAG ('c','v','\0','\0')) /* cvXX */ - return TRACE_RETURN (u.characterVariants.sanitize (c)); - return TRACE_RETURN (true); + return_trace (u.characterVariants.sanitize (c)); + return_trace (true); } inline const FeatureParamsSize& get_size_params (hb_tag_t tag) const { if (tag == HB_TAG ('s','i','z','e')) return u.size; return Null(FeatureParamsSize); } @@ -500,53 +500,53 @@ struct Feature inline const FeatureParams &get_feature_params (void) const { return this+featureParams; } inline bool sanitize (hb_sanitize_context_t *c, const Record<Feature>::sanitize_closure_t *closure) const { TRACE_SANITIZE (this); if (unlikely (!(c->check_struct (this) && lookupIndex.sanitize (c)))) - return TRACE_RETURN (false); + return_trace (false); /* Some earlier versions of Adobe tools calculated the offset of the * FeatureParams subtable from the beginning of the FeatureList table! * * If sanitizing "failed" for the FeatureParams subtable, try it with the * alternative location. We would know sanitize "failed" if old value * of the offset was non-zero, but it's zeroed now. * * Only do this for the 'size' feature, since at the time of the faulty * Adobe tools, only the 'size' feature had FeatureParams defined. */ OffsetTo<FeatureParams> orig_offset = featureParams; if (unlikely (!featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE))) - return TRACE_RETURN (false); + return_trace (false); if (likely (orig_offset.is_null ())) - return TRACE_RETURN (true); + return_trace (true); if (featureParams == 0 && closure && closure->tag == HB_TAG ('s','i','z','e') && closure->list_base && closure->list_base < this) { unsigned int new_offset_int = (unsigned int) orig_offset - (((char *) this) - ((char *) closure->list_base)); OffsetTo<FeatureParams> new_offset; /* Check that it did not overflow. */ new_offset.set (new_offset_int); if (new_offset == new_offset_int && c->try_set (&featureParams, new_offset) && !featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE)) - return TRACE_RETURN (false); + return_trace (false); } - return TRACE_RETURN (true); + return_trace (true); } OffsetTo<FeatureParams> featureParams; /* Offset to Feature Parameters table (if one * has been defined for the feature), relative * to the beginning of the Feature Table; = Null * if not required */ IndexArray lookupIndex; /* Array of LookupList indices */ @@ -608,50 +608,50 @@ struct Lookup inline typename context_t::return_t dispatch (context_t *c) const { unsigned int lookup_type = get_type (); TRACE_DISPATCH (this, lookup_type); unsigned int count = get_subtable_count (); for (unsigned int i = 0; i < count; i++) { typename context_t::return_t r = get_subtable<SubTableType> (i).dispatch (c, lookup_type); if (c->stop_sublookup_iteration (r)) - return TRACE_RETURN (r); + return_trace (r); } - return TRACE_RETURN (c->default_return_value ()); + return_trace (c->default_return_value ()); } inline bool serialize (hb_serialize_context_t *c, unsigned int lookup_type, uint32_t lookup_props, unsigned int num_subtables) { TRACE_SERIALIZE (this); - if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false); + if (unlikely (!c->extend_min (*this))) return_trace (false); lookupType.set (lookup_type); lookupFlag.set (lookup_props & 0xFFFFu); - if (unlikely (!subTable.serialize (c, num_subtables))) return TRACE_RETURN (false); + if (unlikely (!subTable.serialize (c, num_subtables))) return_trace (false); if (lookupFlag & LookupFlag::UseMarkFilteringSet) { USHORT &markFilteringSet = StructAfter<USHORT> (subTable); markFilteringSet.set (lookup_props >> 16); } - return TRACE_RETURN (true); + return_trace (true); } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); /* Real sanitize of the subtables is done by GSUB/GPOS/... */ - if (!(c->check_struct (this) && subTable.sanitize (c))) return TRACE_RETURN (false); + if (!(c->check_struct (this) && subTable.sanitize (c))) return_trace (false); if (lookupFlag & LookupFlag::UseMarkFilteringSet) { const USHORT &markFilteringSet = StructAfter<USHORT> (subTable); - if (!markFilteringSet.sanitize (c)) return TRACE_RETURN (false); + if (!markFilteringSet.sanitize (c)) return_trace (false); } - return TRACE_RETURN (true); + return_trace (true); } private: USHORT lookupType; /* Different enumerations for GSUB and GPOS */ USHORT lookupFlag; /* Lookup qualifiers */ ArrayOf<Offset<> > subTable; /* Array of SubTables */ USHORT markFilteringSetX[VAR]; /* Index (base 0) into GDEF mark glyph sets @@ -680,29 +680,29 @@ struct CoverageFormat1 return i; } inline bool serialize (hb_serialize_context_t *c, Supplier<GlyphID> &glyphs, unsigned int num_glyphs) { TRACE_SERIALIZE (this); - if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false); + if (unlikely (!c->extend_min (*this))) return_trace (false); glyphArray.len.set (num_glyphs); - if (unlikely (!c->extend (glyphArray))) return TRACE_RETURN (false); + if (unlikely (!c->extend (glyphArray))) return_trace (false); for (unsigned int i = 0; i < num_glyphs; i++) glyphArray[i] = glyphs[i]; glyphs.advance (num_glyphs); - return TRACE_RETURN (true); + return_trace (true); } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return TRACE_RETURN (glyphArray.sanitize (c)); + return_trace (glyphArray.sanitize (c)); } inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const { return glyphs->has (glyphArray[index]); } template <typename set_t> inline void add_coverage (set_t *glyphs) const { @@ -749,47 +749,47 @@ struct CoverageFormat2 return NOT_COVERED; } inline bool serialize (hb_serialize_context_t *c, Supplier<GlyphID> &glyphs, unsigned int num_glyphs) { TRACE_SERIALIZE (this); - if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false); + if (unlikely (!c->extend_min (*this))) return_trace (false); - if (unlikely (!num_glyphs)) return TRACE_RETURN (true); + if (unlikely (!num_glyphs)) return_trace (true); unsigned int num_ranges = 1; for (unsigned int i = 1; i < num_glyphs; i++) if (glyphs[i - 1] + 1 != glyphs[i]) num_ranges++; rangeRecord.len.set (num_ranges); - if (unlikely (!c->extend (rangeRecord))) return TRACE_RETURN (false); + if (unlikely (!c->extend (rangeRecord))) return_trace (false); unsigned int range = 0; rangeRecord[range].start = glyphs[0]; rangeRecord[range].value.set (0); for (unsigned int i = 1; i < num_glyphs; i++) if (glyphs[i - 1] + 1 != glyphs[i]) { range++; rangeRecord[range].start = glyphs[i]; rangeRecord[range].value.set (i); rangeRecord[range].end = glyphs[i]; } else { rangeRecord[range].end = glyphs[i]; } glyphs.advance (num_glyphs); - return TRACE_RETURN (true); + return_trace (true); } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return TRACE_RETURN (rangeRecord.sanitize (c)); + return_trace (rangeRecord.sanitize (c)); } inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const { unsigned int i; unsigned int count = rangeRecord.len; for (i = 0; i < count; i++) { const RangeRecord &range = rangeRecord[i]; if (range.value <= index && @@ -859,37 +859,37 @@ struct Coverage } } inline bool serialize (hb_serialize_context_t *c, Supplier<GlyphID> &glyphs, unsigned int num_glyphs) { TRACE_SERIALIZE (this); - if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false); + if (unlikely (!c->extend_min (*this))) return_trace (false); unsigned int num_ranges = 1; for (unsigned int i = 1; i < num_glyphs; i++) if (glyphs[i - 1] + 1 != glyphs[i]) num_ranges++; u.format.set (num_glyphs * 2 < num_ranges * 3 ? 1 : 2); switch (u.format) { - case 1: return TRACE_RETURN (u.format1.serialize (c, glyphs, num_glyphs)); - case 2: return TRACE_RETURN (u.format2.serialize (c, glyphs, num_glyphs)); - default:return TRACE_RETURN (false); + case 1: return_trace (u.format1.serialize (c, glyphs, num_glyphs)); + case 2: return_trace (u.format2.serialize (c, glyphs, num_glyphs)); + default:return_trace (false); } } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - if (!u.format.sanitize (c)) return TRACE_RETURN (false); + if (!u.format.sanitize (c)) return_trace (false); switch (u.format) { - case 1: return TRACE_RETURN (u.format1.sanitize (c)); - case 2: return TRACE_RETURN (u.format2.sanitize (c)); - default:return TRACE_RETURN (true); + case 1: return_trace (u.format1.sanitize (c)); + case 2: return_trace (u.format2.sanitize (c)); + default:return_trace (true); } } inline bool intersects (const hb_set_t *glyphs) const { /* TODO speed this up */ Coverage::Iter iter; for (iter.init (*this); iter.more (); iter.next ()) { if (glyphs->has (iter.get_glyph ())) @@ -988,17 +988,17 @@ struct ClassDefFormat1 if (unlikely (i < classValue.len)) return classValue[i]; return 0; } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return TRACE_RETURN (c->check_struct (this) && classValue.sanitize (c)); + return_trace (c->check_struct (this) && classValue.sanitize (c)); } template <typename set_t> inline void add_class (set_t *glyphs, unsigned int klass) const { unsigned int count = classValue.len; for (unsigned int i = 0; i < count; i++) if (classValue[i] == klass) glyphs->add (startGlyph + i); @@ -1045,17 +1045,17 @@ struct ClassDefFormat2 if (unlikely (i != -1)) return rangeRecord[i].value; return 0; } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return TRACE_RETURN (rangeRecord.sanitize (c)); + return_trace (rangeRecord.sanitize (c)); } template <typename set_t> inline void add_class (set_t *glyphs, unsigned int klass) const { unsigned int count = rangeRecord.len; for (unsigned int i = 0; i < count; i++) if (rangeRecord[i].value == klass) rangeRecord[i].add_coverage (glyphs); @@ -1103,21 +1103,21 @@ struct ClassDef case 2: return u.format2.get_class(glyph_id); default:return 0; } } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - if (!u.format.sanitize (c)) return TRACE_RETURN (false); + if (!u.format.sanitize (c)) return_trace (false); switch (u.format) { - case 1: return TRACE_RETURN (u.format1.sanitize (c)); - case 2: return TRACE_RETURN (u.format2.sanitize (c)); - default:return TRACE_RETURN (true); + case 1: return_trace (u.format1.sanitize (c)); + case 2: return_trace (u.format2.sanitize (c)); + default:return_trace (true); } } inline void add_class (hb_set_t *glyphs, unsigned int klass) const { switch (u.format) { case 1: u.format1.add_class (glyphs, klass); return; case 2: u.format2.add_class (glyphs, klass); return; default:return; @@ -1196,17 +1196,17 @@ struct Device unsigned int f = deltaFormat; if (unlikely (f < 1 || f > 3 || startSize > endSize)) return 3 * USHORT::static_size; return USHORT::static_size * (4 + ((endSize - startSize) >> (4 - f))); } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return TRACE_RETURN (c->check_struct (this) && c->check_range (this, this->get_size ())); + return_trace (c->check_struct (this) && c->check_range (this, this->get_size ())); } protected: USHORT startSize; /* Smallest size to correct--in ppem */ USHORT endSize; /* Largest size to correct--in ppem */ USHORT deltaFormat; /* Format of DeltaValue array data: 1, 2, or 3 * 1 Signed 2-bit value, 8 values per uint16 * 2 Signed 4-bit value, 4 values per uint16
--- a/gfx/harfbuzz/src/hb-ot-layout-gdef-table.hh +++ b/gfx/harfbuzz/src/hb-ot-layout-gdef-table.hh @@ -69,17 +69,17 @@ struct AttachList } return points.len; } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return TRACE_RETURN (coverage.sanitize (c, this) && attachPoint.sanitize (c, this)); + return_trace (coverage.sanitize (c, this) && attachPoint.sanitize (c, this)); } protected: OffsetTo<Coverage> coverage; /* Offset to Coverage table -- from * beginning of AttachList table */ OffsetArrayOf<AttachPoint> attachPoint; /* Array of AttachPoint tables @@ -100,17 +100,17 @@ struct CaretValueFormat1 inline hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction, hb_codepoint_t glyph_id HB_UNUSED) const { return HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_x (coordinate) : font->em_scale_y (coordinate); } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return TRACE_RETURN (c->check_struct (this)); + return_trace (c->check_struct (this)); } protected: USHORT caretValueFormat; /* Format identifier--format = 1 */ SHORT coordinate; /* X or Y value, in design units */ public: DEFINE_SIZE_STATIC (4); }; @@ -127,17 +127,17 @@ struct CaretValueFormat2 return HB_DIRECTION_IS_HORIZONTAL (direction) ? x : y; else return 0; } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return TRACE_RETURN (c->check_struct (this)); + return_trace (c->check_struct (this)); } protected: USHORT caretValueFormat; /* Format identifier--format = 2 */ USHORT caretValuePoint; /* Contour point index on glyph */ public: DEFINE_SIZE_STATIC (4); }; @@ -151,17 +151,17 @@ struct CaretValueFormat3 return HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_x (coordinate) + (this+deviceTable).get_x_delta (font) : font->em_scale_y (coordinate) + (this+deviceTable).get_y_delta (font); } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return TRACE_RETURN (c->check_struct (this) && deviceTable.sanitize (c, this)); + return_trace (c->check_struct (this) && deviceTable.sanitize (c, this)); } protected: USHORT caretValueFormat; /* Format identifier--format = 3 */ SHORT coordinate; /* X or Y value, in design units */ OffsetTo<Device> deviceTable; /* Offset to Device table for X or Y * value--from beginning of CaretValue @@ -180,22 +180,22 @@ struct CaretValue case 3: return u.format3.get_caret_value (font, direction, glyph_id); default:return 0; } } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - if (!u.format.sanitize (c)) return TRACE_RETURN (false); + if (!u.format.sanitize (c)) return_trace (false); switch (u.format) { - case 1: return TRACE_RETURN (u.format1.sanitize (c)); - case 2: return TRACE_RETURN (u.format2.sanitize (c)); - case 3: return TRACE_RETURN (u.format3.sanitize (c)); - default:return TRACE_RETURN (true); + case 1: return_trace (u.format1.sanitize (c)); + case 2: return_trace (u.format2.sanitize (c)); + case 3: return_trace (u.format3.sanitize (c)); + default:return_trace (true); } } protected: union { USHORT format; /* Format identifier */ CaretValueFormat1 format1; CaretValueFormat2 format2; @@ -222,17 +222,17 @@ struct LigGlyph } return carets.len; } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return TRACE_RETURN (carets.sanitize (c, this)); + return_trace (carets.sanitize (c, this)); } protected: OffsetArrayOf<CaretValue> carets; /* Offset array of CaretValue tables * --from beginning of LigGlyph table * --in increasing coordinate order */ public: @@ -257,17 +257,17 @@ struct LigCaretList } const LigGlyph &lig_glyph = this+ligGlyph[index]; return lig_glyph.get_lig_carets (font, direction, glyph_id, start_offset, caret_count, caret_array); } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return TRACE_RETURN (coverage.sanitize (c, this) && ligGlyph.sanitize (c, this)); + return_trace (coverage.sanitize (c, this) && ligGlyph.sanitize (c, this)); } protected: OffsetTo<Coverage> coverage; /* Offset to Coverage table--from * beginning of LigCaretList table */ OffsetArrayOf<LigGlyph> ligGlyph; /* Array of LigGlyph tables @@ -280,17 +280,17 @@ struct LigCaretList struct MarkGlyphSetsFormat1 { inline bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const { return (this+coverage[set_index]).get_coverage (glyph_id) != NOT_COVERED; } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return TRACE_RETURN (coverage.sanitize (c, this)); + return_trace (coverage.sanitize (c, this)); } protected: USHORT format; /* Format identifier--format = 1 */ ArrayOf<OffsetTo<Coverage, ULONG> > coverage; /* Array of long offsets to mark set * coverage tables */ public: @@ -305,20 +305,20 @@ struct MarkGlyphSets case 1: return u.format1.covers (set_index, glyph_id); default:return false; } } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - if (!u.format.sanitize (c)) return TRACE_RETURN (false); + if (!u.format.sanitize (c)) return_trace (false); switch (u.format) { - case 1: return TRACE_RETURN (u.format1.sanitize (c)); - default:return TRACE_RETURN (true); + case 1: return_trace (u.format1.sanitize (c)); + default:return_trace (true); } } protected: union { USHORT format; /* Format identifier */ MarkGlyphSetsFormat1 format1; } u; @@ -371,23 +371,23 @@ struct GDEF inline bool has_mark_sets (void) const { return version.to_int () >= 0x00010002u && markGlyphSetsDef[0] != 0; } inline bool mark_set_covers (unsigned int set_index, hb_codepoint_t glyph_id) const { return version.to_int () >= 0x00010002u && (this+markGlyphSetsDef[0]).covers (set_index, glyph_id); } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return TRACE_RETURN (version.sanitize (c) && - likely (version.major == 1) && - glyphClassDef.sanitize (c, this) && - attachList.sanitize (c, this) && - ligCaretList.sanitize (c, this) && - markAttachClassDef.sanitize (c, this) && - (version.to_int () < 0x00010002u || markGlyphSetsDef[0].sanitize (c, this))); + return_trace (version.sanitize (c) && + likely (version.major == 1) && + glyphClassDef.sanitize (c, this) && + attachList.sanitize (c, this) && + ligCaretList.sanitize (c, this) && + markAttachClassDef.sanitize (c, this) && + (version.to_int () < 0x00010002u || markGlyphSetsDef[0].sanitize (c, this))); } /* glyph_props is a 16-bit integer where the lower 8-bit have bits representing * glyph class and other bits, and high 8-bit gthe mark attachment type (if any). * Not to be confused with lookup_props which is very similar. */ inline unsigned int get_glyph_props (hb_codepoint_t glyph) const {
--- a/gfx/harfbuzz/src/hb-ot-layout-gpos-table.hh +++ b/gfx/harfbuzz/src/hb-ot-layout-gpos-table.hh @@ -176,68 +176,68 @@ struct ValueFormat : USHORT inline bool has_device (void) const { unsigned int format = *this; return (format & devices) != 0; } inline bool sanitize_value (hb_sanitize_context_t *c, const void *base, const Value *values) const { TRACE_SANITIZE (this); - return TRACE_RETURN (c->check_range (values, get_size ()) && (!has_device () || sanitize_value_devices (c, base, values))); + return_trace (c->check_range (values, get_size ()) && (!has_device () || sanitize_value_devices (c, base, values))); } inline bool sanitize_values (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count) const { TRACE_SANITIZE (this); unsigned int len = get_len (); - if (!c->check_array (values, get_size (), count)) return TRACE_RETURN (false); + if (!c->check_array (values, get_size (), count)) return_trace (false); - if (!has_device ()) return TRACE_RETURN (true); + if (!has_device ()) return_trace (true); for (unsigned int i = 0; i < count; i++) { if (!sanitize_value_devices (c, base, values)) - return TRACE_RETURN (false); + return_trace (false); values += len; } - return TRACE_RETURN (true); + return_trace (true); } /* Just sanitize referenced Device tables. Doesn't check the values themselves. */ inline bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count, unsigned int stride) const { TRACE_SANITIZE (this); - if (!has_device ()) return TRACE_RETURN (true); + if (!has_device ()) return_trace (true); for (unsigned int i = 0; i < count; i++) { if (!sanitize_value_devices (c, base, values)) - return TRACE_RETURN (false); + return_trace (false); values += stride; } - return TRACE_RETURN (true); + return_trace (true); } }; struct AnchorFormat1 { inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id HB_UNUSED, hb_position_t *x, hb_position_t *y) const { *x = font->em_scale_x (xCoordinate); *y = font->em_scale_y (yCoordinate); } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return TRACE_RETURN (c->check_struct (this)); + return_trace (c->check_struct (this)); } protected: USHORT format; /* Format identifier--format = 1 */ SHORT xCoordinate; /* Horizontal value--in design units */ SHORT yCoordinate; /* Vertical value--in design units */ public: DEFINE_SIZE_STATIC (6); @@ -257,17 +257,17 @@ struct AnchorFormat2 font->get_glyph_contour_point_for_origin (glyph_id, anchorPoint, HB_DIRECTION_LTR, &cx, &cy); *x = ret && x_ppem ? cx : font->em_scale_x (xCoordinate); *y = ret && y_ppem ? cy : font->em_scale_y (yCoordinate); } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return TRACE_RETURN (c->check_struct (this)); + return_trace (c->check_struct (this)); } protected: USHORT format; /* Format identifier--format = 2 */ SHORT xCoordinate; /* Horizontal value--in design units */ SHORT yCoordinate; /* Vertical value--in design units */ USHORT anchorPoint; /* Index to glyph contour point */ public: @@ -286,17 +286,17 @@ struct AnchorFormat3 *x += (this+xDeviceTable).get_x_delta (font); if (font->y_ppem) *y += (this+yDeviceTable).get_x_delta (font); } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return TRACE_RETURN (c->check_struct (this) && xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this)); + return_trace (c->check_struct (this) && xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this)); } protected: USHORT format; /* Format identifier--format = 3 */ SHORT xCoordinate; /* Horizontal value--in design units */ SHORT yCoordinate; /* Vertical value--in design units */ OffsetTo<Device> xDeviceTable; /* Offset to Device table for X @@ -322,22 +322,22 @@ struct Anchor case 3: u.format3.get_anchor (font, glyph_id, x, y); return; default: return; } } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - if (!u.format.sanitize (c)) return TRACE_RETURN (false); + if (!u.format.sanitize (c)) return_trace (false); switch (u.format) { - case 1: return TRACE_RETURN (u.format1.sanitize (c)); - case 2: return TRACE_RETURN (u.format2.sanitize (c)); - case 3: return TRACE_RETURN (u.format3.sanitize (c)); - default:return TRACE_RETURN (true); + case 1: return_trace (u.format1.sanitize (c)); + case 2: return_trace (u.format2.sanitize (c)); + case 3: return_trace (u.format3.sanitize (c)); + default:return_trace (true); } } protected: union { USHORT format; /* Format identifier */ AnchorFormat1 format1; AnchorFormat2 format2; @@ -355,23 +355,23 @@ struct AnchorMatrix if (unlikely (row >= rows || col >= cols)) return Null(Anchor); *found = !matrixZ[row * cols + col].is_null (); return this+matrixZ[row * cols + col]; } inline bool sanitize (hb_sanitize_context_t *c, unsigned int cols) const { TRACE_SANITIZE (this); - if (!c->check_struct (this)) return TRACE_RETURN (false); - if (unlikely (rows > 0 && cols >= ((unsigned int) -1) / rows)) return TRACE_RETURN (false); + if (!c->check_struct (this)) return_trace (false); + if (unlikely (rows > 0 && cols >= ((unsigned int) -1) / rows)) return_trace (false); unsigned int count = rows * cols; - if (!c->check_array (matrixZ, matrixZ[0].static_size, count)) return TRACE_RETURN (false); + if (!c->check_array (matrixZ, matrixZ[0].static_size, count)) return_trace (false); for (unsigned int i = 0; i < count; i++) - if (!matrixZ[i].sanitize (c, this)) return TRACE_RETURN (false); - return TRACE_RETURN (true); + if (!matrixZ[i].sanitize (c, this)) return_trace (false); + return_trace (true); } USHORT rows; /* Number of rows */ protected: OffsetTo<Anchor> matrixZ[VAR]; /* Matrix of offsets to Anchor tables-- * from beginning of AnchorMatrix table */ public: @@ -381,17 +381,17 @@ struct AnchorMatrix struct MarkRecord { friend struct MarkArray; inline bool sanitize (hb_sanitize_context_t *c, const void *base) const { TRACE_SANITIZE (this); - return TRACE_RETURN (c->check_struct (this) && markAnchor.sanitize (c, base)); + return_trace (c->check_struct (this) && markAnchor.sanitize (c, base)); } protected: USHORT klass; /* Class defined for this mark */ OffsetTo<Anchor> markAnchor; /* Offset to Anchor table--from * beginning of MarkArray table */ public: @@ -410,36 +410,36 @@ struct MarkArray : ArrayOf<MarkRecord> / const MarkRecord &record = ArrayOf<MarkRecord>::operator[](mark_index); unsigned int mark_class = record.klass; const Anchor& mark_anchor = this + record.markAnchor; bool found; const Anchor& glyph_anchor = anchors.get_anchor (glyph_index, mark_class, class_count, &found); /* If this subtable doesn't have an anchor for this base and this class, * return false such that the subsequent subtables have a chance at it. */ - if (unlikely (!found)) return TRACE_RETURN (false); + if (unlikely (!found)) return_trace (false); hb_position_t mark_x, mark_y, base_x, base_y; mark_anchor.get_anchor (c->font, buffer->cur().codepoint, &mark_x, &mark_y); glyph_anchor.get_anchor (c->font, buffer->info[glyph_pos].codepoint, &base_x, &base_y); hb_glyph_position_t &o = buffer->cur_pos(); o.x_offset = base_x - mark_x; o.y_offset = base_y - mark_y; o.attach_lookback() = buffer->idx - glyph_pos; buffer->idx++; - return TRACE_RETURN (true); + return_trace (true); } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return TRACE_RETURN (ArrayOf<MarkRecord>::sanitize (c, this)); + return_trace (ArrayOf<MarkRecord>::sanitize (c, this)); } }; /* Lookups */ struct SinglePosFormat1 { @@ -454,31 +454,31 @@ struct SinglePosFormat1 return this+coverage; } inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (this); hb_buffer_t *buffer = c->buffer; unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint); - if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); + if (likely (index == NOT_COVERED)) return_trace (false); valueFormat.apply_value (c->font, c->direction, this, values, buffer->cur_pos()); buffer->idx++; - return TRACE_RETURN (true); + return_trace (true); } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return TRACE_RETURN (c->check_struct (this) - && coverage.sanitize (c, this) - && valueFormat.sanitize_value (c, this, values)); + return_trace (c->check_struct (this) && + coverage.sanitize (c, this) && + valueFormat.sanitize_value (c, this, values)); } protected: USHORT format; /* Format identifier--format = 1 */ OffsetTo<Coverage> coverage; /* Offset to Coverage table--from * beginning of subtable */ ValueFormat valueFormat; /* Defines the types of data in the @@ -503,34 +503,34 @@ struct SinglePosFormat2 return this+coverage; } inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (this); hb_buffer_t *buffer = c->buffer; unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint); - if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); + if (likely (index == NOT_COVERED)) return_trace (false); - if (likely (index >= valueCount)) return TRACE_RETURN (false); + if (likely (index >= valueCount)) return_trace (false); valueFormat.apply_value (c->font, c->direction, this, &values[index * valueFormat.get_len ()], buffer->cur_pos()); buffer->idx++; - return TRACE_RETURN (true); + return_trace (true); } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return TRACE_RETURN (c->check_struct (this) - && coverage.sanitize (c, this) - && valueFormat.sanitize_values (c, this, values, valueCount)); + return_trace (c->check_struct (this) && + coverage.sanitize (c, this) && + valueFormat.sanitize_values (c, this, values, valueCount)); } protected: USHORT format; /* Format identifier--format = 2 */ OffsetTo<Coverage> coverage; /* Offset to Coverage table--from * beginning of subtable */ ValueFormat valueFormat; /* Defines the types of data in the @@ -543,21 +543,21 @@ struct SinglePosFormat2 }; struct SinglePos { template <typename context_t> inline typename context_t::return_t dispatch (context_t *c) const { TRACE_DISPATCH (this, u.format); - if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ()); + if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); switch (u.format) { - case 1: return TRACE_RETURN (c->dispatch (u.format1)); - case 2: return TRACE_RETURN (c->dispatch (u.format2)); - default:return TRACE_RETURN (c->default_return_value ()); + case 1: return_trace (c->dispatch (u.format1)); + case 2: return_trace (c->dispatch (u.format2)); + default:return_trace (c->default_return_value ()); } } protected: union { USHORT format; /* Format identifier */ SinglePosFormat1 format1; SinglePosFormat2 format2; @@ -610,17 +610,17 @@ struct PairSet unsigned int len2 = valueFormats[1].get_len (); unsigned int record_size = USHORT::static_size * (1 + len1 + len2); const PairValueRecord *record_array = CastP<PairValueRecord> (arrayZ); unsigned int count = len; /* Hand-coded bsearch. */ if (unlikely (!count)) - return TRACE_RETURN (false); + return_trace (false); hb_codepoint_t x = buffer->info[pos].codepoint; int min = 0, max = (int) count - 1; while (min <= max) { int mid = (min + max) / 2; const PairValueRecord *record = &StructAtOffset<PairValueRecord> (record_array, record_size * mid); hb_codepoint_t mid_x = record->secondGlyph; if (x < mid_x) @@ -631,40 +631,40 @@ struct PairSet { valueFormats[0].apply_value (c->font, c->direction, this, &record->values[0], buffer->cur_pos()); valueFormats[1].apply_value (c->font, c->direction, this, &record->values[len1], buffer->pos[pos]); if (len2) pos++; buffer->idx = pos; - return TRACE_RETURN (true); + return_trace (true); } } - return TRACE_RETURN (false); + return_trace (false); } struct sanitize_closure_t { const void *base; const ValueFormat *valueFormats; unsigned int len1; /* valueFormats[0].get_len() */ unsigned int stride; /* 1 + len1 + len2 */ }; inline bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) const { TRACE_SANITIZE (this); if (!(c->check_struct (this) - && c->check_array (arrayZ, USHORT::static_size * closure->stride, len))) return TRACE_RETURN (false); + && c->check_array (arrayZ, USHORT::static_size * closure->stride, len))) return_trace (false); unsigned int count = len; const PairValueRecord *record = CastP<PairValueRecord> (arrayZ); - return TRACE_RETURN (closure->valueFormats[0].sanitize_values_stride_unsafe (c, closure->base, &record->values[0], count, closure->stride) - && closure->valueFormats[1].sanitize_values_stride_unsafe (c, closure->base, &record->values[closure->len1], count, closure->stride)); + return_trace (closure->valueFormats[0].sanitize_values_stride_unsafe (c, closure->base, &record->values[0], count, closure->stride) && + closure->valueFormats[1].sanitize_values_stride_unsafe (c, closure->base, &record->values[closure->len1], count, closure->stride)); } protected: USHORT len; /* Number of PairValueRecords */ USHORT arrayZ[VAR]; /* Array of PairValueRecords--ordered * by GlyphID of the second glyph */ public: DEFINE_SIZE_ARRAY (2, arrayZ); @@ -686,39 +686,41 @@ struct PairPosFormat1 return this+coverage; } inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (this); hb_buffer_t *buffer = c->buffer; unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint); - if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); + if (likely (index == NOT_COVERED)) return_trace (false); hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; skippy_iter.reset (buffer->idx, 1); - if (!skippy_iter.next ()) return TRACE_RETURN (false); + if (!skippy_iter.next ()) return_trace (false); - return TRACE_RETURN ((this+pairSet[index]).apply (c, &valueFormat1, skippy_iter.idx)); + return_trace ((this+pairSet[index]).apply (c, &valueFormat1, skippy_iter.idx)); } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); + if (!c->check_struct (this)) return_trace (false); + unsigned int len1 = valueFormat1.get_len (); unsigned int len2 = valueFormat2.get_len (); PairSet::sanitize_closure_t closure = { this, &valueFormat1, len1, 1 + len1 + len2 }; - return TRACE_RETURN (c->check_struct (this) && coverage.sanitize (c, this) && pairSet.sanitize (c, this, &closure)); + return_trace (coverage.sanitize (c, this) && pairSet.sanitize (c, this, &closure)); } protected: USHORT format; /* Format identifier--format = 1 */ OffsetTo<Coverage> coverage; /* Offset to Coverage table--from * beginning of subtable */ ValueFormat valueFormat1; /* Defines the types of data in @@ -757,59 +759,59 @@ struct PairPosFormat2 return this+coverage; } inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (this); hb_buffer_t *buffer = c->buffer; unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint); - if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); + if (likely (index == NOT_COVERED)) return_trace (false); hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; skippy_iter.reset (buffer->idx, 1); - if (!skippy_iter.next ()) return TRACE_RETURN (false); + if (!skippy_iter.next ()) return_trace (false); unsigned int len1 = valueFormat1.get_len (); unsigned int len2 = valueFormat2.get_len (); unsigned int record_len = len1 + len2; unsigned int klass1 = (this+classDef1).get_class (buffer->cur().codepoint); unsigned int klass2 = (this+classDef2).get_class (buffer->info[skippy_iter.idx].codepoint); - if (unlikely (klass1 >= class1Count || klass2 >= class2Count)) return TRACE_RETURN (false); + if (unlikely (klass1 >= class1Count || klass2 >= class2Count)) return_trace (false); const Value *v = &values[record_len * (klass1 * class2Count + klass2)]; valueFormat1.apply_value (c->font, c->direction, this, v, buffer->cur_pos()); valueFormat2.apply_value (c->font, c->direction, this, v + len1, buffer->pos[skippy_iter.idx]); buffer->idx = skippy_iter.idx; if (len2) buffer->idx++; - return TRACE_RETURN (true); + return_trace (true); } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); if (!(c->check_struct (this) && coverage.sanitize (c, this) && classDef1.sanitize (c, this) - && classDef2.sanitize (c, this))) return TRACE_RETURN (false); + && classDef2.sanitize (c, this))) return_trace (false); unsigned int len1 = valueFormat1.get_len (); unsigned int len2 = valueFormat2.get_len (); unsigned int stride = len1 + len2; unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size (); unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count; - return TRACE_RETURN (c->check_array (values, record_size, count) && - valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) && - valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride)); + return_trace (c->check_array (values, record_size, count) && + valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) && + valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride)); } protected: USHORT format; /* Format identifier--format = 2 */ OffsetTo<Coverage> coverage; /* Offset to Coverage table--from * beginning of subtable */ ValueFormat valueFormat1; /* ValueRecord definition--for the @@ -838,21 +840,21 @@ struct PairPosFormat2 }; struct PairPos { template <typename context_t> inline typename context_t::return_t dispatch (context_t *c) const { TRACE_DISPATCH (this, u.format); - if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ()); + if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); switch (u.format) { - case 1: return TRACE_RETURN (c->dispatch (u.format1)); - case 2: return TRACE_RETURN (c->dispatch (u.format2)); - default:return TRACE_RETURN (c->default_return_value ()); + case 1: return_trace (c->dispatch (u.format1)); + case 2: return_trace (c->dispatch (u.format2)); + default:return_trace (c->default_return_value ()); } } protected: union { USHORT format; /* Format identifier */ PairPosFormat1 format1; PairPosFormat2 format2; @@ -862,17 +864,17 @@ struct PairPos struct EntryExitRecord { friend struct CursivePosFormat1; inline bool sanitize (hb_sanitize_context_t *c, const void *base) const { TRACE_SANITIZE (this); - return TRACE_RETURN (entryAnchor.sanitize (c, base) && exitAnchor.sanitize (c, base)); + return_trace (entryAnchor.sanitize (c, base) && exitAnchor.sanitize (c, base)); } protected: OffsetTo<Anchor> entryAnchor; /* Offset to EntryAnchor table--from * beginning of CursivePos * subtable--may be NULL */ OffsetTo<Anchor> @@ -900,27 +902,27 @@ struct CursivePosFormat1 } inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (this); hb_buffer_t *buffer = c->buffer; /* We don't handle mark glyphs here. */ - if (unlikely (_hb_glyph_info_is_mark (&buffer->cur()))) return TRACE_RETURN (false); + if (unlikely (_hb_glyph_info_is_mark (&buffer->cur()))) return_trace (false); const EntryExitRecord &this_record = entryExitRecord[(this+coverage).get_coverage (buffer->cur().codepoint)]; - if (!this_record.exitAnchor) return TRACE_RETURN (false); + if (!this_record.exitAnchor) return_trace (false); hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; skippy_iter.reset (buffer->idx, 1); - if (!skippy_iter.next ()) return TRACE_RETURN (false); + if (!skippy_iter.next ()) return_trace (false); const EntryExitRecord &next_record = entryExitRecord[(this+coverage).get_coverage (buffer->info[skippy_iter.idx].codepoint)]; - if (!next_record.entryAnchor) return TRACE_RETURN (false); + if (!next_record.entryAnchor) return_trace (false); unsigned int i = buffer->idx; unsigned int j = skippy_iter.idx; hb_position_t entry_x, entry_y, exit_x, exit_y; (this+this_record.exitAnchor).get_anchor (c->font, buffer->info[i].codepoint, &exit_x, &exit_y); (this+next_record.entryAnchor).get_anchor (c->font, buffer->info[j].codepoint, &entry_x, &entry_y); @@ -992,23 +994,23 @@ struct CursivePosFormat1 pos[child].cursive_chain() = parent - child; if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction))) pos[child].y_offset = y_offset; else pos[child].x_offset = x_offset; buffer->idx = j; - return TRACE_RETURN (true); + return_trace (true); } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return TRACE_RETURN (coverage.sanitize (c, this) && entryExitRecord.sanitize (c, this)); + return_trace (coverage.sanitize (c, this) && entryExitRecord.sanitize (c, this)); } protected: USHORT format; /* Format identifier--format = 1 */ OffsetTo<Coverage> coverage; /* Offset to Coverage table--from * beginning of subtable */ ArrayOf<EntryExitRecord> @@ -1019,20 +1021,20 @@ struct CursivePosFormat1 }; struct CursivePos { template <typename context_t> inline typename context_t::return_t dispatch (context_t *c) const { TRACE_DISPATCH (this, u.format); - if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ()); + if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); switch (u.format) { - case 1: return TRACE_RETURN (c->dispatch (u.format1)); - default:return TRACE_RETURN (c->default_return_value ()); + case 1: return_trace (c->dispatch (u.format1)); + default:return_trace (c->default_return_value ()); } } protected: union { USHORT format; /* Format identifier */ CursivePosFormat1 format1; } u; @@ -1058,43 +1060,46 @@ struct MarkBasePosFormat1 return this+markCoverage; } inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (this); hb_buffer_t *buffer = c->buffer; unsigned int mark_index = (this+markCoverage).get_coverage (buffer->cur().codepoint); - if (likely (mark_index == NOT_COVERED)) return TRACE_RETURN (false); + if (likely (mark_index == NOT_COVERED)) return_trace (false); /* now we search backwards for a non-mark glyph */ hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; skippy_iter.reset (buffer->idx, 1); skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks); do { - if (!skippy_iter.prev ()) return TRACE_RETURN (false); + if (!skippy_iter.prev ()) return_trace (false); /* We only want to attach to the first of a MultipleSubst sequence. Reject others. */ if (0 == _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx])) break; skippy_iter.reject (); } while (1); /* Checking that matched glyph is actually a base glyph by GDEF is too strong; disabled */ - if (!_hb_glyph_info_is_base_glyph (&buffer->info[skippy_iter.idx])) { /*return TRACE_RETURN (false);*/ } + if (!_hb_glyph_info_is_base_glyph (&buffer->info[skippy_iter.idx])) { /*return_trace (false);*/ } unsigned int base_index = (this+baseCoverage).get_coverage (buffer->info[skippy_iter.idx].codepoint); - if (base_index == NOT_COVERED) return TRACE_RETURN (false); + if (base_index == NOT_COVERED) return_trace (false); - return TRACE_RETURN ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, skippy_iter.idx)); + return_trace ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, skippy_iter.idx)); } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return TRACE_RETURN (c->check_struct (this) && markCoverage.sanitize (c, this) && baseCoverage.sanitize (c, this) && - markArray.sanitize (c, this) && baseArray.sanitize (c, this, (unsigned int) classCount)); + return_trace (c->check_struct (this) && + markCoverage.sanitize (c, this) && + baseCoverage.sanitize (c, this) && + markArray.sanitize (c, this) && + baseArray.sanitize (c, this, (unsigned int) classCount)); } protected: USHORT format; /* Format identifier--format = 1 */ OffsetTo<Coverage> markCoverage; /* Offset to MarkCoverage table--from * beginning of MarkBasePos subtable */ OffsetTo<Coverage> @@ -1112,20 +1117,20 @@ struct MarkBasePosFormat1 }; struct MarkBasePos { template <typename context_t> inline typename context_t::return_t dispatch (context_t *c) const { TRACE_DISPATCH (this, u.format); - if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ()); + if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); switch (u.format) { - case 1: return TRACE_RETURN (c->dispatch (u.format1)); - default:return TRACE_RETURN (c->default_return_value ()); + case 1: return_trace (c->dispatch (u.format1)); + default:return_trace (c->default_return_value ()); } } protected: union { USHORT format; /* Format identifier */ MarkBasePosFormat1 format1; } u; @@ -1156,59 +1161,62 @@ struct MarkLigPosFormat1 return this+markCoverage; } inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (this); hb_buffer_t *buffer = c->buffer; unsigned int mark_index = (this+markCoverage).get_coverage (buffer->cur().codepoint); - if (likely (mark_index == NOT_COVERED)) return TRACE_RETURN (false); + if (likely (mark_index == NOT_COVERED)) return_trace (false); /* now we search backwards for a non-mark glyph */ hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; skippy_iter.reset (buffer->idx, 1); skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks); - if (!skippy_iter.prev ()) return TRACE_RETURN (false); + if (!skippy_iter.prev ()) return_trace (false); /* Checking that matched glyph is actually a ligature by GDEF is too strong; disabled */ - if (!_hb_glyph_info_is_ligature (&buffer->info[skippy_iter.idx])) { /*return TRACE_RETURN (false);*/ } + if (!_hb_glyph_info_is_ligature (&buffer->info[skippy_iter.idx])) { /*return_trace (false);*/ } unsigned int j = skippy_iter.idx; unsigned int lig_index = (this+ligatureCoverage).get_coverage (buffer->info[j].codepoint); - if (lig_index == NOT_COVERED) return TRACE_RETURN (false); + if (lig_index == NOT_COVERED) return_trace (false); const LigatureArray& lig_array = this+ligatureArray; const LigatureAttach& lig_attach = lig_array[lig_index]; /* Find component to attach to */ unsigned int comp_count = lig_attach.rows; - if (unlikely (!comp_count)) return TRACE_RETURN (false); + if (unlikely (!comp_count)) return_trace (false); /* We must now check whether the ligature ID of the current mark glyph * is identical to the ligature ID of the found ligature. If yes, we * can directly use the component index. If not, we attach the mark * glyph to the last component of the ligature. */ unsigned int comp_index; unsigned int lig_id = _hb_glyph_info_get_lig_id (&buffer->info[j]); unsigned int mark_id = _hb_glyph_info_get_lig_id (&buffer->cur()); unsigned int mark_comp = _hb_glyph_info_get_lig_comp (&buffer->cur()); if (lig_id && lig_id == mark_id && mark_comp > 0) comp_index = MIN (comp_count, _hb_glyph_info_get_lig_comp (&buffer->cur())) - 1; else comp_index = comp_count - 1; - return TRACE_RETURN ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j)); + return_trace ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j)); } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return TRACE_RETURN (c->check_struct (this) && markCoverage.sanitize (c, this) && ligatureCoverage.sanitize (c, this) && - markArray.sanitize (c, this) && ligatureArray.sanitize (c, this, (unsigned int) classCount)); + return_trace (c->check_struct (this) && + markCoverage.sanitize (c, this) && + ligatureCoverage.sanitize (c, this) && + markArray.sanitize (c, this) && + ligatureArray.sanitize (c, this, (unsigned int) classCount)); } protected: USHORT format; /* Format identifier--format = 1 */ OffsetTo<Coverage> markCoverage; /* Offset to Mark Coverage table--from * beginning of MarkLigPos subtable */ OffsetTo<Coverage> @@ -1227,20 +1235,20 @@ struct MarkLigPosFormat1 }; struct MarkLigPos { template <typename context_t> inline typename context_t::return_t dispatch (context_t *c) const { TRACE_DISPATCH (this, u.format); - if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ()); + if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); switch (u.format) { - case 1: return TRACE_RETURN (c->dispatch (u.format1)); - default:return TRACE_RETURN (c->default_return_value ()); + case 1: return_trace (c->dispatch (u.format1)); + default:return_trace (c->default_return_value ()); } } protected: union { USHORT format; /* Format identifier */ MarkLigPosFormat1 format1; } u; @@ -1266,25 +1274,25 @@ struct MarkMarkPosFormat1 return this+mark1Coverage; } inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (this); hb_buffer_t *buffer = c->buffer; unsigned int mark1_index = (this+mark1Coverage).get_coverage (buffer->cur().codepoint); - if (likely (mark1_index == NOT_COVERED)) return TRACE_RETURN (false); + if (likely (mark1_index == NOT_COVERED)) return_trace (false); /* now we search backwards for a suitable mark glyph until a non-mark glyph */ hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; skippy_iter.reset (buffer->idx, 1); skippy_iter.set_lookup_props (c->lookup_props & ~LookupFlag::IgnoreFlags); - if (!skippy_iter.prev ()) return TRACE_RETURN (false); + if (!skippy_iter.prev ()) return_trace (false); - if (!_hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx])) { return TRACE_RETURN (false); } + if (!_hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx])) { return_trace (false); } unsigned int j = skippy_iter.idx; unsigned int id1 = _hb_glyph_info_get_lig_id (&buffer->cur()); unsigned int id2 = _hb_glyph_info_get_lig_id (&buffer->info[j]); unsigned int comp1 = _hb_glyph_info_get_lig_comp (&buffer->cur()); unsigned int comp2 = _hb_glyph_info_get_lig_comp (&buffer->info[j]); @@ -1296,31 +1304,33 @@ struct MarkMarkPosFormat1 } else { /* If ligature ids don't match, it may be the case that one of the marks * itself is a ligature. In which case match. */ if ((id1 > 0 && !comp1) || (id2 > 0 && !comp2)) goto good; } /* Didn't match. */ - return TRACE_RETURN (false); + return_trace (false); good: unsigned int mark2_index = (this+mark2Coverage).get_coverage (buffer->info[j].codepoint); - if (mark2_index == NOT_COVERED) return TRACE_RETURN (false); + if (mark2_index == NOT_COVERED) return_trace (false); - return TRACE_RETURN ((this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j)); + return_trace ((this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j)); } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return TRACE_RETURN (c->check_struct (this) && mark1Coverage.sanitize (c, this) && - mark2Coverage.sanitize (c, this) && mark1Array.sanitize (c, this) - && mark2Array.sanitize (c, this, (unsigned int) classCount)); + return_trace (c->check_struct (this) && + mark1Coverage.sanitize (c, this) && + mark2Coverage.sanitize (c, this) && + mark1Array.sanitize (c, this) && + mark2Array.sanitize (c, this, (unsigned int) classCount)); } protected: USHORT format; /* Format identifier--format = 1 */ OffsetTo<Coverage> mark1Coverage; /* Offset to Combining Mark1 Coverage * table--from beginning of MarkMarkPos * subtable */ @@ -1340,20 +1350,20 @@ struct MarkMarkPosFormat1 }; struct MarkMarkPos { template <typename context_t> inline typename context_t::return_t dispatch (context_t *c) const { TRACE_DISPATCH (this, u.format); - if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ()); + if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); switch (u.format) { - case 1: return TRACE_RETURN (c->dispatch (u.format1)); - default:return TRACE_RETURN (c->default_return_value ()); + case 1: return_trace (c->dispatch (u.format1)); + default:return_trace (c->default_return_value ()); } } protected: union { USHORT format; /* Format identifier */ MarkMarkPosFormat1 format1; } u; @@ -1391,29 +1401,28 @@ struct PosLookupSubTable ChainContext = 8, Extension = 9 }; template <typename context_t> inline typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const { TRACE_DISPATCH (this, lookup_type); - /* The sub_format passed to may_dispatch is unnecessary but harmless. */ - if (unlikely (!c->may_dispatch (this, &u.sub_format))) TRACE_RETURN (c->default_return_value ()); + if (unlikely (!c->may_dispatch (this, &u.sub_format))) return_trace (c->no_dispatch_return_value ()); switch (lookup_type) { - case Single: return TRACE_RETURN (u.single.dispatch (c)); - case Pair: return TRACE_RETURN (u.pair.dispatch (c)); - case Cursive: return TRACE_RETURN (u.cursive.dispatch (c)); - case MarkBase: return TRACE_RETURN (u.markBase.dispatch (c)); - case MarkLig: return TRACE_RETURN (u.markLig.dispatch (c)); - case MarkMark: return TRACE_RETURN (u.markMark.dispatch (c)); - case Context: return TRACE_RETURN (u.context.dispatch (c)); - case ChainContext: return TRACE_RETURN (u.chainContext.dispatch (c)); - case Extension: return TRACE_RETURN (u.extension.dispatch (c)); - default: return TRACE_RETURN (c->default_return_value ()); + case Single: return_trace (u.single.dispatch (c)); + case Pair: return_trace (u.pair.dispatch (c)); + case Cursive: return_trace (u.cursive.dispatch (c)); + case MarkBase: return_trace (u.markBase.dispatch (c)); + case MarkLig: return_trace (u.markLig.dispatch (c)); + case MarkMark: return_trace (u.markMark.dispatch (c)); + case Context: return_trace (u.context.dispatch (c)); + case ChainContext: return_trace (u.chainContext.dispatch (c)); + case Extension: return_trace (u.extension.dispatch (c)); + default: return_trace (c->default_return_value ()); } } protected: union { USHORT sub_format; SinglePos single; PairPos pair; @@ -1438,23 +1447,23 @@ struct PosLookup : Lookup inline bool is_reverse (void) const { return false; } inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (this); - return TRACE_RETURN (dispatch (c)); + return_trace (dispatch (c)); } inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const { TRACE_COLLECT_GLYPHS (this); - return TRACE_RETURN (dispatch (c)); + return_trace (dispatch (c)); } template <typename set_t> inline void add_coverage (set_t *glyphs) const { hb_add_coverage_context_t<set_t> c (glyphs); dispatch (&c); } @@ -1466,18 +1475,18 @@ struct PosLookup : Lookup template <typename context_t> inline typename context_t::return_t dispatch (context_t *c) const { return Lookup::dispatch<PosLookupSubTable> (c); } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - if (unlikely (!Lookup::sanitize (c))) return TRACE_RETURN (false); - return TRACE_RETURN (dispatch (c)); + if (unlikely (!Lookup::sanitize (c))) return_trace (false); + return_trace (dispatch (c)); } }; typedef OffsetListOf<PosLookup> PosLookupList; /* * GPOS -- The Glyph Positioning Table */ @@ -1490,19 +1499,19 @@ struct GPOS : GSUBGPOS { return CastR<PosLookup> (GSUBGPOS::get_lookup (i)); } static inline void position_start (hb_font_t *font, hb_buffer_t *buffer); static inline void position_finish (hb_font_t *font, hb_buffer_t *buffer); inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - if (unlikely (!GSUBGPOS::sanitize (c))) return TRACE_RETURN (false); + if (unlikely (!GSUBGPOS::sanitize (c))) return_trace (false); const OffsetTo<PosLookupList> &list = CastR<OffsetTo<PosLookupList> > (lookupList); - return TRACE_RETURN (list.sanitize (c, this)); + return_trace (list.sanitize (c, this)); } public: DEFINE_SIZE_STATIC (10); }; static void reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction, unsigned int new_parent)
--- a/gfx/harfbuzz/src/hb-ot-layout-gsub-table.hh +++ b/gfx/harfbuzz/src/hb-ot-layout-gsub-table.hh @@ -62,50 +62,50 @@ struct SingleSubstFormat1 inline const Coverage &get_coverage (void) const { return this+coverage; } inline bool would_apply (hb_would_apply_context_t *c) const { TRACE_WOULD_APPLY (this); - return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED); + return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED); } inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (this); hb_codepoint_t glyph_id = c->buffer->cur().codepoint; unsigned int index = (this+coverage).get_coverage (glyph_id); - if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); + if (likely (index == NOT_COVERED)) return_trace (false); /* According to the Adobe Annotated OpenType Suite, result is always * limited to 16bit. */ glyph_id = (glyph_id + deltaGlyphID) & 0xFFFFu; c->replace_glyph (glyph_id); - return TRACE_RETURN (true); + return_trace (true); } inline bool serialize (hb_serialize_context_t *c, Supplier<GlyphID> &glyphs, unsigned int num_glyphs, int delta) { TRACE_SERIALIZE (this); - if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false); - if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false); + if (unlikely (!c->extend_min (*this))) return_trace (false); + if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false); deltaGlyphID.set (delta); /* TODO(serilaize) overflow? */ - return TRACE_RETURN (true); + return_trace (true); } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return TRACE_RETURN (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c)); + return_trace (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c)); } protected: USHORT format; /* Format identifier--format = 1 */ OffsetTo<Coverage> coverage; /* Offset to Coverage table--from * beginning of Substitution table */ SHORT deltaGlyphID; /* Add to original GlyphID to get @@ -139,50 +139,50 @@ struct SingleSubstFormat2 inline const Coverage &get_coverage (void) const { return this+coverage; } inline bool would_apply (hb_would_apply_context_t *c) const { TRACE_WOULD_APPLY (this); - return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED); + return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED); } inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (this); hb_codepoint_t glyph_id = c->buffer->cur().codepoint; unsigned int index = (this+coverage).get_coverage (glyph_id); - if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); + if (likely (index == NOT_COVERED)) return_trace (false); - if (unlikely (index >= substitute.len)) return TRACE_RETURN (false); + if (unlikely (index >= substitute.len)) return_trace (false); glyph_id = substitute[index]; c->replace_glyph (glyph_id); - return TRACE_RETURN (true); + return_trace (true); } inline bool serialize (hb_serialize_context_t *c, Supplier<GlyphID> &glyphs, Supplier<GlyphID> &substitutes, unsigned int num_glyphs) { TRACE_SERIALIZE (this); - if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false); - if (unlikely (!substitute.serialize (c, substitutes, num_glyphs))) return TRACE_RETURN (false); - if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false); - return TRACE_RETURN (true); + if (unlikely (!c->extend_min (*this))) return_trace (false); + if (unlikely (!substitute.serialize (c, substitutes, num_glyphs))) return_trace (false); + if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false); + return_trace (true); } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return TRACE_RETURN (coverage.sanitize (c, this) && substitute.sanitize (c)); + return_trace (coverage.sanitize (c, this) && substitute.sanitize (c)); } protected: USHORT format; /* Format identifier--format = 2 */ OffsetTo<Coverage> coverage; /* Offset to Coverage table--from * beginning of Substitution table */ ArrayOf<GlyphID> @@ -195,46 +195,46 @@ struct SingleSubstFormat2 struct SingleSubst { inline bool serialize (hb_serialize_context_t *c, Supplier<GlyphID> &glyphs, Supplier<GlyphID> &substitutes, unsigned int num_glyphs) { TRACE_SERIALIZE (this); - if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false); + if (unlikely (!c->extend_min (u.format))) return_trace (false); unsigned int format = 2; int delta = 0; if (num_glyphs) { format = 1; /* TODO(serialize) check for wrap-around */ delta = substitutes[0] - glyphs[0]; for (unsigned int i = 1; i < num_glyphs; i++) if (delta != substitutes[i] - glyphs[i]) { format = 2; break; } } u.format.set (format); switch (u.format) { - case 1: return TRACE_RETURN (u.format1.serialize (c, glyphs, num_glyphs, delta)); - case 2: return TRACE_RETURN (u.format2.serialize (c, glyphs, substitutes, num_glyphs)); - default:return TRACE_RETURN (false); + case 1: return_trace (u.format1.serialize (c, glyphs, num_glyphs, delta)); + case 2: return_trace (u.format2.serialize (c, glyphs, substitutes, num_glyphs)); + default:return_trace (false); } } template <typename context_t> inline typename context_t::return_t dispatch (context_t *c) const { TRACE_DISPATCH (this, u.format); - if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ()); + if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); switch (u.format) { - case 1: return TRACE_RETURN (c->dispatch (u.format1)); - case 2: return TRACE_RETURN (c->dispatch (u.format2)); - default:return TRACE_RETURN (c->default_return_value ()); + case 1: return_trace (c->dispatch (u.format1)); + case 2: return_trace (c->dispatch (u.format2)); + default:return_trace (c->default_return_value ()); } } protected: union { USHORT format; /* Format identifier */ SingleSubstFormat1 format1; SingleSubstFormat2 format2; @@ -268,52 +268,52 @@ struct Sequence /* TODO: * Testing shows that Uniscribe actually allows zero-len susbstitute, * which essentially deletes a glyph. We don't allow for now. It * can be confusing to the client since the cluster from the deleted * glyph won't be merged with any output cluster... Also, currently * buffer->move_to() makes assumptions about this too. Perhaps fix * in the future after figuring out what to do with the clusters. */ - if (unlikely (!count)) return TRACE_RETURN (false); + if (unlikely (!count)) return_trace (false); /* Special-case to make it in-place and not consider this * as a "multiplied" substitution. */ if (unlikely (count == 1)) { c->replace_glyph (substitute.array[0]); - return TRACE_RETURN (true); + return_trace (true); } unsigned int klass = _hb_glyph_info_is_ligature (&c->buffer->cur()) ? HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 0; for (unsigned int i = 0; i < count; i++) { _hb_glyph_info_set_lig_props_for_component (&c->buffer->cur(), i); c->output_glyph_for_component (substitute.array[i], klass); } c->buffer->skip_glyph (); - return TRACE_RETURN (true); + return_trace (true); } inline bool serialize (hb_serialize_context_t *c, Supplier<GlyphID> &glyphs, unsigned int num_glyphs) { TRACE_SERIALIZE (this); - if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false); - if (unlikely (!substitute.serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false); - return TRACE_RETURN (true); + if (unlikely (!c->extend_min (*this))) return_trace (false); + if (unlikely (!substitute.serialize (c, glyphs, num_glyphs))) return_trace (false); + return_trace (true); } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return TRACE_RETURN (substitute.sanitize (c)); + return_trace (substitute.sanitize (c)); } protected: ArrayOf<GlyphID> substitute; /* String of GlyphIDs to substitute */ public: DEFINE_SIZE_ARRAY (2, substitute); }; @@ -342,51 +342,51 @@ struct MultipleSubstFormat1 inline const Coverage &get_coverage (void) const { return this+coverage; } inline bool would_apply (hb_would_apply_context_t *c) const { TRACE_WOULD_APPLY (this); - return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED); + return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED); } inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (this); unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); - if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); + if (likely (index == NOT_COVERED)) return_trace (false); - return TRACE_RETURN ((this+sequence[index]).apply (c)); + return_trace ((this+sequence[index]).apply (c)); } inline bool serialize (hb_serialize_context_t *c, Supplier<GlyphID> &glyphs, Supplier<unsigned int> &substitute_len_list, unsigned int num_glyphs, Supplier<GlyphID> &substitute_glyphs_list) { TRACE_SERIALIZE (this); - if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false); - if (unlikely (!sequence.serialize (c, num_glyphs))) return TRACE_RETURN (false); + if (unlikely (!c->extend_min (*this))) return_trace (false); + if (unlikely (!sequence.serialize (c, num_glyphs))) return_trace (false); for (unsigned int i = 0; i < num_glyphs; i++) if (unlikely (!sequence[i].serialize (c, this).serialize (c, substitute_glyphs_list, - substitute_len_list[i]))) return TRACE_RETURN (false); + substitute_len_list[i]))) return_trace (false); substitute_len_list.advance (num_glyphs); - if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false); - return TRACE_RETURN (true); + if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false); + return_trace (true); } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return TRACE_RETURN (coverage.sanitize (c, this) && sequence.sanitize (c, this)); + return_trace (coverage.sanitize (c, this) && sequence.sanitize (c, this)); } protected: USHORT format; /* Format identifier--format = 1 */ OffsetTo<Coverage> coverage; /* Offset to Coverage table--from * beginning of Substitution table */ OffsetArrayOf<Sequence> @@ -400,33 +400,33 @@ struct MultipleSubst { inline bool serialize (hb_serialize_context_t *c, Supplier<GlyphID> &glyphs, Supplier<unsigned int> &substitute_len_list, unsigned int num_glyphs, Supplier<GlyphID> &substitute_glyphs_list) { TRACE_SERIALIZE (this); - if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false); + if (unlikely (!c->extend_min (u.format))) return_trace (false); unsigned int format = 1; u.format.set (format); switch (u.format) { - case 1: return TRACE_RETURN (u.format1.serialize (c, glyphs, substitute_len_list, num_glyphs, substitute_glyphs_list)); - default:return TRACE_RETURN (false); + case 1: return_trace (u.format1.serialize (c, glyphs, substitute_len_list, num_glyphs, substitute_glyphs_list)); + default:return_trace (false); } } template <typename context_t> inline typename context_t::return_t dispatch (context_t *c) const { TRACE_DISPATCH (this, u.format); - if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ()); + if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); switch (u.format) { - case 1: return TRACE_RETURN (c->dispatch (u.format1)); - default:return TRACE_RETURN (c->default_return_value ()); + case 1: return_trace (c->dispatch (u.format1)); + default:return_trace (c->default_return_value ()); } } protected: union { USHORT format; /* Format identifier */ MultipleSubstFormat1 format1; } u; @@ -468,69 +468,69 @@ struct AlternateSubstFormat1 inline const Coverage &get_coverage (void) const { return this+coverage; } inline bool would_apply (hb_would_apply_context_t *c) const { TRACE_WOULD_APPLY (this); - return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED); + return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED); } inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (this); hb_codepoint_t glyph_id = c->buffer->cur().codepoint; unsigned int index = (this+coverage).get_coverage (glyph_id); - if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); + if (likely (index == NOT_COVERED)) return_trace (false); const AlternateSet &alt_set = this+alternateSet[index]; - if (unlikely (!alt_set.len)) return TRACE_RETURN (false); + if (unlikely (!alt_set.len)) return_trace (false); hb_mask_t glyph_mask = c->buffer->cur().mask; hb_mask_t lookup_mask = c->lookup_mask; /* Note: This breaks badly if two features enabled this lookup together. */ unsigned int shift = _hb_ctz (lookup_mask); unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift); - if (unlikely (alt_index > alt_set.len || alt_index == 0)) return TRACE_RETURN (false); + if (unlikely (alt_index > alt_set.len || alt_index == 0)) return_trace (false); glyph_id = alt_set[alt_index - 1]; c->replace_glyph (glyph_id); - return TRACE_RETURN (true); + return_trace (true); } inline bool serialize (hb_serialize_context_t *c, Supplier<GlyphID> &glyphs, Supplier<unsigned int> &alternate_len_list, unsigned int num_glyphs, Supplier<GlyphID> &alternate_glyphs_list) { TRACE_SERIALIZE (this); - if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false); - if (unlikely (!alternateSet.serialize (c, num_glyphs))) return TRACE_RETURN (false); + if (unlikely (!c->extend_min (*this))) return_trace (false); + if (unlikely (!alternateSet.serialize (c, num_glyphs))) return_trace (false); for (unsigned int i = 0; i < num_glyphs; i++) if (unlikely (!alternateSet[i].serialize (c, this).serialize (c, alternate_glyphs_list, - alternate_len_list[i]))) return TRACE_RETURN (false); + alternate_len_list[i]))) return_trace (false); alternate_len_list.advance (num_glyphs); - if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false); - return TRACE_RETURN (true); + if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false); + return_trace (true); } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return TRACE_RETURN (coverage.sanitize (c, this) && alternateSet.sanitize (c, this)); + return_trace (coverage.sanitize (c, this) && alternateSet.sanitize (c, this)); } protected: USHORT format; /* Format identifier--format = 1 */ OffsetTo<Coverage> coverage; /* Offset to Coverage table--from * beginning of Substitution table */ OffsetArrayOf<AlternateSet> @@ -544,33 +544,33 @@ struct AlternateSubst { inline bool serialize (hb_serialize_context_t *c, Supplier<GlyphID> &glyphs, Supplier<unsigned int> &alternate_len_list, unsigned int num_glyphs, Supplier<GlyphID> &alternate_glyphs_list) { TRACE_SERIALIZE (this); - if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false); + if (unlikely (!c->extend_min (u.format))) return_trace (false); unsigned int format = 1; u.format.set (format); switch (u.format) { - case 1: return TRACE_RETURN (u.format1.serialize (c, glyphs, alternate_len_list, num_glyphs, alternate_glyphs_list)); - default:return TRACE_RETURN (false); + case 1: return_trace (u.format1.serialize (c, glyphs, alternate_len_list, num_glyphs, alternate_glyphs_list)); + default:return_trace (false); } } template <typename context_t> inline typename context_t::return_t dispatch (context_t *c) const { TRACE_DISPATCH (this, u.format); - if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ()); + if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); switch (u.format) { - case 1: return TRACE_RETURN (c->dispatch (u.format1)); - default:return TRACE_RETURN (c->default_return_value ()); + case 1: return_trace (c->dispatch (u.format1)); + default:return_trace (c->default_return_value ()); } } protected: union { USHORT format; /* Format identifier */ AlternateSubstFormat1 format1; } u; @@ -597,84 +597,84 @@ struct Ligature c->input->add (component[i]); c->output->add (ligGlyph); } inline bool would_apply (hb_would_apply_context_t *c) const { TRACE_WOULD_APPLY (this); if (c->len != component.len) - return TRACE_RETURN (false); + return_trace (false); for (unsigned int i = 1; i < c->len; i++) if (likely (c->glyphs[i] != component[i])) - return TRACE_RETURN (false); + return_trace (false); - return TRACE_RETURN (true); + return_trace (true); } inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (this); unsigned int count = component.len; - if (unlikely (!count)) return TRACE_RETURN (false); + if (unlikely (!count)) return_trace (false); /* Special-case to make it in-place and not consider this * as a "ligated" substitution. */ if (unlikely (count == 1)) { c->replace_glyph (ligGlyph); - return TRACE_RETURN (true); + return_trace (true); } bool is_mark_ligature = false; unsigned int total_component_count = 0; unsigned int match_length = 0; unsigned int match_positions[MAX_CONTEXT_LENGTH]; if (likely (!match_input (c, count, &component[1], match_glyph, NULL, &match_length, match_positions, &is_mark_ligature, &total_component_count))) - return TRACE_RETURN (false); + return_trace (false); ligate_input (c, count, match_positions, match_length, ligGlyph, is_mark_ligature, total_component_count); - return TRACE_RETURN (true); + return_trace (true); } inline bool serialize (hb_serialize_context_t *c, GlyphID ligature, Supplier<GlyphID> &components, /* Starting from second */ unsigned int num_components /* Including first component */) { TRACE_SERIALIZE (this); - if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false); + if (unlikely (!c->extend_min (*this))) return_trace (false); ligGlyph = ligature; - if (unlikely (!component.serialize (c, components, num_components))) return TRACE_RETURN (false); - return TRACE_RETURN (true); + if (unlikely (!component.serialize (c, components, num_components))) return_trace (false); + return_trace (true); } public: inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return TRACE_RETURN (ligGlyph.sanitize (c) && component.sanitize (c)); + return_trace (ligGlyph.sanitize (c) && component.sanitize (c)); } protected: GlyphID ligGlyph; /* GlyphID of ligature to substitute */ HeadlessArrayOf<GlyphID> component; /* Array of component GlyphIDs--start * with the second component--ordered * in writing direction */ @@ -703,57 +703,57 @@ struct LigatureSet inline bool would_apply (hb_would_apply_context_t *c) const { TRACE_WOULD_APPLY (this); unsigned int num_ligs = ligature.len; for (unsigned int i = 0; i < num_ligs; i++) { const Ligature &lig = this+ligature[i]; if (lig.would_apply (c)) - return TRACE_RETURN (true); + return_trace (true); } - return TRACE_RETURN (false); + return_trace (false); } inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (this); unsigned int num_ligs = ligature.len; for (unsigned int i = 0; i < num_ligs; i++) { const Ligature &lig = this+ligature[i]; - if (lig.apply (c)) return TRACE_RETURN (true); + if (lig.apply (c)) return_trace (true); } - return TRACE_RETURN (false); + return_trace (false); } inline bool serialize (hb_serialize_context_t *c, Supplier<GlyphID> &ligatures, Supplier<unsigned int> &component_count_list, unsigned int num_ligatures, Supplier<GlyphID> &component_list /* Starting from second for each ligature */) { TRACE_SERIALIZE (this); - if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false); - if (unlikely (!ligature.serialize (c, num_ligatures))) return TRACE_RETURN (false); + if (unlikely (!c->extend_min (*this))) return_trace (false); + if (unlikely (!ligature.serialize (c, num_ligatures))) return_trace (false); for (unsigned int i = 0; i < num_ligatures; i++) if (unlikely (!ligature[i].serialize (c, this).serialize (c, ligatures[i], component_list, - component_count_list[i]))) return TRACE_RETURN (false); + component_count_list[i]))) return_trace (false); ligatures.advance (num_ligatures); component_count_list.advance (num_ligatures); - return TRACE_RETURN (true); + return_trace (true); } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return TRACE_RETURN (ligature.sanitize (c, this)); + return_trace (ligature.sanitize (c, this)); } protected: OffsetArrayOf<Ligature> ligature; /* Array LigatureSet tables * ordered by preference */ public: DEFINE_SIZE_ARRAY (2, ligature); @@ -785,60 +785,60 @@ struct LigatureSubstFormat1 { return this+coverage; } inline bool would_apply (hb_would_apply_context_t *c) const { TRACE_WOULD_APPLY (this); unsigned int index = (this+coverage).get_coverage (c->glyphs[0]); - if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); + if (likely (index == NOT_COVERED)) return_trace (false); const LigatureSet &lig_set = this+ligatureSet[index]; - return TRACE_RETURN (lig_set.would_apply (c)); + return_trace (lig_set.would_apply (c)); } inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (this); hb_codepoint_t glyph_id = c->buffer->cur().codepoint; unsigned int index = (this+coverage).get_coverage (glyph_id); - if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); + if (likely (index == NOT_COVERED)) return_trace (false); const LigatureSet &lig_set = this+ligatureSet[index]; - return TRACE_RETURN (lig_set.apply (c)); + return_trace (lig_set.apply (c)); } inline bool serialize (hb_serialize_context_t *c, Supplier<GlyphID> &first_glyphs, Supplier<unsigned int> &ligature_per_first_glyph_count_list, unsigned int num_first_glyphs, Supplier<GlyphID> &ligatures_list, Supplier<unsigned int> &component_count_list, Supplier<GlyphID> &component_list /* Starting from second for each ligature */) { TRACE_SERIALIZE (this); - if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false); - if (unlikely (!ligatureSet.serialize (c, num_first_glyphs))) return TRACE_RETURN (false); + if (unlikely (!c->extend_min (*this))) return_trace (false); + if (unlikely (!ligatureSet.serialize (c, num_first_glyphs))) return_trace (false); for (unsigned int i = 0; i < num_first_glyphs; i++) if (unlikely (!ligatureSet[i].serialize (c, this).serialize (c, ligatures_list, component_count_list, ligature_per_first_glyph_count_list[i], - component_list))) return TRACE_RETURN (false); + component_list))) return_trace (false); ligature_per_first_glyph_count_list.advance (num_first_glyphs); - if (unlikely (!coverage.serialize (c, this).serialize (c, first_glyphs, num_first_glyphs))) return TRACE_RETURN (false); - return TRACE_RETURN (true); + if (unlikely (!coverage.serialize (c, this).serialize (c, first_glyphs, num_first_glyphs))) return_trace (false); + return_trace (true); } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return TRACE_RETURN (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this)); + return_trace (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this)); } protected: USHORT format; /* Format identifier--format = 1 */ OffsetTo<Coverage> coverage; /* Offset to Coverage table--from * beginning of Substitution table */ OffsetArrayOf<LigatureSet> @@ -854,34 +854,39 @@ struct LigatureSubst Supplier<GlyphID> &first_glyphs, Supplier<unsigned int> &ligature_per_first_glyph_count_list, unsigned int num_first_glyphs, Supplier<GlyphID> &ligatures_list, Supplier<unsigned int> &component_count_list, Supplier<GlyphID> &component_list /* Starting from second for each ligature */) { TRACE_SERIALIZE (this); - if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false); + if (unlikely (!c->extend_min (u.format))) return_trace (false); unsigned int format = 1; u.format.set (format); switch (u.format) { - case 1: return TRACE_RETURN (u.format1.serialize (c, first_glyphs, ligature_per_first_glyph_count_list, num_first_glyphs, - ligatures_list, component_count_list, component_list)); - default:return TRACE_RETURN (false); + case 1: return_trace (u.format1.serialize (c, + first_glyphs, + ligature_per_first_glyph_count_list, + num_first_glyphs, + ligatures_list, + component_count_list, + component_list)); + default:return_trace (false); } } template <typename context_t> inline typename context_t::return_t dispatch (context_t *c) const { TRACE_DISPATCH (this, u.format); - if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ()); + if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); switch (u.format) { - case 1: return TRACE_RETURN (c->dispatch (u.format1)); - default:return TRACE_RETURN (c->default_return_value ()); + case 1: return_trace (c->dispatch (u.format1)); + default:return_trace (c->default_return_value ()); } } protected: union { USHORT format; /* Format identifier */ LigatureSubstFormat1 format1; } u; @@ -954,59 +959,59 @@ struct ReverseChainSingleSubstFormat1 inline const Coverage &get_coverage (void) const { return this+coverage; } inline bool would_apply (hb_would_apply_context_t *c) const { TRACE_WOULD_APPLY (this); - return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED); + return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED); } inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (this); if (unlikely (c->nesting_level_left != MAX_NESTING_LEVEL)) - return TRACE_RETURN (false); /* No chaining to this type */ + return_trace (false); /* No chaining to this type */ unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); - if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); + if (likely (index == NOT_COVERED)) return_trace (false); const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack); const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead); if (match_backtrack (c, backtrack.len, (USHORT *) backtrack.array, match_coverage, this) && match_lookahead (c, lookahead.len, (USHORT *) lookahead.array, match_coverage, this, 1)) { c->replace_glyph_inplace (substitute[index]); /* Note: We DON'T decrease buffer->idx. The main loop does it * for us. This is useful for preventing surprises if someone * calls us through a Context lookup. */ - return TRACE_RETURN (true); + return_trace (true); } - return TRACE_RETURN (false); + return_trace (false); } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this))) - return TRACE_RETURN (false); + return_trace (false); const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack); if (!lookahead.sanitize (c, this)) - return TRACE_RETURN (false); + return_trace (false); const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead); - return TRACE_RETURN (substitute.sanitize (c)); + return_trace (substitute.sanitize (c)); } protected: USHORT format; /* Format identifier--format = 1 */ OffsetTo<Coverage> coverage; /* Offset to Coverage table--from * beginning of table */ OffsetArrayOf<Coverage> @@ -1025,20 +1030,20 @@ struct ReverseChainSingleSubstFormat1 }; struct ReverseChainSingleSubst { template <typename context_t> inline typename context_t::return_t dispatch (context_t *c) const { TRACE_DISPATCH (this, u.format); - if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ()); + if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); switch (u.format) { - case 1: return TRACE_RETURN (c->dispatch (u.format1)); - default:return TRACE_RETURN (c->default_return_value ()); + case 1: return_trace (c->dispatch (u.format1)); + default:return_trace (c->default_return_value ()); } } protected: union { USHORT format; /* Format identifier */ ReverseChainSingleSubstFormat1 format1; } u; @@ -1064,28 +1069,27 @@ struct SubstLookupSubTable Extension = 7, ReverseChainSingle = 8 }; template <typename context_t> inline typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const { TRACE_DISPATCH (this, lookup_type); - /* The sub_format passed to may_dispatch is unnecessary but harmless. */ - if (unlikely (!c->may_dispatch (this, &u.sub_format))) TRACE_RETURN (c->default_return_value ()); + if (unlikely (!c->may_dispatch (this, &u.sub_format))) return_trace (c->no_dispatch_return_value ()); switch (lookup_type) { - case Single: return TRACE_RETURN (u.single.dispatch (c)); - case Multiple: return TRACE_RETURN (u.multiple.dispatch (c)); - case Alternate: return TRACE_RETURN (u.alternate.dispatch (c)); - case Ligature: return TRACE_RETURN (u.ligature.dispatch (c)); - case Context: return TRACE_RETURN (u.context.dispatch (c)); - case ChainContext: return TRACE_RETURN (u.chainContext.dispatch (c)); - case Extension: return TRACE_RETURN (u.extension.dispatch (c)); - case ReverseChainSingle: return TRACE_RETURN (u.reverseChainContextSingle.dispatch (c)); - default: return TRACE_RETURN (c->default_return_value ()); + case Single: return_trace (u.single.dispatch (c)); + case Multiple: return_trace (u.multiple.dispatch (c)); + case Alternate: return_trace (u.alternate.dispatch (c)); + case Ligature: return_trace (u.ligature.dispatch (c)); + case Context: return_trace (u.context.dispatch (c)); + case ChainContext: return_trace (u.chainContext.dispatch (c)); + case Extension: return_trace (u.extension.dispatch (c)); + case ReverseChainSingle: return_trace (u.reverseChainContextSingle.dispatch (c)); + default: return_trace (c->default_return_value ()); } } protected: union { USHORT sub_format; SingleSubst single; MultipleSubst multiple; @@ -1115,132 +1119,143 @@ struct SubstLookup : Lookup if (unlikely (type == SubstLookupSubTable::Extension)) return CastR<ExtensionSubst> (get_subtable(0)).is_reverse (); return lookup_type_is_reverse (type); } inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (this); - return TRACE_RETURN (dispatch (c)); + return_trace (dispatch (c)); } inline hb_closure_context_t::return_t closure (hb_closure_context_t *c) const { TRACE_CLOSURE (this); c->set_recurse_func (dispatch_recurse_func<hb_closure_context_t>); - return TRACE_RETURN (dispatch (c)); + return_trace (dispatch (c)); } inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const { TRACE_COLLECT_GLYPHS (this); c->set_recurse_func (dispatch_recurse_func<hb_collect_glyphs_context_t>); - return TRACE_RETURN (dispatch (c)); + return_trace (dispatch (c)); } template <typename set_t> inline void add_coverage (set_t *glyphs) const { hb_add_coverage_context_t<set_t> c (glyphs); dispatch (&c); } inline bool would_apply (hb_would_apply_context_t *c, const hb_ot_layout_lookup_accelerator_t *accel) const { TRACE_WOULD_APPLY (this); - if (unlikely (!c->len)) return TRACE_RETURN (false); - if (!accel->may_have (c->glyphs[0])) return TRACE_RETURN (false); - return TRACE_RETURN (dispatch (c)); + if (unlikely (!c->len)) return_trace (false); + if (!accel->may_have (c->glyphs[0])) return_trace (false); + return_trace (dispatch (c)); } static bool apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index); inline SubstLookupSubTable& serialize_subtable (hb_serialize_context_t *c, unsigned int i) { return get_subtables<SubstLookupSubTable> ()[i].serialize (c, this); } inline bool serialize_single (hb_serialize_context_t *c, uint32_t lookup_props, Supplier<GlyphID> &glyphs, Supplier<GlyphID> &substitutes, unsigned int num_glyphs) { TRACE_SERIALIZE (this); - if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Single, lookup_props, 1))) return TRACE_RETURN (false); - return TRACE_RETURN (serialize_subtable (c, 0).u.single.serialize (c, glyphs, substitutes, num_glyphs)); + if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Single, lookup_props, 1))) return_trace (false); + return_trace (serialize_subtable (c, 0).u.single.serialize (c, glyphs, substitutes, num_glyphs)); } inline bool serialize_multiple (hb_serialize_context_t *c, uint32_t lookup_props, Supplier<GlyphID> &glyphs, Supplier<unsigned int> &substitute_len_list, unsigned int num_glyphs, Supplier<GlyphID> &substitute_glyphs_list) { TRACE_SERIALIZE (this); - if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Multiple, lookup_props, 1))) return TRACE_RETURN (false); - return TRACE_RETURN (serialize_subtable (c, 0).u.multiple.serialize (c, glyphs, substitute_len_list, num_glyphs, - substitute_glyphs_list)); + if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Multiple, lookup_props, 1))) return_trace (false); + return_trace (serialize_subtable (c, 0).u.multiple.serialize (c, + glyphs, + substitute_len_list, + num_glyphs, + substitute_glyphs_list)); } inline bool serialize_alternate (hb_serialize_context_t *c, uint32_t lookup_props, Supplier<GlyphID> &glyphs, Supplier<unsigned int> &alternate_len_list, unsigned int num_glyphs, Supplier<GlyphID> &alternate_glyphs_list) { TRACE_SERIALIZE (this); - if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Alternate, lookup_props, 1))) return TRACE_RETURN (false); - return TRACE_RETURN (serialize_subtable (c, 0).u.alternate.serialize (c, glyphs, alternate_len_list, num_glyphs, - alternate_glyphs_list)); + if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Alternate, lookup_props, 1))) return_trace (false); + return_trace (serialize_subtable (c, 0).u.alternate.serialize (c, + glyphs, + alternate_len_list, + num_glyphs, + alternate_glyphs_list)); } inline bool serialize_ligature (hb_serialize_context_t *c, uint32_t lookup_props, Supplier<GlyphID> &first_glyphs, Supplier<unsigned int> &ligature_per_first_glyph_count_list, unsigned int num_first_glyphs, Supplier<GlyphID> &ligatures_list, Supplier<unsigned int> &component_count_list, Supplier<GlyphID> &component_list /* Starting from second for each ligature */) { TRACE_SERIALIZE (this); - if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Ligature, lookup_props, 1))) return TRACE_RETURN (false); - return TRACE_RETURN (serialize_subtable (c, 0).u.ligature.serialize (c, first_glyphs, ligature_per_first_glyph_count_list, num_first_glyphs, - ligatures_list, component_count_list, component_list)); + if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Ligature, lookup_props, 1))) return_trace (false); + return_trace (serialize_subtable (c, 0).u.ligature.serialize (c, + first_glyphs, + ligature_per_first_glyph_count_list, + num_first_glyphs, + ligatures_list, + component_count_list, + component_list)); } template <typename context_t> static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index); template <typename context_t> inline typename context_t::return_t dispatch (context_t *c) const { return Lookup::dispatch<SubstLookupSubTable> (c); } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - if (unlikely (!Lookup::sanitize (c))) return TRACE_RETURN (false); - if (unlikely (!dispatch (c))) return TRACE_RETURN (false); + if (unlikely (!Lookup::sanitize (c))) return_trace (false); + if (unlikely (!dispatch (c))) return_trace (false); if (unlikely (get_type () == SubstLookupSubTable::Extension)) { /* The spec says all subtables of an Extension lookup should * have the same type. This is specially important if one has * a reverse type! */ unsigned int type = get_subtable (0).u.extension.get_type (); unsigned int count = get_subtable_count (); for (unsigned int i = 1; i < count; i++) if (get_subtable (i).u.extension.get_type () != type) - return TRACE_RETURN (false); + return_trace (false); } - return TRACE_RETURN (true); + return_trace (true); } }; typedef OffsetListOf<SubstLookup> SubstLookupList; /* * GSUB -- The Glyph Substitution Table */ @@ -1253,19 +1268,19 @@ struct GSUB : GSUBGPOS { return CastR<SubstLookup> (GSUBGPOS::get_lookup (i)); } static inline void substitute_start (hb_font_t *font, hb_buffer_t *buffer); static inline void substitute_finish (hb_font_t *font, hb_buffer_t *buffer); inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - if (unlikely (!GSUBGPOS::sanitize (c))) return TRACE_RETURN (false); + if (unlikely (!GSUBGPOS::sanitize (c))) return_trace (false); const OffsetTo<SubstLookupList> &list = CastR<OffsetTo<SubstLookupList> > (lookupList); - return TRACE_RETURN (list.sanitize (c, this)); + return_trace (list.sanitize (c, this)); } public: DEFINE_SIZE_STATIC (10); }; void GSUB::substitute_start (hb_font_t *font, hb_buffer_t *buffer)
--- a/gfx/harfbuzz/src/hb-ot-layout-gsubgpos-private.hh +++ b/gfx/harfbuzz/src/hb-ot-layout-gsubgpos-private.hh @@ -41,24 +41,21 @@ namespace OT { #define HB_DEBUG_CLOSURE (HB_DEBUG+0) #endif #define TRACE_CLOSURE(this) \ hb_auto_trace_t<HB_DEBUG_CLOSURE, hb_void_t> trace \ (&c->debug_depth, c->get_name (), this, HB_FUNC, \ ""); -struct hb_closure_context_t +struct hb_closure_context_t : + hb_dispatch_context_t<hb_closure_context_t, hb_void_t, HB_DEBUG_CLOSURE> { inline const char *get_name (void) { return "CLOSURE"; } - static const unsigned int max_debug_depth = HB_DEBUG_CLOSURE; - typedef hb_void_t return_t; typedef return_t (*recurse_func_t) (hb_closure_context_t *c, unsigned int lookup_index); - template <typename T, typename F> - inline bool may_dispatch (const T *obj, const F *format) { return true; } template <typename T> inline return_t dispatch (const T &obj) { obj.closure (this); return HB_VOID; } static return_t default_return_value (void) { return HB_VOID; } bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; } return_t recurse (unsigned int lookup_index) { if (unlikely (nesting_level_left == 0 || !recurse_func)) return default_return_value (); @@ -93,23 +90,20 @@ struct hb_closure_context_t #define HB_DEBUG_WOULD_APPLY (HB_DEBUG+0) #endif #define TRACE_WOULD_APPLY(this) \ hb_auto_trace_t<HB_DEBUG_WOULD_APPLY, bool> trace \ (&c->debug_depth, c->get_name (), this, HB_FUNC, \ "%d glyphs", c->len); -struct hb_would_apply_context_t +struct hb_would_apply_context_t : + hb_dispatch_context_t<hb_would_apply_context_t, bool, HB_DEBUG_WOULD_APPLY> { inline const char *get_name (void) { return "WOULD_APPLY"; } - static const unsigned int max_debug_depth = HB_DEBUG_WOULD_APPLY; - typedef bool return_t; - template <typename T, typename F> - inline bool may_dispatch (const T *obj, const F *format) { return true; } template <typename T> inline return_t dispatch (const T &obj) { return obj.would_apply (this); } static return_t default_return_value (void) { return false; } bool stop_sublookup_iteration (return_t r) const { return r; } hb_face_t *face; const hb_codepoint_t *glyphs; unsigned int len; @@ -133,24 +127,21 @@ struct hb_would_apply_context_t #define HB_DEBUG_COLLECT_GLYPHS (HB_DEBUG+0) #endif #define TRACE_COLLECT_GLYPHS(this) \ hb_auto_trace_t<HB_DEBUG_COLLECT_GLYPHS, hb_void_t> trace \ (&c->debug_depth, c->get_name (), this, HB_FUNC, \ ""); -struct hb_collect_glyphs_context_t +struct hb_collect_glyphs_context_t : + hb_dispatch_context_t<hb_collect_glyphs_context_t, hb_void_t, HB_DEBUG_COLLECT_GLYPHS> { inline const char *get_name (void) { return "COLLECT_GLYPHS"; } - static const unsigned int max_debug_depth = HB_DEBUG_COLLECT_GLYPHS; - typedef hb_void_t return_t; typedef return_t (*recurse_func_t) (hb_collect_glyphs_context_t *c, unsigned int lookup_index); - template <typename T, typename F> - inline bool may_dispatch (const T *obj, const F *format) { return true; } template <typename T> inline return_t dispatch (const T &obj) { obj.collect_glyphs (this); return HB_VOID; } static return_t default_return_value (void) { return HB_VOID; } bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; } return_t recurse (unsigned int lookup_index) { if (unlikely (nesting_level_left == 0 || !recurse_func)) return default_return_value (); @@ -227,24 +218,24 @@ struct hb_collect_glyphs_context_t }; #ifndef HB_DEBUG_GET_COVERAGE #define HB_DEBUG_GET_COVERAGE (HB_DEBUG+0) #endif +/* XXX Can we remove this? */ + template <typename set_t> -struct hb_add_coverage_context_t +struct hb_add_coverage_context_t : + hb_dispatch_context_t<hb_add_coverage_context_t<set_t>, const Coverage &, HB_DEBUG_GET_COVERAGE> { inline const char *get_name (void) { return "GET_COVERAGE"; } - static const unsigned int max_debug_depth = HB_DEBUG_GET_COVERAGE; typedef const Coverage &return_t; - template <typename T, typename F> - inline bool may_dispatch (const T *obj, const F *format) { return true; } template <typename T> inline return_t dispatch (const T &obj) { return obj.get_coverage (); } static return_t default_return_value (void) { return Null(Coverage); } bool stop_sublookup_iteration (return_t r) const { r.add_coverage (set); return false; } @@ -264,17 +255,18 @@ struct hb_add_coverage_context_t #endif #define TRACE_APPLY(this) \ hb_auto_trace_t<HB_DEBUG_APPLY, bool> trace \ (&c->debug_depth, c->get_name (), this, HB_FUNC, \ "idx %d gid %u lookup %d", \ c->buffer->idx, c->buffer->cur().codepoint, (int) c->lookup_index); -struct hb_apply_context_t +struct hb_apply_context_t : + hb_dispatch_context_t<hb_apply_context_t, bool, HB_DEBUG_APPLY> { struct matcher_t { inline matcher_t (void) : lookup_props (0), ignore_zwnj (false), ignore_zwj (false), mask (-1), @@ -444,21 +436,17 @@ struct hb_apply_context_t const USHORT *match_glyph_data; unsigned int num_items; unsigned int end; }; inline const char *get_name (void) { return "APPLY"; } - static const unsigned int max_debug_depth = HB_DEBUG_APPLY; - typedef bool return_t; typedef return_t (*recurse_func_t) (hb_apply_context_t *c, unsigned int lookup_index); - template <typename T, typename F> - inline bool may_dispatch (const T *obj, const F *format) { return true; } template <typename T> inline return_t dispatch (const T &obj) { return obj.apply (this); } static return_t default_return_value (void) { return false; } bool stop_sublookup_iteration (return_t r) const { return r; } return_t recurse (unsigned int lookup_index) { if (unlikely (nesting_level_left == 0 || !recurse_func)) return default_return_value (); @@ -717,17 +705,17 @@ static inline bool match_input (hb_apply const void *match_data, unsigned int *end_offset, unsigned int match_positions[MAX_CONTEXT_LENGTH], bool *p_is_mark_ligature = NULL, unsigned int *p_total_component_count = NULL) { TRACE_APPLY (NULL); - if (unlikely (count > MAX_CONTEXT_LENGTH)) return TRACE_RETURN (false); + if (unlikely (count > MAX_CONTEXT_LENGTH)) return_trace (false); hb_buffer_t *buffer = c->buffer; hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; skippy_iter.reset (buffer->idx, count - 1); skippy_iter.set_match_func (match_func, match_data, input); /* @@ -754,52 +742,52 @@ static inline bool match_input (hb_apply total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->cur()); unsigned int first_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur()); unsigned int first_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->cur()); match_positions[0] = buffer->idx; for (unsigned int i = 1; i < count; i++) { - if (!skippy_iter.next ()) return TRACE_RETURN (false); + if (!skippy_iter.next ()) return_trace (false); match_positions[i] = skippy_iter.idx; unsigned int this_lig_id = _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]); unsigned int this_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]); if (first_lig_id && first_lig_comp) { /* If first component was attached to a previous ligature component, * all subsequent components should be attached to the same ligature * component, otherwise we shouldn't ligate them. */ if (first_lig_id != this_lig_id || first_lig_comp != this_lig_comp) - return TRACE_RETURN (false); + return_trace (false); } else { /* If first component was NOT attached to a previous ligature component, * all subsequent components should also NOT be attached to any ligature * component, unless they are attached to the first component itself! */ if (this_lig_id && this_lig_comp && (this_lig_id != first_lig_id)) - return TRACE_RETURN (false); + return_trace (false); } is_mark_ligature = is_mark_ligature && _hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx]); total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->info[skippy_iter.idx]); } *end_offset = skippy_iter.idx - buffer->idx + 1; if (p_is_mark_ligature) *p_is_mark_ligature = is_mark_ligature; if (p_total_component_count) *p_total_component_count = total_component_count; - return TRACE_RETURN (true); + return_trace (true); } -static inline void ligate_input (hb_apply_context_t *c, +static inline bool ligate_input (hb_apply_context_t *c, unsigned int count, /* Including the first glyph */ unsigned int match_positions[MAX_CONTEXT_LENGTH], /* Including the first glyph */ unsigned int match_length, hb_codepoint_t lig_glyph, bool is_mark_ligature, unsigned int total_component_count) { TRACE_APPLY (NULL); @@ -879,36 +867,36 @@ static inline void ligate_input (hb_appl if (last_lig_id == _hb_glyph_info_get_lig_id (&buffer->info[i])) { unsigned int new_lig_comp = components_so_far - last_num_components + MIN (MAX (_hb_glyph_info_get_lig_comp (&buffer->info[i]), 1u), last_num_components); _hb_glyph_info_set_lig_props_for_mark (&buffer->info[i], lig_id, new_lig_comp); } else break; } } - TRACE_RETURN (true); + return_trace (true); } static inline bool match_backtrack (hb_apply_context_t *c, unsigned int count, const USHORT backtrack[], match_func_t match_func, const void *match_data) { TRACE_APPLY (NULL); hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context; skippy_iter.reset (c->buffer->backtrack_len (), count); skippy_iter.set_match_func (match_func, match_data, backtrack); for (unsigned int i = 0; i < count; i++) if (!skippy_iter.prev ()) - return TRACE_RETURN (false); + return_trace (false); - return TRACE_RETURN (true); + return_trace (true); } static inline bool match_lookahead (hb_apply_context_t *c, unsigned int count, const USHORT lookahead[], match_func_t match_func, const void *match_data, unsigned int offset) @@ -916,29 +904,29 @@ static inline bool match_lookahead (hb_a TRACE_APPLY (NULL); hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context; skippy_iter.reset (c->buffer->idx + offset - 1, count); skippy_iter.set_match_func (match_func, match_data, lookahead); for (unsigned int i = 0; i < count; i++) if (!skippy_iter.next ()) - return TRACE_RETURN (false); + return_trace (false); - return TRACE_RETURN (true); + return_trace (true); } struct LookupRecord { inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return TRACE_RETURN (c->check_struct (this)); + return_trace (c->check_struct (this)); } USHORT sequenceIndex; /* Index into current glyph * sequence--first glyph = 0 */ USHORT lookupListIndex; /* Lookup to apply to that * position--zero--based */ public: DEFINE_SIZE_STATIC (4); @@ -1029,17 +1017,17 @@ static inline bool apply_lookup (hb_appl /* And fixup the rest. */ for (; next < count; next++) match_positions[next] += delta; } buffer->move_to (end); - return TRACE_RETURN (true); + return_trace (true); } /* Contextual lookups */ struct ContextClosureLookupContext { @@ -1138,24 +1126,24 @@ struct Rule lookupCount, lookupRecord, lookup_context); } inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const { TRACE_WOULD_APPLY (this); const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (inputZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0)); - return TRACE_RETURN (context_would_apply_lookup (c, inputCount, inputZ, lookupCount, lookupRecord, lookup_context)); + return_trace (context_would_apply_lookup (c, inputCount, inputZ, lookupCount, lookupRecord, lookup_context)); } inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const { TRACE_APPLY (this); const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (inputZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0)); - return TRACE_RETURN (context_apply_lookup (c, inputCount, inputZ, lookupCount, lookupRecord, lookup_context)); + return_trace (context_apply_lookup (c, inputCount, inputZ, lookupCount, lookupRecord, lookup_context)); } public: inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return inputCount.sanitize (c) && lookupCount.sanitize (c) @@ -1197,37 +1185,37 @@ struct RuleSet inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const { TRACE_WOULD_APPLY (this); unsigned int num_rules = rule.len; for (unsigned int i = 0; i < num_rules; i++) { if ((this+rule[i]).would_apply (c, lookup_context)) - return TRACE_RETURN (true); + return_trace (true); } - return TRACE_RETURN (false); + return_trace (false); } inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const { TRACE_APPLY (this); unsigned int num_rules = rule.len; for (unsigned int i = 0; i < num_rules; i++) { if ((this+rule[i]).apply (c, lookup_context)) - return TRACE_RETURN (true); + return_trace (true); } - return TRACE_RETURN (false); + return_trace (false); } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return TRACE_RETURN (rule.sanitize (c, this)); + return_trace (rule.sanitize (c, this)); } protected: OffsetArrayOf<Rule> rule; /* Array of Rule tables * ordered by preference */ public: DEFINE_SIZE_ARRAY (2, rule); @@ -1274,43 +1262,43 @@ struct ContextFormat1 { TRACE_WOULD_APPLY (this); const RuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])]; struct ContextApplyLookupContext lookup_context = { {match_glyph}, NULL }; - return TRACE_RETURN (rule_set.would_apply (c, lookup_context)); + return_trace (rule_set.would_apply (c, lookup_context)); } inline const Coverage &get_coverage (void) const { return this+coverage; } inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (this); unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); if (likely (index == NOT_COVERED)) - return TRACE_RETURN (false); + return_trace (false); const RuleSet &rule_set = this+ruleSet[index]; struct ContextApplyLookupContext lookup_context = { {match_glyph}, NULL }; - return TRACE_RETURN (rule_set.apply (c, lookup_context)); + return_trace (rule_set.apply (c, lookup_context)); } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return TRACE_RETURN (coverage.sanitize (c, this) && ruleSet.sanitize (c, this)); + return_trace (coverage.sanitize (c, this) && ruleSet.sanitize (c, this)); } protected: USHORT format; /* Format identifier--format = 1 */ OffsetTo<Coverage> coverage; /* Offset to Coverage table--from * beginning of table */ OffsetArrayOf<RuleSet> @@ -1366,44 +1354,44 @@ struct ContextFormat2 const ClassDef &class_def = this+classDef; unsigned int index = class_def.get_class (c->glyphs[0]); const RuleSet &rule_set = this+ruleSet[index]; struct ContextApplyLookupContext lookup_context = { {match_class}, &class_def }; - return TRACE_RETURN (rule_set.would_apply (c, lookup_context)); + return_trace (rule_set.would_apply (c, lookup_context)); } inline const Coverage &get_coverage (void) const { return this+coverage; } inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (this); unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); - if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); + if (likely (index == NOT_COVERED)) return_trace (false); const ClassDef &class_def = this+classDef; index = class_def.get_class (c->buffer->cur().codepoint); const RuleSet &rule_set = this+ruleSet[index]; struct ContextApplyLookupContext lookup_context = { {match_class}, &class_def }; - return TRACE_RETURN (rule_set.apply (c, lookup_context)); + return_trace (rule_set.apply (c, lookup_context)); } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return TRACE_RETURN (coverage.sanitize (c, this) && classDef.sanitize (c, this) && ruleSet.sanitize (c, this)); + return_trace (coverage.sanitize (c, this) && classDef.sanitize (c, this) && ruleSet.sanitize (c, this)); } protected: USHORT format; /* Format identifier--format = 2 */ OffsetTo<Coverage> coverage; /* Offset to Coverage table--from * beginning of table */ OffsetTo<ClassDef> @@ -1457,49 +1445,49 @@ struct ContextFormat3 { TRACE_WOULD_APPLY (this); const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount); struct ContextApplyLookupContext lookup_context = { {match_coverage}, this }; - return TRACE_RETURN (context_would_apply_lookup (c, glyphCount, (const USHORT *) (coverageZ + 1), lookupCount, lookupRecord, lookup_context)); + return_trace (context_would_apply_lookup (c, glyphCount, (const USHORT *) (coverageZ + 1), lookupCount, lookupRecord, lookup_context)); } inline const Coverage &get_coverage (void) const { return this+coverageZ[0]; } inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (this); unsigned int index = (this+coverageZ[0]).get_coverage (c->buffer->cur().codepoint); - if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); + if (likely (index == NOT_COVERED)) return_trace (false); const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount); struct ContextApplyLookupContext lookup_context = { {match_coverage}, this }; - return TRACE_RETURN (context_apply_lookup (c, glyphCount, (const USHORT *) (coverageZ + 1), lookupCount, lookupRecord, lookup_context)); + return_trace (context_apply_lookup (c, glyphCount, (const USHORT *) (coverageZ + 1), lookupCount, lookupRecord, lookup_context)); } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - if (!c->check_struct (this)) return TRACE_RETURN (false); + if (!c->check_struct (this)) return_trace (false); unsigned int count = glyphCount; - if (!count) return TRACE_RETURN (false); /* We want to access coverageZ[0] freely. */ - if (!c->check_array (coverageZ, coverageZ[0].static_size, count)) return TRACE_RETURN (false); + if (!count) return_trace (false); /* We want to access coverageZ[0] freely. */ + if (!c->check_array (coverageZ, coverageZ[0].static_size, count)) return_trace (false); for (unsigned int i = 0; i < count; i++) - if (!coverageZ[i].sanitize (c, this)) return TRACE_RETURN (false); + if (!coverageZ[i].sanitize (c, this)) return_trace (false); const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * count); - return TRACE_RETURN (c->check_array (lookupRecord, lookupRecord[0].static_size, lookupCount)); + return_trace (c->check_array (lookupRecord, lookupRecord[0].static_size, lookupCount)); } protected: USHORT format; /* Format identifier--format = 3 */ USHORT glyphCount; /* Number of glyphs in the input glyph * sequence */ USHORT lookupCount; /* Number of LookupRecords */ OffsetTo<Coverage> @@ -1512,22 +1500,22 @@ struct ContextFormat3 }; struct Context { template <typename context_t> inline typename context_t::return_t dispatch (context_t *c) const { TRACE_DISPATCH (this, u.format); - if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ()); + if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); switch (u.format) { - case 1: return TRACE_RETURN (c->dispatch (u.format1)); - case 2: return TRACE_RETURN (c->dispatch (u.format2)); - case 3: return TRACE_RETURN (c->dispatch (u.format3)); - default:return TRACE_RETURN (c->default_return_value ()); + case 1: return_trace (c->dispatch (u.format1)); + case 2: return_trace (c->dispatch (u.format2)); + case 3: return_trace (c->dispatch (u.format3)); + default:return_trace (c->default_return_value ()); } } protected: union { USHORT format; /* Format identifier */ ContextFormat1 format1; ContextFormat2 format2; @@ -1682,46 +1670,46 @@ struct ChainRule } inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const { TRACE_WOULD_APPLY (this); const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack); const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input); const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); - return TRACE_RETURN (chain_context_would_apply_lookup (c, - backtrack.len, backtrack.array, - input.len, input.array, - lookahead.len, lookahead.array, lookup.len, - lookup.array, lookup_context)); + return_trace (chain_context_would_apply_lookup (c, + backtrack.len, backtrack.array, + input.len, input.array, + lookahead.len, lookahead.array, lookup.len, + lookup.array, lookup_context)); } inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const { TRACE_APPLY (this); const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack); const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input); const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); - return TRACE_RETURN (chain_context_apply_lookup (c, - backtrack.len, backtrack.array, - input.len, input.array, - lookahead.len, lookahead.array, lookup.len, - lookup.array, lookup_context)); + return_trace (chain_context_apply_lookup (c, + backtrack.len, backtrack.array, + input.len, input.array, + lookahead.len, lookahead.array, lookup.len, + lookup.array, lookup_context)); } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - if (!backtrack.sanitize (c)) return TRACE_RETURN (false); + if (!backtrack.sanitize (c)) return_trace (false); const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack); - if (!input.sanitize (c)) return TRACE_RETURN (false); + if (!input.sanitize (c)) return_trace (false); const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input); - if (!lookahead.sanitize (c)) return TRACE_RETURN (false); + if (!lookahead.sanitize (c)) return_trace (false); const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); - return TRACE_RETURN (lookup.sanitize (c)); + return_trace (lookup.sanitize (c)); } protected: ArrayOf<USHORT> backtrack; /* Array of backtracking values * (to be matched before the input * sequence) */ HeadlessArrayOf<USHORT> @@ -1756,36 +1744,36 @@ struct ChainRuleSet } inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const { TRACE_WOULD_APPLY (this); unsigned int num_rules = rule.len; for (unsigned int i = 0; i < num_rules; i++) if ((this+rule[i]).would_apply (c, lookup_context)) - return TRACE_RETURN (true); + return_trace (true); - return TRACE_RETURN (false); + return_trace (false); } inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const { TRACE_APPLY (this); unsigned int num_rules = rule.len; for (unsigned int i = 0; i < num_rules; i++) if ((this+rule[i]).apply (c, lookup_context)) - return TRACE_RETURN (true); + return_trace (true); - return TRACE_RETURN (false); + return_trace (false); } inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return TRACE_RETURN (rule.sanitize (c, this)); + return_trace (rule.sanitize (c, this)); } protected: OffsetArrayOf<ChainRule> rule; /* Array of ChainRule tables * ordered by preference */ public: DEFINE_SIZE_ARRAY (2, rule); @@ -1830,42 +1818,42 @@ struct ChainContextFormat1 { TRACE_WOULD_APPLY (this); const ChainRuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])]; struct ChainContextApplyLookupContext lookup_context = { {match_glyph}, {NULL, NULL, NULL} }; - return TRACE_RETURN (rule_set.would_apply (c, lookup_context)); + return_trace (rule_set.would_apply (c, lookup_context)); } inline const Coverage &get_coverage (void) const { return this+coverage; } inline bool apply (hb_apply_context_t *c) const { TRACE_APPLY (this); unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); - if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); + if (likely (index == NOT_COVERED)) return_trace (false); const ChainRuleSet &rule_set = this+ruleSet[index]; struct ChainContextApplyLookupContext lookup_context = { {match_glyph}, {NULL, NULL, NULL} }; - return TRACE_RETURN (rule_set.apply (c, lookup_context)); + return_trace (rule_set.apply (c, lookup_context)); } inline bool sanitize (hb_sanitize_context_t *c) const {