From 159d7b9c2f922e34ed05805acc4acbd3603b8862 Mon Sep 17 00:00:00 2001 From: roytam1 Date: Thu, 20 Jul 2023 11:53:14 +0800 Subject: [PATCH] import changes from `dev' branch of rmottola/Arctic-Fox: - Bug 967693 - Temporarily turn on HTTP cache v2 on for Desktop Firefox Nightly users, r=jduell+ehsan (0fb43bca09) - Bug 1230939 - check the return of sGlobalEntryTables->Get(aContextKey, &diskEntries). r=mayhemer (da62f5bd04) - fix header include (52d6efa786) - Bug 1193605 - Part 3: do not stop non-started service; r=mcmanus (dfe2187f22) - Bug 1193605 - Part 4: add UUID for listeners; r=mcmanus (fee78fd19d) - Bug 1214176 - fix typo in _onOffer. r=junior. (b388d1f2a6) - align test to 1216398 (74d505d1d6) - Bug 1228457 create pref to allow blocking .onion at dns level rfc 7687 r=valentin.gosu (521aab1e58) - Bug 1216370 - For safety and searchability, define the nsHostResolver::RES_* enum in terms of the nsIDNSService::RESOLVE_* enum. r=mayhemer (84c22f815f) - Bug 1194763 - Ensure non-cluster-start flag is set properly for a run-initial supplementary-plane combining mark when shaping text. r=jdaggett (17c3ad163d) - Bug 1168176 - Mark gfxFontShaper::mFont as MOZ_NON_OWNING_REF. r=jtd (0f3ca78c16) - Bug 1167403 - Mark gfxFont::GlyphChangeObserver::mFont as MOZ_NON_OWNING_REF. r=jtd (ec77538943) - align gfxContext to pre-1232822 (part 6) (bb7fa256c9) - Bug 1231889 - Moz2Dify gfxWindowsNativeDrawing::PaintToContext(). r=mattwoodrow. (69b1d62395) - Bug 1231864 (part 1) - Remove useless GetCairo() call in gfxWindowsNativeDrawing::BeginNativeDrawing(). r=mattwoodrow. (aa3017c392) - Bug 1231864 (part 2) - Clean up gfxWindowsNativeDrawing::BeginNativeDrawing(). r=mattwoodrow. (860a81ba59) - Bug 1225682 - Don't use nsAuto{,C}String as class member variables in gfx/. r=jrmuizel (a1cc11b749) - Bug 1230611 - Make gfxWindowsPlatform::SupportsApzTouchInput use a pref cache to speed it up. r=dvander (4026e5dfe8) - Bug 1193842 - Delete touch resampling preference and non resampling paths. r=kats (ff58c7753c) - Bug 1177335 - Skip resampling if the time difference of touches is less than 2ms. (b98e40343d) - Bug 1204518 - Fix warnings in widget/gonk/. r=mwu. (ddc13a4c24) - Bug 1231832. Make IsActive work on Querys that have not begun. r=jgilbert (4b70a8fb0b) - Bug 1218881. Enforce queries' new availability semantics. r=jgilbert (503bf80f8b) - Bug 1233858 - Part 1 - ensure Skia's SkGraphics::Init is called from gfxPlatform::Init. r=jmuizelaar (db5fde96b1) - Bug 1233858 -Part 2 - implement runtime-detected SSE2 optimizations for Skia. r=jmuizelaar (3c9ebaa64d) - Bug 1233858 - work around Skia __vectorcall bugs on Win32. r=jmuizelaar (b5b5e2bbcf) - Bug 1222569 - remove unused function from gfxPlatformFontList.cpp; r=Bas (68e1615eb2) - Bug 1234566: Use LoadLibraryA instead of LoadLibrary in some skia Windows code to allow UNICODE to be defined. r=lsalzman (e45bf51ef7) - Bug 1156742 Part 1: Change Moz2D recording, so that it can be used in isolation. r=bas (f02fd4992b) - Bug 1156742 Part 2: Make gfx thebes/gl/2d work with UNICODE defined. r=bas, r=glandium (8fca45d9a3) - Bug 1156742 Part 3: Add support for FontType::CAIRO to CreateScaledFontForTrueTypeData on Windows. r=bas (863ea539c4) - Bug 1156742 Part 4: Add an in memory DrawEventRecorder. r=bas (c9196512a1) - Bug 1156742 Part 5: Add a skeleton RemotePrintJob. r=mconley (aa48df9f32) - Bug 1156742 Part 6: Add RemotePrintJob to PrintSession and PrintData. r=roc, r=mconley (607a3e6b9b) - Bug 1233444 - add override declarations for widget/windows/; r=roc (edab847cb0) - Bug 1156742 Part 7: Refactor nsDeviceContext.cpp to use printing surface for size and nsIDeviceContextSpec for DPI and scale. r=roc (ec6ff3d592) - Bug 1156742 Part 8: Change gfxWindowsSurface, so that a non-printing surface can be used when recording a print. r=roc (1ab167635e) - Bug 1156742 Part 9: Add a new nsIDeviceContextSpec for proxied printing. r=roc (11c3909a8f) - Bug 1156742 Part 10: Allow RemotePrintJob to influence nsPagePrintTimer. r=roc (c658e96338) - Bug 1156742 Part 11: Allow RemotePrintJobChild to abort the print. r=roc (30f3e9bce4) - Bug 1156742 Part 12: Record CreateSimilarDrawTarget separately for Moz2D. r=bas (a978b691c3) - Bug 1156742 Part 13: Create a Moz2D PrintTranslator. r=bas (1eca4e9b33) - Bug 1156742 Part 14: Complete RemotePrintJob using PrintTranslator. r=mconley (7db80f0ba7) - Bug 1156742 Part 15: Add pref for turning on printing via the parent process. r=mconley (e3dbf281ea) - Bug 1156742 Part 16: Add recording and forwarding of Matrix attribute set for Moz2D recording. r=bas (cd5da598ea) - Bug 1156742 Part 17: Add virtual destructor to RecorededEvent and fix subsequent crash with DWrite playback fonts. r=bas (c20a0b84fc) - Bug 1156742 Part 18: Fix the way we hold custom font data so that they can be recorded with Moz2D. r=bas (54b4630927) - Bug 1156742 Part 19: Implement GetFontFileData for ScaledFontWin. r=bas (f1df40b31b) - Bug 1156742 Part 20: Move Moz2D PreferenceAccess into its own header. r=bas (0afdff8e14) - Bug 1156742 Part 21: Use GetDirect3D11Device instead of DrawTargetD2D::GetDWriteFactory to determine if DWrite fonts should be used. r=Bas (0c87a5866d) - Bug 1156742 Part 22: Change ScaledFontDWrite to support creation from TrueType Collection data. r=bas (5f2c607e64) - Bug 1156742 Part 23: Assert in PrintTranslator when a lookup fails. r=bas (72e24c789f) - Bug 1156742 Part 24: Add new Recorded event to record font data. r=bas (a0c6f951aa) - Bug 1156742 Part 25: Flip the big switch and wait for the lightning. r=mconley (082a1a3ede) - Bug 1203232 - Fix -Wshadow warnings in some ipc/chromium headers. r=njn (018499b8a1) - Bug 1089837 - Make IPC::Message use MOZ_COUNT_CTOR/DTOR. r=jld (124e011902) - Bug 1235234 - Fix unintentional switch fallthrough in ipc/chromium/ found by -Wimplicit-fallthrough warning. r=gcp (af37d85c1c) - Bug 1207498 - Part 2: Remove use of expression closure from tests in toolkit/components/. r=Gijs (98915956bd) - Bug 1157282 - Add test coverage for telemetry histogram recording. r=gfritzsche (f403b07c7f) - Bug 1228147: part 1: Add telemetry RecordingEnabled support. r=gfritzsche f=froydnj (610c92394f) - Bug 1228147: part 2: Add telemetry probe for synchronous scroll. r=kats (6816099c37) - Bug 1201492 - Remove extended_statistics_ok from Telemetry histograms. r=dexter (f7f991249f) - Bug 842894 - Support DirectWrite using the Skia backend. r=bas (f2487cf863) --- b2g/app/b2g.js | 6 - dom/canvas/WebGL2ContextQueries.cpp | 8 + dom/canvas/WebGLQuery.cpp | 4 + dom/canvas/WebGLQuery.h | 18 +- .../provider/TCPPresentationServer.js | 2 +- .../test_multicast_dns_device_provider.js | 227 +---------- .../printingui/ipc/PPrintSettingsDialog.ipdl | 1 + .../components/printingui/ipc/PPrinting.ipdl | 3 + .../printingui/ipc/PPrintingTypes.ipdlh | 3 + .../printingui/ipc/PrintingParent.cpp | 22 +- .../printingui/ipc/PrintingParent.h | 11 +- .../printingui/ipc/nsPrintingProxy.cpp | 20 +- .../printingui/ipc/nsPrintingProxy.h | 12 + gfx/2d/2D.h | 46 ++- gfx/2d/AutoHelpersWin.h | 86 +++++ gfx/2d/BigEndianInts.h | 80 ++++ gfx/2d/DrawEventRecorder.cpp | 50 ++- gfx/2d/DrawEventRecorder.h | 70 +++- gfx/2d/DrawTargetRecording.cpp | 268 +++++++++---- gfx/2d/DrawTargetRecording.h | 16 +- gfx/2d/DrawTargetSkia.cpp | 3 +- gfx/2d/Factory.cpp | 69 ++-- gfx/2d/Logging.h | 34 +- gfx/2d/NativeFontResourceDWrite.cpp | 287 ++++++++++++++ gfx/2d/NativeFontResourceDWrite.h | 56 +++ gfx/2d/NativeFontResourceGDI.cpp | 112 ++++++ gfx/2d/NativeFontResourceGDI.h | 57 +++ gfx/2d/PathRecording.cpp | 2 +- gfx/2d/Preferences.cpp | 60 +++ gfx/2d/Preferences.h | 34 ++ gfx/2d/RecordedEvent.cpp | 141 +++++-- gfx/2d/RecordedEvent.h | 122 +++++- gfx/2d/SFNTData.cpp | 240 ++++++++++++ gfx/2d/SFNTData.h | 93 +++++ gfx/2d/SFNTNameTable.cpp | 257 +++++++++++++ gfx/2d/SFNTNameTable.h | 67 ++++ gfx/2d/ScaledFontBase.cpp | 27 ++ gfx/2d/ScaledFontBase.h | 3 + gfx/2d/ScaledFontDWrite.cpp | 260 ++----------- gfx/2d/ScaledFontDWrite.h | 24 +- gfx/2d/ScaledFontWin.cpp | 70 +++- gfx/2d/ScaledFontWin.h | 13 +- gfx/2d/moz.build | 16 +- gfx/2d/u16string.h | 24 ++ gfx/gl/moz.build | 3 - gfx/skia/generate_mozbuild.py | 7 + gfx/skia/moz.build | 7 + gfx/skia/skia/include/ports/SkTypeface_win.h | 11 + gfx/skia/skia/src/core/SkOpts.cpp | 2 + .../gl/win/GrGLCreateNativeInterface_win.cpp | 2 +- gfx/skia/skia/src/opts/SkOpts_sse2.cpp | 44 +++ gfx/skia/skia/src/opts/SkXfermode_opts.h | 69 ++-- gfx/skia/skia/src/ports/SkFontHost_win.cpp | 13 + gfx/skia/skia/src/ports/SkOSLibrary_win.cpp | 2 +- gfx/src/nsDeviceContext.cpp | 79 +--- gfx/src/nsDeviceContext.h | 6 +- gfx/thebes/gfxContext.cpp | 46 ++- gfx/thebes/gfxContext.h | 6 +- gfx/thebes/gfxDWriteCommon.cpp | 190 +++++++-- gfx/thebes/gfxDWriteCommon.h | 82 +--- gfx/thebes/gfxDWriteFontList.cpp | 56 ++- gfx/thebes/gfxDWriteFontList.h | 13 +- gfx/thebes/gfxDWriteFonts.cpp | 30 +- gfx/thebes/gfxDWriteFonts.h | 2 + gfx/thebes/gfxFT2FontBase.cpp | 5 +- gfx/thebes/gfxFont.cpp | 18 +- gfx/thebes/gfxFont.h | 10 +- gfx/thebes/gfxFontEntry.cpp | 3 +- gfx/thebes/gfxGDIFont.cpp | 2 +- gfx/thebes/gfxGDIFontList.cpp | 6 +- gfx/thebes/gfxGradientCache.cpp | 8 +- gfx/thebes/gfxGradientCache.h | 2 +- gfx/thebes/gfxMacFont.cpp | 3 +- gfx/thebes/gfxPlatform.cpp | 4 + gfx/thebes/gfxPlatformFontList.cpp | 18 - gfx/thebes/gfxPrefs.cpp | 2 +- gfx/thebes/gfxPrefs.h | 4 +- gfx/thebes/gfxSVGGlyphs.h | 2 +- gfx/thebes/gfxWindowsNativeDrawing.cpp | 59 +-- gfx/thebes/gfxWindowsNativeDrawing.h | 2 +- gfx/thebes/gfxWindowsPlatform.cpp | 6 +- gfx/thebes/gfxWindowsSurface.cpp | 29 +- gfx/thebes/gfxWindowsSurface.h | 2 - gfx/thebes/moz.build | 3 - ipc/chromium/src/base/hash_tables.h | 18 + ipc/chromium/src/base/histogram.cc | 22 +- ipc/chromium/src/base/histogram.h | 15 +- ipc/chromium/src/base/message_loop.h | 10 +- ipc/chromium/src/base/process.h | 6 +- ipc/chromium/src/base/process_util_mac.mm | 1 + ipc/chromium/src/base/revocable_store.h | 4 +- ipc/chromium/src/base/string_piece.h | 8 +- ipc/chromium/src/base/tracked.h | 8 +- .../src/chrome/common/child_process_info.h | 8 +- ipc/chromium/src/chrome/common/ipc_message.cc | 14 +- ipc/chromium/src/chrome/common/ipc_message.h | 8 +- layout/base/nsRefreshDriver.cpp | 10 +- layout/generic/nsGfxScrollFrame.cpp | 12 +- layout/media/symbols.def.in | 1 + layout/printing/PrintTranslator.cpp | 102 +++++ layout/printing/PrintTranslator.h | 178 +++++++++ layout/printing/ipc/PRemotePrintJob.ipdl | 47 +++ layout/printing/ipc/RemotePrintJobChild.cpp | 102 +++++ layout/printing/ipc/RemotePrintJobChild.h | 58 +++ layout/printing/ipc/RemotePrintJobParent.cpp | 165 ++++++++ layout/printing/ipc/RemotePrintJobParent.h | 59 +++ layout/printing/moz.build | 15 +- layout/printing/nsPagePrintTimer.cpp | 51 ++- layout/printing/nsPagePrintTimer.h | 4 + layout/printing/nsPrintEngine.cpp | 34 +- modules/libpref/init/all.js | 14 + netwerk/cache2/CacheObserver.cpp | 9 +- netwerk/cache2/CacheStorageService.cpp | 3 +- .../dns/mdns/libmdns/nsDNSServiceDiscovery.h | 2 +- .../dns/mdns/libmdns/nsDNSServiceDiscovery.js | 62 ++- netwerk/dns/nsDNSService2.cpp | 54 ++- netwerk/dns/nsDNSService2.h | 6 + netwerk/dns/nsHostResolver.h | 19 +- netwerk/test/unit/test_dns_onion.js | 70 ++++ netwerk/test/unit/xpcshell.ini | 1 + .../contentprefs/tests/unit_cps2/head.js | 8 +- .../tests/unit_cps2/test_getCached.js | 16 +- .../unit_cps2/test_getCachedSubdomains.js | 12 +- .../tests/unit_cps2/test_getSubdomains.js | 15 +- .../tests/unit_cps2/test_remove.js | 24 +- .../tests/unit_cps2/test_removeAllDomains.js | 2 +- .../unit_cps2/test_removeAllDomainsSince.js | 2 +- .../tests/unit_cps2/test_removeByDomain.js | 14 +- .../tests/unit_cps2/test_removeByName.js | 6 +- .../tests/unit_cps2/test_setGet.js | 38 +- .../test/browser/browser_download_history.js | 4 +- .../osfile/tests/xpcshell/test_path.js | 8 +- .../test/browser/browser_passwordmgrdlg.js | 2 +- .../passwordmgr/test/test_zzz_finish.html | 2 +- .../tests/autocomplete/head_autocomplete.js | 8 +- .../places/tests/autocomplete/test_enabled.js | 4 +- .../autocomplete/test_match_beginning.js | 4 +- .../tests/autocomplete/test_special_search.js | 28 +- .../autocomplete/test_word_boundary_search.js | 4 +- .../places/tests/bookmarks/test_675416.js | 4 +- .../places/tests/bookmarks/test_711914.js | 4 +- .../bookmarks/test_nsINavBookmarkObserver.js | 361 +++++++++--------- ...ser_favicon_privatebrowsing_perwindowpb.js | 2 +- ...owser_favicon_setAndFetchFaviconForPage.js | 2 +- ...icon_setAndFetchFaviconForPage_failures.js | 2 +- ...er_visituri_privatebrowsing_perwindowpb.js | 2 +- .../components/places/tests/head_common.js | 4 +- .../places/tests/inline/head_autocomplete.js | 4 +- .../queries/test_containersQueries_sorting.js | 4 +- .../tests/queries/test_querySerialization.js | 4 +- .../places/tests/queries/test_redirects.js | 10 +- .../queries/test_sort-date-site-grouping.js | 4 +- .../places/tests/queries/test_tags.js | 8 +- .../tests/test_bug_461710_perwindowpb.html | 2 +- .../unifiedcomplete/head_autocomplete.js | 4 +- .../places/tests/unit/test_000_frecency.js | 4 +- .../places/tests/unit/test_408221.js | 2 +- .../places/tests/unit/test_adaptive.js | 50 ++- .../tests/unit/test_adaptive_bug527311.js | 2 +- .../tests/unit/test_async_transactions.js | 4 +- .../test_autocomplete_stopSearch_no_throw.js | 2 +- .../test_bookmarks_restore_notification.js | 8 +- .../places/tests/unit/test_browserhistory.js | 2 +- .../unit/test_history_autocomplete_tags.js | 50 +-- .../places/tests/unit/test_telemetry.js | 4 +- .../browser_privbrowsing_perwindowpb.js | 2 +- .../satchel/test/test_bug_787624.html | 2 +- .../satchel/test/unit/head_satchel.js | 4 +- .../satchel/test/unit/test_history_api.js | 34 +- .../components/social/test/xpcshell/head.js | 2 +- .../test/xpcshell/test_SocialService.js | 2 +- toolkit/components/telemetry/Histograms.json | 337 ++-------------- toolkit/components/telemetry/Telemetry.cpp | 109 +++++- toolkit/components/telemetry/Telemetry.h | 10 + .../components/telemetry/TelemetrySession.jsm | 7 +- .../telemetry/gen-histogram-data.py | 3 +- .../components/telemetry/histogram_tools.py | 8 +- toolkit/components/telemetry/nsITelemetry.idl | 12 +- .../tests/unit/test_TelemetryStopwatch.js | 8 +- .../telemetry/tests/unit/test_nsITelemetry.js | 257 ++++++++++--- toolkit/components/thumbnails/test/head.js | 8 +- widget/cocoa/nsDeviceContextSpecX.h | 2 +- widget/cocoa/nsDeviceContextSpecX.mm | 2 +- widget/gonk/GeckoTouchDispatcher.cpp | 64 ++-- widget/gonk/GeckoTouchDispatcher.h | 1 + widget/gonk/GonkMemoryPressureMonitoring.cpp | 2 - widget/gonk/GonkPermission.cpp | 1 + widget/gonk/OrientationObserver.cpp | 10 +- widget/gonk/libui/InputDispatcher.cpp | 4 - widget/gonk/libui/InputReader.cpp | 8 +- widget/gonk/libui/Keyboard.cpp | 1 - widget/gonk/libui/SpriteController.cpp | 19 +- widget/gonk/nsAppShell.cpp | 1 + widget/gtk/nsDeviceContextSpecG.cpp | 6 +- widget/gtk/nsDeviceContextSpecG.h | 3 +- widget/moz.build | 2 + widget/nsDeviceContextSpecProxy.cpp | 178 +++++++++ widget/nsDeviceContextSpecProxy.h | 63 +++ widget/nsIDeviceContextSpec.h | 40 +- widget/nsIPrintSession.idl | 21 +- widget/nsPrimitiveHelpers.cpp | 5 +- widget/nsPrintOptionsImpl.cpp | 15 +- widget/nsPrintSession.cpp | 20 + widget/nsPrintSession.h | 12 + widget/qt/nsDeviceContextSpecQt.cpp | 2 +- widget/qt/nsDeviceContextSpecQt.h | 2 +- widget/windows/JumpListItem.h | 12 +- widget/windows/TaskbarWindowPreview.h | 14 +- widget/windows/nsClipboard.h | 8 +- widget/windows/nsDeviceContextSpecWin.cpp | 22 +- widget/windows/nsDeviceContextSpecWin.h | 20 +- widget/windows/nsIdleServiceWin.h | 4 +- widget/windows/nsNativeThemeWin.h | 22 +- widget/windows/nsWindow.h | 96 ++--- 214 files changed, 5200 insertions(+), 2119 deletions(-) create mode 100644 gfx/2d/AutoHelpersWin.h create mode 100644 gfx/2d/BigEndianInts.h create mode 100644 gfx/2d/NativeFontResourceDWrite.cpp create mode 100644 gfx/2d/NativeFontResourceDWrite.h create mode 100644 gfx/2d/NativeFontResourceGDI.cpp create mode 100644 gfx/2d/NativeFontResourceGDI.h create mode 100644 gfx/2d/Preferences.cpp create mode 100644 gfx/2d/Preferences.h create mode 100644 gfx/2d/SFNTData.cpp create mode 100644 gfx/2d/SFNTData.h create mode 100644 gfx/2d/SFNTNameTable.cpp create mode 100644 gfx/2d/SFNTNameTable.h create mode 100644 gfx/2d/u16string.h create mode 100644 gfx/skia/skia/src/opts/SkOpts_sse2.cpp create mode 100644 layout/printing/PrintTranslator.cpp create mode 100644 layout/printing/PrintTranslator.h create mode 100644 layout/printing/ipc/PRemotePrintJob.ipdl create mode 100644 layout/printing/ipc/RemotePrintJobChild.cpp create mode 100644 layout/printing/ipc/RemotePrintJobChild.h create mode 100644 layout/printing/ipc/RemotePrintJobParent.cpp create mode 100644 layout/printing/ipc/RemotePrintJobParent.h create mode 100644 netwerk/test/unit/test_dns_onion.js create mode 100644 widget/nsDeviceContextSpecProxy.cpp create mode 100644 widget/nsDeviceContextSpecProxy.h diff --git a/b2g/app/b2g.js b/b2g/app/b2g.js index 0f2c6ae426..093a04a707 100644 --- a/b2g/app/b2g.js +++ b/b2g/app/b2g.js @@ -1112,12 +1112,6 @@ pref("dom.mozSettings.allowForceReadOnly", false); // RequestSync API is enabled by default on B2G. pref("dom.requestSync.enabled", true); -// Use vsync aligned rendering -pref("gfx.vsync.hw-vsync.enabled", true); -pref("gfx.vsync.compositor", true); -pref("gfx.touch.resample", true); -pref("gfx.vsync.refreshdriver", true); - // Comma separated list of activity names that can only be provided by // the system app in dev mode. pref("dom.activities.developer_mode_only", "import-app"); diff --git a/dom/canvas/WebGL2ContextQueries.cpp b/dom/canvas/WebGL2ContextQueries.cpp index b3ffe264e6..1fec22d70e 100644 --- a/dom/canvas/WebGL2ContextQueries.cpp +++ b/dom/canvas/WebGL2ContextQueries.cpp @@ -6,6 +6,8 @@ #include "WebGL2Context.h" #include "GLContext.h" #include "WebGLQuery.h" +#include "gfxPrefs.h" +#include "nsThreadUtils.h" namespace mozilla { @@ -255,6 +257,7 @@ WebGL2Context::EndQuery(GLenum target) } UpdateBoundQuery(target, nullptr); + NS_DispatchToCurrentThread(new WebGLQuery::AvailableRunnable(activeQuery)); } already_AddRefed @@ -325,6 +328,11 @@ WebGL2Context::GetQueryParameter(JSContext*, WebGLQuery* query, GLenum pname, return; } + // We must wait for an event loop before the query can be available + if (!query->mCanBeAvailable && !gfxPrefs::WebGLImmediateQueries()) { + return; + } + MakeContextCurrent(); GLuint returned = 0; switch (pname) { diff --git a/dom/canvas/WebGLQuery.cpp b/dom/canvas/WebGLQuery.cpp index 63c92861ef..e557b8b450 100644 --- a/dom/canvas/WebGLQuery.cpp +++ b/dom/canvas/WebGLQuery.cpp @@ -20,6 +20,7 @@ WebGLQuery::WrapObject(JSContext* cx, JS::Handle givenProto) WebGLQuery::WebGLQuery(WebGLContext* webgl) : WebGLContextBoundObject(webgl) + , mCanBeAvailable(false) , mGLName(0) , mType(0) { @@ -40,6 +41,9 @@ WebGLQuery::Delete() bool WebGLQuery::IsActive() const { + if (!HasEverBeenActive()) + return false; + WebGLRefPtr& targetSlot = mContext->GetQuerySlotByTarget(mType); return targetSlot.get() == this; diff --git a/dom/canvas/WebGLQuery.h b/dom/canvas/WebGLQuery.h index 68a579786f..a9fbaabbbe 100644 --- a/dom/canvas/WebGLQuery.h +++ b/dom/canvas/WebGLQuery.h @@ -10,6 +10,7 @@ #include "nsWrapperCache.h" #include "WebGLObjectModel.h" +#include "nsThreadUtils.h" namespace mozilla { @@ -22,9 +23,22 @@ class WebGLQuery final public: explicit WebGLQuery(WebGLContext* webgl); + class AvailableRunnable final : public nsRunnable + { + public: + explicit AvailableRunnable(WebGLQuery* query) : mQuery(query) { } + + NS_IMETHOD Run() override { + mQuery->mCanBeAvailable = true; + return NS_OK; + } + private: + const RefPtr mQuery; + }; + bool IsActive() const; - bool HasEverBeenActive() { + bool HasEverBeenActive() const { return mType != 0; } @@ -42,6 +56,8 @@ public: NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLQuery) NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLQuery) + // Track whether the event loop has spun + bool mCanBeAvailable; private: ~WebGLQuery() { diff --git a/dom/presentation/provider/TCPPresentationServer.js b/dom/presentation/provider/TCPPresentationServer.js index 4256e88d35..af4502451a 100644 --- a/dom/presentation/provider/TCPPresentationServer.js +++ b/dom/presentation/provider/TCPPresentationServer.js @@ -608,7 +608,7 @@ TCPControlChannel.prototype = { return; } if (!this._listener) { - this._pendingOffer = offer; + this._pendingOffer = aOffer; return; } DEBUG && log("TCPControlChannel - notify offer: " diff --git a/dom/presentation/tests/xpcshell/test_multicast_dns_device_provider.js b/dom/presentation/tests/xpcshell/test_multicast_dns_device_provider.js index c4fb0562bc..77b59abaac 100644 --- a/dom/presentation/tests/xpcshell/test_multicast_dns_device_provider.js +++ b/dom/presentation/tests/xpcshell/test_multicast_dns_device_provider.js @@ -645,231 +645,6 @@ function noAddDevice() { run_next_test(); } -function handleSessionRequest() { - Services.prefs.setBoolPref(PREF_DISCOVERY, true); - - const testUrl = "http://example.com"; - const testPresentationId = "test-presentation-id"; - - let mockDevice = createDevice("device.local", - 12345, - "service.name", - "_mozilla_papi._tcp"); - let mockSDObj = { - QueryInterface: XPCOMUtils.generateQI([Ci.nsIDNSServiceDiscovery]), - startDiscovery: function(serviceType, listener) { - listener.onDiscoveryStarted(serviceType); - listener.onServiceFound(createDevice("", - 0, - mockDevice.serviceName, - mockDevice.serviceType)); - return { - QueryInterface: XPCOMUtils.generateQI([Ci.nsICancelable]), - cancel: function() {} - }; - }, - registerService: function(serviceInfo, listener) {}, - resolveService: function(serviceInfo, listener) { - listener.onServiceResolved(createDevice(mockDevice.host, - mockDevice.port, - mockDevice.serviceName, - mockDevice.serviceType)); - } - }; - - let mockServerObj = { - QueryInterface: XPCOMUtils.generateQI([Ci.nsITCPPresentationServer]), - requestSession: function(deviceInfo, url, presentationId) { - this.request = { - deviceInfo: deviceInfo, - url: url, - presentationId: presentationId, - }; - return { - QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlChannel]), - }; - }, - }; - - let contractHookSD = new ContractHook(SD_CONTRACT_ID, mockSDObj); - let contractHookServer = new ContractHook(SERVER_CONTRACT_ID, mockServerObj); - let provider = Cc[PROVIDER_CONTRACT_ID].createInstance(Ci.nsIPresentationDeviceProvider); - let listener = { - QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDeviceListener, - Ci.nsISupportsWeakReference]), - addDevice: function(device) { - this.device = device; - }, - }; - - provider.listener = listener; - - let controlChannel = listener.device.establishControlChannel(testUrl, testPresentationId); - - Assert.equal(mockServerObj.request.deviceInfo.id, mockDevice.host); - Assert.equal(mockServerObj.request.deviceInfo.host, mockDevice.host); - Assert.equal(mockServerObj.request.deviceInfo.port, mockDevice.port); - Assert.equal(mockServerObj.request.url, testUrl); - Assert.equal(mockServerObj.request.presentationId, testPresentationId); - - provider.listener = null; - - run_next_test(); -} - -function handleOnSessionRequest() { - Services.prefs.setBoolPref(PREF_DISCOVERY, true); - - let mockDevice = createDevice("device.local", - 12345, - "service.name", - "_mozilla_papi._tcp"); - let mockSDObj = { - QueryInterface: XPCOMUtils.generateQI([Ci.nsIDNSServiceDiscovery]), - startDiscovery: function(serviceType, listener) { - listener.onDiscoveryStarted(serviceType); - listener.onServiceFound(createDevice("", - 0, - mockDevice.serviceName, - mockDevice.serviceType)); - return { - QueryInterface: XPCOMUtils.generateQI([Ci.nsICancelable]), - cancel: function() {} - }; - }, - registerService: function(serviceInfo, listener) {}, - resolveService: function(serviceInfo, listener) { - listener.onServiceResolved(createDevice(mockDevice.host, - mockDevice.port, - mockDevice.serviceName, - mockDevice.serviceType)); - } - }; - - let mockServerObj = { - QueryInterface: XPCOMUtils.generateQI([Ci.nsITCPPresentationServer]), - startService: function() {}, - sessionRequest: function() {}, - close: function() {}, - id: '', - port: 0, - listener: null, - }; - - let contractHookSD = new ContractHook(SD_CONTRACT_ID, mockSDObj); - let contractHookServer = new ContractHook(SERVER_CONTRACT_ID, mockServerObj); - let provider = Cc[PROVIDER_CONTRACT_ID].createInstance(Ci.nsIPresentationDeviceProvider); - let listener = { - QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDeviceListener, - Ci.nsISupportsWeakReference]), - addDevice: function(device) {}, - removeDevice: function(device) {}, - updateDevice: function(device) {}, - onSessionRequest: function(device, url, presentationId, controlChannel) { - Assert.ok(true, "recieve onSessionRequest event"); - this.request = { - deviceId: device.id, - url: url, - presentationId: presentationId, - }; - } - }; - - provider.listener = listener; - - const deviceInfo = { - QueryInterface: XPCOMUtils.generateQI([Ci.nsITCPDeviceInfo]), - id: mockDevice.host, - host: mockDevice.host, - port: 54321, - }; - - const testUrl = "http://example.com"; - const testPresentationId = "test-presentation-id"; - const testControlChannel = { - QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlChannel]), - }; - provider.QueryInterface(Ci.nsITCPPresentationServerListener) - .onSessionRequest(deviceInfo, testUrl, testPresentationId, testControlChannel); - - Assert.equal(listener.request.deviceId, deviceInfo.id); - Assert.equal(listener.request.url, testUrl); - Assert.equal(listener.request.presentationId, testPresentationId); - - provider.listener = null; - - run_next_test(); -} - -function handleOnSessionRequestFromUnknownDevice() { - let mockSDObj = { - QueryInterface: XPCOMUtils.generateQI([Ci.nsIDNSServiceDiscovery]), - startDiscovery: function(serviceType, listener) {}, - registerService: function(serviceInfo, listener) {}, - resolveService: function(serviceInfo, listener) {} - }; - - let mockServerObj = { - QueryInterface: XPCOMUtils.generateQI([Ci.nsITCPPresentationServer]), - init: function() {}, - sessionRequest: function() {}, - close: function() {}, - id: '', - port: 0, - listener: null, - }; - - let contractHookSD = new ContractHook(SD_CONTRACT_ID, mockSDObj); - let contractHookServer = new ContractHook(SERVER_CONTRACT_ID, mockServerObj); - let provider = Cc[PROVIDER_CONTRACT_ID].createInstance(Ci.nsIPresentationDeviceProvider); - let listener = { - QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDeviceListener, - Ci.nsISupportsWeakReference]), - addDevice: function(device) { - Assert.ok(false, "shouldn't create any new device"); - }, - removeDevice: function(device) { - Assert.ok(false, "shouldn't remote any device"); - }, - updateDevice: function(device) { - Assert.ok(false, "shouldn't update any device"); - }, - onSessionRequest: function(device, url, presentationId, controlChannel) { - Assert.ok(true, "recieve onSessionRequest event"); - this.request = { - deviceId: device.id, - url: url, - presentationId: presentationId, - }; - } - }; - - provider.listener = listener; - - const deviceInfo = { - QueryInterface: XPCOMUtils.generateQI([Ci.nsITCPDeviceInfo]), - id: "unknown-device.local", - host: "unknown-device.local", - port: 12345, - }; - - const testUrl = "http://example.com"; - const testPresentationId = "test-presentation-id"; - const testControlChannel = { - QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationControlChannel]), - }; - provider.QueryInterface(Ci.nsITCPPresentationServerListener) - .onSessionRequest(deviceInfo, testUrl, testPresentationId, testControlChannel); - - Assert.equal(listener.request.deviceId, deviceInfo.id); - Assert.equal(listener.request.url, testUrl); - Assert.equal(listener.request.presentationId, testPresentationId); - - provider.listener = null; - - run_next_test(); -} - function ignoreSelfDevice() { Services.prefs.setBoolPref(PREF_DISCOVERY, false); Services.prefs.setBoolPref(PREF_DISCOVERABLE, true); @@ -913,7 +688,7 @@ function ignoreSelfDevice() { let mockServerObj = { QueryInterface: XPCOMUtils.generateQI([Ci.nsITCPPresentationServer]), - init: function() {}, + startService: function() {}, sessionRequest: function() {}, close: function() {}, id: '', diff --git a/embedding/components/printingui/ipc/PPrintSettingsDialog.ipdl b/embedding/components/printingui/ipc/PPrintSettingsDialog.ipdl index 91f29fde2a..95868e3e44 100644 --- a/embedding/components/printingui/ipc/PPrintSettingsDialog.ipdl +++ b/embedding/components/printingui/ipc/PPrintSettingsDialog.ipdl @@ -5,6 +5,7 @@ include PPrintingTypes; include protocol PPrinting; +include protocol PRemotePrintJob; namespace mozilla { namespace embedding { diff --git a/embedding/components/printingui/ipc/PPrinting.ipdl b/embedding/components/printingui/ipc/PPrinting.ipdl index f86f80b464..1aee578704 100644 --- a/embedding/components/printingui/ipc/PPrinting.ipdl +++ b/embedding/components/printingui/ipc/PPrinting.ipdl @@ -8,6 +8,7 @@ include protocol PContent; include protocol PBrowser; include protocol PPrintProgressDialog; include protocol PPrintSettingsDialog; +include protocol PRemotePrintJob; namespace mozilla { namespace embedding { @@ -17,6 +18,7 @@ sync protocol PPrinting manager PContent; manages PPrintProgressDialog; manages PPrintSettingsDialog; + manages PRemotePrintJob; parent: sync ShowProgress(PBrowser browser, @@ -37,6 +39,7 @@ parent: returns(nsresult rv); child: + async PRemotePrintJob(); __delete__(); }; diff --git a/embedding/components/printingui/ipc/PPrintingTypes.ipdlh b/embedding/components/printingui/ipc/PPrintingTypes.ipdlh index 5f6a2135a3..5a4d7a21c1 100644 --- a/embedding/components/printingui/ipc/PPrintingTypes.ipdlh +++ b/embedding/components/printingui/ipc/PPrintingTypes.ipdlh @@ -3,6 +3,8 @@ * 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/. */ +include protocol PRemotePrintJob; + namespace mozilla { namespace embedding { @@ -12,6 +14,7 @@ struct CStringKeyValue { }; struct PrintData { + nullable PRemotePrintJob remotePrintJob; int32_t startPageRange; int32_t endPageRange; double edgeTop; diff --git a/embedding/components/printingui/ipc/PrintingParent.cpp b/embedding/components/printingui/ipc/PrintingParent.cpp index 85ed1bd44e..804d3818b5 100644 --- a/embedding/components/printingui/ipc/PrintingParent.cpp +++ b/embedding/components/printingui/ipc/PrintingParent.cpp @@ -1,5 +1,5 @@ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* vim: set sw=4 ts=8 et tw=80 : */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ @@ -19,9 +19,11 @@ #include "PrintDataUtils.h" #include "PrintProgressDialogParent.h" #include "PrintSettingsDialogParent.h" +#include "mozilla/layout/RemotePrintJobParent.h" using namespace mozilla; using namespace mozilla::dom; +using namespace mozilla::layout; namespace mozilla { namespace embedding { @@ -102,6 +104,10 @@ PrintingParent::ShowPrintDialog(PBrowserParent* aParent, // And send it back. rv = po->SerializeToPrintData(settings, nullptr, aResult); + + PRemotePrintJobParent* remotePrintJob = new RemotePrintJobParent(settings); + aResult->remotePrintJobParent() = SendPRemotePrintJobConstructor(remotePrintJob); + return rv; } @@ -183,6 +189,20 @@ PrintingParent::DeallocPPrintSettingsDialogParent(PPrintSettingsDialogParent* aD return true; } +PRemotePrintJobParent* +PrintingParent::AllocPRemotePrintJobParent() +{ + MOZ_ASSERT_UNREACHABLE("No default constructors for implementations."); + return nullptr; +} + +bool +PrintingParent::DeallocPRemotePrintJobParent(PRemotePrintJobParent* aDoomed) +{ + delete aDoomed; + return true; +} + void PrintingParent::ActorDestroy(ActorDestroyReason aWhy) { diff --git a/embedding/components/printingui/ipc/PrintingParent.h b/embedding/components/printingui/ipc/PrintingParent.h index 47197c2965..f3a37b7b5e 100644 --- a/embedding/components/printingui/ipc/PrintingParent.h +++ b/embedding/components/printingui/ipc/PrintingParent.h @@ -15,6 +15,10 @@ class PPrintProgressDialogParent; class PPrintSettingsDialogParent; namespace mozilla { +namespace layout { +class PRemotePrintJobParent; +} + namespace embedding { class PrintingParent final : public PPrintingParent @@ -49,6 +53,12 @@ public: virtual bool DeallocPPrintSettingsDialogParent(PPrintSettingsDialogParent* aActor); + virtual PRemotePrintJobParent* + AllocPRemotePrintJobParent(); + + virtual bool + DeallocPRemotePrintJobParent(PRemotePrintJobParent* aActor); + virtual void ActorDestroy(ActorDestroyReason aWhy); @@ -69,4 +79,3 @@ private: } // namespace mozilla #endif - diff --git a/embedding/components/printingui/ipc/nsPrintingProxy.cpp b/embedding/components/printingui/ipc/nsPrintingProxy.cpp index 512fab24e7..1f414feda7 100644 --- a/embedding/components/printingui/ipc/nsPrintingProxy.cpp +++ b/embedding/components/printingui/ipc/nsPrintingProxy.cpp @@ -4,15 +4,17 @@ * 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/. */ +#include "nsPrintingProxy.h" + #include "mozilla/ClearOnShutdown.h" #include "mozilla/dom/ContentChild.h" #include "mozilla/dom/TabChild.h" +#include "mozilla/layout/RemotePrintJobChild.h" #include "mozilla/unused.h" #include "nsIDocShell.h" #include "nsIDocShellTreeOwner.h" #include "nsIPrintingPromptService.h" #include "nsPIDOMWindow.h" -#include "nsPrintingProxy.h" #include "nsPrintOptionsImpl.h" #include "PrintDataUtils.h" #include "PrintProgressDialogChild.h" @@ -20,6 +22,7 @@ using namespace mozilla; using namespace mozilla::dom; using namespace mozilla::embedding; +using namespace mozilla::layout; static StaticRefPtr sPrintingProxyInstance; @@ -233,3 +236,18 @@ nsPrintingProxy::DeallocPPrintSettingsDialogChild(PPrintSettingsDialogChild* aAc // will take itself out. return true; } + +PRemotePrintJobChild* +nsPrintingProxy::AllocPRemotePrintJobChild() +{ + RefPtr remotePrintJob = new RemotePrintJobChild(); + return remotePrintJob.forget().take(); +} + +bool +nsPrintingProxy::DeallocPRemotePrintJobChild(PRemotePrintJobChild* aDoomed) +{ + RemotePrintJobChild* remotePrintJob = static_cast(aDoomed); + NS_RELEASE(remotePrintJob); + return true; +} diff --git a/embedding/components/printingui/ipc/nsPrintingProxy.h b/embedding/components/printingui/ipc/nsPrintingProxy.h index 01a04ddb50..6b4d9cf5ae 100644 --- a/embedding/components/printingui/ipc/nsPrintingProxy.h +++ b/embedding/components/printingui/ipc/nsPrintingProxy.h @@ -9,6 +9,12 @@ #include "nsIPrintingPromptService.h" #include "mozilla/embedding/PPrintingChild.h" +namespace mozilla { +namespace layout { +class PRemotePrintJobChild; +} +} + class nsPrintingProxy: public nsIPrintingPromptService, public mozilla::embedding::PPrintingChild { @@ -39,6 +45,12 @@ public: virtual bool DeallocPPrintSettingsDialogChild(PPrintSettingsDialogChild* aActor) override; + + virtual PRemotePrintJobChild* + AllocPRemotePrintJobChild() override; + + virtual bool + DeallocPRemotePrintJobChild(PRemotePrintJobChild* aActor) override; }; #endif diff --git a/gfx/2d/2D.h b/gfx/2d/2D.h index 0dbd56595b..c7109a45b4 100644 --- a/gfx/2d/2D.h +++ b/gfx/2d/2D.h @@ -42,6 +42,9 @@ struct ID3D11Texture2D; struct ID3D11Device; struct ID2D1Device; struct IDWriteRenderingParams; +struct IDWriteFont; +struct IDWriteFontFamily; +struct IDWriteFontFace; class GrContext; @@ -667,6 +670,29 @@ protected: UserData mUserData; }; +/** + * Derived classes hold a native font resource from which to create + * ScaledFonts. + */ +class NativeFontResource : public RefCounted +{ +public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(NativeFontResource) + + /** + * Creates a ScaledFont using the font corresponding to the index and + * the given glyph size. + * + * @param aIndex index for the font within the resource. + * @param aGlyphSize the size of ScaledFont required. + * @return an already_addrefed ScaledFont, containing nullptr if failed. + */ + virtual already_AddRefed + CreateScaledFont(uint32_t aIndex, uint32_t aGlyphSize) = 0; + + virtual ~NativeFontResource() {}; +}; + /** This class is designed to allow passing additional glyph rendering * parameters to the glyph drawing functions. This is an empty wrapper class * merely used to allow holding on to and passing around platform specific @@ -703,6 +729,9 @@ public: virtual DrawTargetType GetType() const = 0; virtual BackendType GetBackendType() const = 0; + + virtual bool IsRecording() const { return false; } + /** * Returns a SourceSurface which is a snapshot of the current contents of the DrawTarget. * Multiple calls to Snapshot() without any drawing operations in between will @@ -1190,16 +1219,15 @@ public: CreateScaledFontForNativeFont(const NativeFont &aNativeFont, Float aSize); /** - * This creates a ScaledFont from TrueType data. + * This creates a NativeFontResource from TrueType data. * * @param aData Pointer to the data * @param aSize Size of the TrueType data - * @param aFaceIndex Index of the font face in the truetype data this ScaledFont needs to represent. - * @param aGlyphSize Size of the glyphs in this ScaledFont - * @param aType Type of ScaledFont that should be created. + * @param aType Type of NativeFontResource that should be created. + * @return a NativeFontResource of nullptr if failed. */ - static already_AddRefed - CreateScaledFontForTrueTypeData(uint8_t *aData, uint32_t aSize, uint32_t aFaceIndex, Float aGlyphSize, FontType aType); + static already_AddRefed + CreateNativeFontResource(uint8_t *aData, uint32_t aSize, FontType aType); /** * This creates a scaled font with an associated cairo_scaled_font_t, and @@ -1314,6 +1342,12 @@ public: static uint64_t GetD2DVRAMUsageSourceSurface(); static void D2DCleanup(); + static already_AddRefed + CreateScaledFontForDWriteFont(IDWriteFont* aFont, + IDWriteFontFamily* aFontFamily, + IDWriteFontFace* aFontFace, + Float aSize); + private: static ID2D1Device *mD2D1Device; static ID3D10Device1 *mD3D10Device; diff --git a/gfx/2d/AutoHelpersWin.h b/gfx/2d/AutoHelpersWin.h new file mode 100644 index 0000000000..744d0d5003 --- /dev/null +++ b/gfx/2d/AutoHelpersWin.h @@ -0,0 +1,86 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- +* 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/. */ + +#ifndef mozilla_gfx_AutoHelpersWin_h +#define mozilla_gfx_AutoHelpersWin_h + +#include + +namespace mozilla { +namespace gfx { + +// Get the global device context, and auto-release it on destruction. +class AutoDC +{ +public: + AutoDC() { + mDC = ::GetDC(nullptr); + } + + ~AutoDC() { + ::ReleaseDC(nullptr, mDC); + } + + HDC GetDC() { + return mDC; + } + +private: + HDC mDC; +}; + +// Select a font into the given DC, and auto-restore. +class AutoSelectFont +{ +public: + AutoSelectFont(HDC aDC, LOGFONTW *aLogFont) + : mOwnsFont(false) + { + mFont = ::CreateFontIndirectW(aLogFont); + if (mFont) { + mOwnsFont = true; + mDC = aDC; + mOldFont = (HFONT)::SelectObject(aDC, mFont); + } else { + mOldFont = nullptr; + } + } + + AutoSelectFont(HDC aDC, HFONT aFont) + : mOwnsFont(false) + { + mDC = aDC; + mFont = aFont; + mOldFont = (HFONT)::SelectObject(aDC, aFont); + } + + ~AutoSelectFont() { + if (mOldFont) { + ::SelectObject(mDC, mOldFont); + if (mOwnsFont) { + ::DeleteObject(mFont); + } + } + } + + bool IsValid() const { + return mFont != nullptr; + } + + HFONT GetFont() const { + return mFont; + } + +private: + HDC mDC; + HFONT mFont; + HFONT mOldFont; + bool mOwnsFont; +}; + +} // gfx +} // mozilla + +#endif // mozilla_gfx_AutoHelpersWin_h diff --git a/gfx/2d/BigEndianInts.h b/gfx/2d/BigEndianInts.h new file mode 100644 index 0000000000..70a76e1d5b --- /dev/null +++ b/gfx/2d/BigEndianInts.h @@ -0,0 +1,80 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_BigEndianInts_h +#define mozilla_BigEndianInts_h + +#include "mozilla/Endian.h" + +namespace mozilla { + +#pragma pack(push, 1) + +struct BigEndianUint16 +{ +#ifdef __SUNPRO_CC + BigEndianUint16& operator=(const uint16_t aValue) + { + value = NativeEndian::swapToBigEndian(aValue); + return *this; + } +#else + MOZ_IMPLICIT BigEndianUint16(const uint16_t aValue) + { + value = NativeEndian::swapToBigEndian(aValue); + } +#endif + + operator uint16_t() const + { + return NativeEndian::swapFromBigEndian(value); + } + + friend inline bool + operator==(const BigEndianUint16& lhs, const BigEndianUint16& rhs) + { + return lhs.value == rhs.value; + } + + friend inline bool + operator!=(const BigEndianUint16& lhs, const BigEndianUint16& rhs) + { + return !(lhs == rhs); + } + +private: + uint16_t value; +}; + +struct BigEndianUint32 +{ +#ifdef __SUNPRO_CC + BigEndianUint32& operator=(const uint32_t aValue) + { + value = NativeEndian::swapToBigEndian(aValue); + return *this; + } +#else + MOZ_IMPLICIT BigEndianUint32(const uint32_t aValue) + { + value = NativeEndian::swapToBigEndian(aValue); + } +#endif + + operator uint32_t() const + { + return NativeEndian::swapFromBigEndian(value); + } + +private: + uint32_t value; +}; + +#pragma pack(pop) + +} // mozilla + +#endif // mozilla_BigEndianInts_h \ No newline at end of file diff --git a/gfx/2d/DrawEventRecorder.cpp b/gfx/2d/DrawEventRecorder.cpp index bfabb127a6..1238344243 100644 --- a/gfx/2d/DrawEventRecorder.cpp +++ b/gfx/2d/DrawEventRecorder.cpp @@ -5,19 +5,26 @@ #include "DrawEventRecorder.h" #include "PathRecording.h" +#include "RecordingTypes.h" namespace mozilla { namespace gfx { using namespace std; -const uint32_t kMagicInt = 0xc001feed; - DrawEventRecorderPrivate::DrawEventRecorderPrivate(std::ostream *aStream) : mOutputStream(aStream) { } +void +DrawEventRecorderPrivate::WriteHeader() +{ + WriteElement(*mOutputStream, kMagicInt); + WriteElement(*mOutputStream, kMajorRevision); + WriteElement(*mOutputStream, kMinorRevision); +} + void DrawEventRecorderPrivate::RecordEvent(const RecordedEvent &aEvent) { @@ -34,9 +41,7 @@ DrawEventRecorderFile::DrawEventRecorderFile(const char *aFilename) { mOutputStream = &mOutputFile; - WriteElement(*mOutputStream, kMagicInt); - WriteElement(*mOutputStream, kMajorRevision); - WriteElement(*mOutputStream, kMinorRevision); + WriteHeader(); } DrawEventRecorderFile::~DrawEventRecorderFile() @@ -50,5 +55,40 @@ DrawEventRecorderFile::Flush() mOutputFile.flush(); } +DrawEventRecorderMemory::DrawEventRecorderMemory() + : DrawEventRecorderPrivate(nullptr) +{ + mOutputStream = &mMemoryStream; + + WriteHeader(); +} + +void +DrawEventRecorderMemory::Flush() +{ + mOutputStream->flush(); +} + +size_t +DrawEventRecorderMemory::RecordingSize() +{ + return mMemoryStream.tellp(); +} + +bool +DrawEventRecorderMemory::CopyRecording(char* aBuffer, size_t aBufferLen) +{ + return !!mMemoryStream.read(aBuffer, aBufferLen); +} + +void +DrawEventRecorderMemory::WipeRecording() +{ + mMemoryStream.str(std::string()); + mMemoryStream.clear(); + + WriteHeader(); +} + } // namespace gfx } // namespace mozilla diff --git a/gfx/2d/DrawEventRecorder.h b/gfx/2d/DrawEventRecorder.h index e6e5d4c8b3..611fd880bf 100644 --- a/gfx/2d/DrawEventRecorder.h +++ b/gfx/2d/DrawEventRecorder.h @@ -29,22 +29,29 @@ public: explicit DrawEventRecorderPrivate(std::ostream *aStream); virtual ~DrawEventRecorderPrivate() { } + void WriteHeader(); + void RecordEvent(const RecordedEvent &aEvent); void WritePath(const PathRecording *aPath); - void AddStoredPath(const ReferencePtr aPath) { - mStoredPaths.insert(aPath); + void AddStoredObject(const ReferencePtr aObject) { + mStoredObjects.insert(aObject); } - void RemoveStoredPath(const ReferencePtr aPath) { - mStoredPaths.erase(aPath); + void RemoveStoredObject(const ReferencePtr aObject) { + mStoredObjects.erase(aObject); } - bool HasStoredPath(const ReferencePtr aPath) { - if (mStoredPaths.find(aPath) != mStoredPaths.end()) { - return true; - } - return false; + bool HasStoredObject(const ReferencePtr aObject) { + return mStoredObjects.find(aObject) != mStoredObjects.end(); + } + + void AddStoredFontData(const uint64_t aFontDataKey) { + mStoredFontData.insert(aFontDataKey); + } + + bool HasStoredFontData(const uint64_t aFontDataKey) { + return mStoredFontData.find(aFontDataKey) != mStoredFontData.end(); } protected: @@ -54,12 +61,14 @@ protected: #if defined(_MSC_VER) typedef std::unordered_set ObjectSet; + typedef std::unordered_set Uint64Set; #else typedef std::set ObjectSet; + typedef std::set Uint64Set; #endif - ObjectSet mStoredPaths; - ObjectSet mStoredScaledFonts; + ObjectSet mStoredObjects; + Uint64Set mStoredFontData; }; class DrawEventRecorderFile : public DrawEventRecorderPrivate @@ -75,6 +84,45 @@ private: std::ofstream mOutputFile; }; +class DrawEventRecorderMemory final : public DrawEventRecorderPrivate +{ +public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawEventRecorderMemory) + + /** + * Constructs a DrawEventRecorder that stores the recording in memory. + */ + DrawEventRecorderMemory(); + + /** + * @return the current size of the recording (in chars). + */ + size_t RecordingSize(); + + /** + * Copies at most aBufferLen chars of the recording into aBuffer. + * + * @param aBuffer buffer to receive the recording chars + * @param aBufferLen length of aBuffer + * @return true if copied successfully + */ + bool CopyRecording(char* aBuffer, size_t aBufferLen); + + /** + * Wipes the internal recording buffer, but the recorder does NOT forget which + * objects it has recorded. This can be used so that a recording can be copied + * and processed in chunks, releasing memory as it goes. + */ + void WipeRecording(); + +private: + ~DrawEventRecorderMemory() {}; + + void Flush() final; + + std::stringstream mMemoryStream; +}; + } // namespace gfx } // namespace mozilla diff --git a/gfx/2d/DrawTargetRecording.cpp b/gfx/2d/DrawTargetRecording.cpp index f05c49fb7c..8940667b8f 100644 --- a/gfx/2d/DrawTargetRecording.cpp +++ b/gfx/2d/DrawTargetRecording.cpp @@ -1,4 +1,5 @@ /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: set ts=8 sts=2 et sw=2 tw=80: * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ @@ -10,10 +11,70 @@ #include "Logging.h" #include "Tools.h" #include "Filters.h" +#include "mozilla/UniquePtr.h" +#include "RecordingTypes.h" namespace mozilla { namespace gfx { +struct RecordingSourceSurfaceUserData +{ + void *refPtr; + RefPtr recorder; +}; + +void RecordingSourceSurfaceUserDataFunc(void *aUserData) +{ + RecordingSourceSurfaceUserData *userData = + static_cast(aUserData); + + userData->recorder->RemoveStoredObject(userData->refPtr); + userData->recorder->RecordEvent( + RecordedSourceSurfaceDestruction(userData->refPtr)); + + delete userData; +} + +static void +StoreSourceSurface(DrawEventRecorderPrivate *aRecorder, SourceSurface *aSurface, + DataSourceSurface *aDataSurf, const char *reason) +{ + if (!aDataSurf) { + gfxWarning() << "Recording failed to record SourceSurface for " << reason; + // Insert a bogus source surface. + int32_t stride = aSurface->GetSize().width * BytesPerPixel(aSurface->GetFormat()); + UniquePtr sourceData(new uint8_t[stride * aSurface->GetSize().height]()); + aRecorder->RecordEvent( + RecordedSourceSurfaceCreation(aSurface, sourceData.get(), stride, + aSurface->GetSize(), aSurface->GetFormat())); + } else { + DataSourceSurface::ScopedMap map(aDataSurf, DataSourceSurface::READ); + aRecorder->RecordEvent( + RecordedSourceSurfaceCreation(aSurface, map.GetData(), map.GetStride(), + aDataSurf->GetSize(), aDataSurf->GetFormat())); + } +} + +static void +EnsureSurfaceStored(DrawEventRecorderPrivate *aRecorder, SourceSurface *aSurface, + const char *reason) +{ + if (aRecorder->HasStoredObject(aSurface)) { + return; + } + + RefPtr dataSurf = aSurface->GetDataSurface(); + StoreSourceSurface(aRecorder, aSurface, dataSurf, reason); + aRecorder->AddStoredObject(aSurface); + + RecordingSourceSurfaceUserData *userData = new RecordingSourceSurfaceUserData; + userData->refPtr = aSurface; + userData->recorder = aRecorder; + aSurface->AddUserData(reinterpret_cast(aRecorder), + userData, &RecordingSourceSurfaceUserDataFunc); + return; +} + class SourceSurfaceRecording : public SourceSurface { public: @@ -21,10 +82,12 @@ public: SourceSurfaceRecording(SourceSurface *aFinalSurface, DrawEventRecorderPrivate *aRecorder) : mFinalSurface(aFinalSurface), mRecorder(aRecorder) { + mRecorder->AddStoredObject(this); } ~SourceSurfaceRecording() { + mRecorder->RemoveStoredObject(this); mRecorder->RecordEvent(RecordedSourceSurfaceDestruction(this)); } @@ -44,10 +107,12 @@ public: GradientStopsRecording(GradientStops *aFinalGradientStops, DrawEventRecorderPrivate *aRecorder) : mFinalGradientStops(aFinalGradientStops), mRecorder(aRecorder) { + mRecorder->AddStoredObject(this); } ~GradientStopsRecording() { + mRecorder->RemoveStoredObject(this); mRecorder->RecordEvent(RecordedGradientStopsDestruction(this)); } @@ -86,29 +151,39 @@ public: FilterNodeRecording(FilterNode *aFinalFilterNode, DrawEventRecorderPrivate *aRecorder) : mFinalFilterNode(aFinalFilterNode), mRecorder(aRecorder) { + mRecorder->AddStoredObject(this); } ~FilterNodeRecording() { + mRecorder->RemoveStoredObject(this); mRecorder->RecordEvent(RecordedFilterNodeDestruction(this)); } + static FilterNode* + GetFilterNode(FilterNode* aNode) + { + if (aNode->GetBackendType() != FILTER_BACKEND_RECORDING) { + gfxWarning() << "Non recording filter node used with recording DrawTarget!"; + return aNode; + } + + return static_cast(aNode)->mFinalFilterNode; + } + virtual void SetInput(uint32_t aIndex, SourceSurface *aSurface) override { + EnsureSurfaceStored(mRecorder, aSurface, "SetInput"); + mRecorder->RecordEvent(RecordedFilterNodeSetInput(this, aIndex, aSurface)); mFinalFilterNode->SetInput(aIndex, GetSourceSurface(aSurface)); } virtual void SetInput(uint32_t aIndex, FilterNode *aFilter) override { - FilterNode *finalNode = aFilter; - if (aFilter->GetBackendType() != FILTER_BACKEND_RECORDING) { - gfxWarning() << "Non recording filter node used with recording DrawTarget!"; - } else { - finalNode = static_cast(aFilter)->mFinalFilterNode; - } + MOZ_ASSERT(mRecorder->HasStoredObject(aFilter)); mRecorder->RecordEvent(RecordedFilterNodeSetInput(this, aIndex, aFilter)); - mFinalFilterNode->SetInput(aIndex, finalNode); + mFinalFilterNode->SetInput(aIndex, GetFilterNode(aFilter)); } @@ -127,6 +202,7 @@ public: FORWARD_SET_ATTRIBUTE(const Rect&, RECT); FORWARD_SET_ATTRIBUTE(const IntRect&, INTRECT); FORWARD_SET_ATTRIBUTE(const Point&, POINT); + FORWARD_SET_ATTRIBUTE(const Matrix&, MATRIX); FORWARD_SET_ATTRIBUTE(const Matrix5x4&, MATRIX5X4); FORWARD_SET_ATTRIBUTE(const Point3D&, POINT3D); FORWARD_SET_ATTRIBUTE(const Color&, COLOR); @@ -144,17 +220,6 @@ public: RefPtr mRecorder; }; -static FilterNode* -GetFilterNode(FilterNode* aNode) -{ - if (aNode->GetBackendType() != FILTER_BACKEND_RECORDING) { - gfxWarning() << "Non recording filter node used with recording DrawTarget!"; - return aNode; - } - - return static_cast(aNode)->mFinalFilterNode; -} - struct AdjustedPattern { explicit AdjustedPattern(const Pattern &aPattern) @@ -233,6 +298,16 @@ DrawTargetRecording::DrawTargetRecording(DrawEventRecorder *aRecorder, DrawTarge mFormat = mFinalDT->GetFormat(); } +DrawTargetRecording::DrawTargetRecording(const DrawTargetRecording *aDT, + const IntSize &aSize, + SurfaceFormat aFormat) + : mRecorder(aDT->mRecorder) + , mFinalDT(aDT->mFinalDT->CreateSimilarDrawTarget(aSize, aFormat)) +{ + mRecorder->RecordEvent(RecordedCreateSimilarDrawTarget(this, aSize, aFormat)); + mFormat = mFinalDT->GetFormat(); +} + DrawTargetRecording::~DrawTargetRecording() { mRecorder->RecordEvent(RecordedDrawTargetDestruction(this)); @@ -243,6 +318,8 @@ DrawTargetRecording::FillRect(const Rect &aRect, const Pattern &aPattern, const DrawOptions &aOptions) { + EnsurePatternDependenciesStored(aPattern); + mRecorder->RecordEvent(RecordedFillRect(this, aRect, aPattern, aOptions)); mFinalDT->FillRect(aRect, *AdjustedPattern(aPattern), aOptions); } @@ -253,6 +330,8 @@ DrawTargetRecording::StrokeRect(const Rect &aRect, const StrokeOptions &aStrokeOptions, const DrawOptions &aOptions) { + EnsurePatternDependenciesStored(aPattern); + mRecorder->RecordEvent(RecordedStrokeRect(this, aRect, aPattern, aStrokeOptions, aOptions)); mFinalDT->StrokeRect(aRect, *AdjustedPattern(aPattern), aStrokeOptions, aOptions); } @@ -264,29 +343,22 @@ DrawTargetRecording::StrokeLine(const Point &aBegin, const StrokeOptions &aStrokeOptions, const DrawOptions &aOptions) { + EnsurePatternDependenciesStored(aPattern); + mRecorder->RecordEvent(RecordedStrokeLine(this, aBegin, aEnd, aPattern, aStrokeOptions, aOptions)); mFinalDT->StrokeLine(aBegin, aEnd, *AdjustedPattern(aPattern), aStrokeOptions, aOptions); } -Path* -DrawTargetRecording::GetPathForPathRecording(const Path *aPath) const -{ - if (aPath->GetBackendType() != BackendType::RECORDING) { - return nullptr; - } - - return static_cast(aPath)->mPath; -} - void DrawTargetRecording::Fill(const Path *aPath, const Pattern &aPattern, const DrawOptions &aOptions) { - EnsureStored(aPath); + RefPtr pathRecording = EnsurePathStored(aPath); + EnsurePatternDependenciesStored(aPattern); - mRecorder->RecordEvent(RecordedFill(this, const_cast(aPath), aPattern, aOptions)); - mFinalDT->Fill(GetPathForPathRecording(aPath), *AdjustedPattern(aPattern), aOptions); + mRecorder->RecordEvent(RecordedFill(this, pathRecording, aPattern, aOptions)); + mFinalDT->Fill(pathRecording->mPath, *AdjustedPattern(aPattern), aOptions); } struct RecordingFontUserData @@ -315,10 +387,20 @@ DrawTargetRecording::FillGlyphs(ScaledFont *aFont, const DrawOptions &aOptions, const GlyphRenderingOptions *aRenderingOptions) { + EnsurePatternDependenciesStored(aPattern); + if (!aFont->GetUserData(reinterpret_cast(mRecorder.get()))) { // TODO support font in b2g recordings #ifndef MOZ_WIDGET_GONK - mRecorder->RecordEvent(RecordedScaledFontCreation(aFont, aFont)); + RecordedFontData fontData(aFont); + RecordedFontDetails fontDetails; + if (fontData.GetFontDetails(fontDetails)) { + if (!mRecorder->HasStoredFontData(fontDetails.fontDataKey)) { + mRecorder->RecordEvent(fontData); + mRecorder->AddStoredFontData(fontDetails.fontDataKey); + } + mRecorder->RecordEvent(RecordedScaledFontCreation(aFont, fontDetails)); + } #endif RecordingFontUserData *userData = new RecordingFontUserData; userData->refPtr = aFont; @@ -339,6 +421,9 @@ DrawTargetRecording::Mask(const Pattern &aSource, const Pattern &aMask, const DrawOptions &aOptions) { + EnsurePatternDependenciesStored(aSource); + EnsurePatternDependenciesStored(aMask); + mRecorder->RecordEvent(RecordedMask(this, aSource, aMask, aOptions)); mFinalDT->Mask(*AdjustedPattern(aSource), *AdjustedPattern(aMask), aOptions); } @@ -349,6 +434,9 @@ DrawTargetRecording::MaskSurface(const Pattern &aSource, Point aOffset, const DrawOptions &aOptions) { + EnsurePatternDependenciesStored(aSource); + EnsureSurfaceStored(mRecorder, aMask, "MaskSurface"); + mRecorder->RecordEvent(RecordedMaskSurface(this, aSource, aMask, aOffset, aOptions)); mFinalDT->MaskSurface(*AdjustedPattern(aSource), GetSourceSurface(aMask), aOffset, aOptions); } @@ -359,10 +447,11 @@ DrawTargetRecording::Stroke(const Path *aPath, const StrokeOptions &aStrokeOptions, const DrawOptions &aOptions) { - EnsureStored(aPath); + RefPtr pathRecording = EnsurePathStored(aPath); + EnsurePatternDependenciesStored(aPattern); - mRecorder->RecordEvent(RecordedStroke(this, const_cast(aPath), aPattern, aStrokeOptions, aOptions)); - mFinalDT->Stroke(GetPathForPathRecording(aPath), *AdjustedPattern(aPattern), aStrokeOptions, aOptions); + mRecorder->RecordEvent(RecordedStroke(this, pathRecording, aPattern, aStrokeOptions, aOptions)); + mFinalDT->Stroke(pathRecording->mPath, *AdjustedPattern(aPattern), aStrokeOptions, aOptions); } already_AddRefed @@ -384,6 +473,8 @@ DrawTargetRecording::DrawSurface(SourceSurface *aSurface, const DrawSurfaceOptions &aSurfOptions, const DrawOptions &aOptions) { + EnsureSurfaceStored(mRecorder, aSurface, "DrawSurface"); + mRecorder->RecordEvent(RecordedDrawSurface(this, aSurface, aDest, aSource, aSurfOptions, aOptions)); mFinalDT->DrawSurface(GetSourceSurface(aSurface), aDest, aSource, aSurfOptions, aOptions); } @@ -396,6 +487,8 @@ DrawTargetRecording::DrawSurfaceWithShadow(SourceSurface *aSurface, Float aSigma, CompositionOp aOp) { + EnsureSurfaceStored(mRecorder, aSurface, "DrawSurfaceWithShadow"); + mRecorder->RecordEvent(RecordedDrawSurfaceWithShadow(this, aSurface, aDest, aColor, aOffset, aSigma, aOp)); mFinalDT->DrawSurfaceWithShadow(GetSourceSurface(aSurface), aDest, aColor, aOffset, aSigma, aOp); } @@ -406,8 +499,10 @@ DrawTargetRecording::DrawFilter(FilterNode *aNode, const Point &aDestPoint, const DrawOptions &aOptions) { + MOZ_ASSERT(mRecorder->HasStoredObject(aNode)); + mRecorder->RecordEvent(RecordedDrawFilter(this, aNode, aSourceRect, aDestPoint, aOptions)); - mFinalDT->DrawFilter(GetFilterNode(aNode), aSourceRect, aDestPoint, aOptions); + mFinalDT->DrawFilter(FilterNodeRecording::GetFilterNode(aNode), aSourceRect, aDestPoint, aOptions); } already_AddRefed @@ -434,6 +529,8 @@ DrawTargetRecording::CopySurface(SourceSurface *aSurface, const IntRect &aSourceRect, const IntPoint &aDestination) { + EnsureSurfaceStored(mRecorder, aSurface, "CopySurface"); + mRecorder->RecordEvent(RecordedCopySurface(this, aSurface, aSourceRect, aDestination)); mFinalDT->CopySurface(GetSourceSurface(aSurface), aSourceRect, aDestination); } @@ -441,10 +538,10 @@ DrawTargetRecording::CopySurface(SourceSurface *aSurface, void DrawTargetRecording::PushClip(const Path *aPath) { - EnsureStored(aPath); + RefPtr pathRecording = EnsurePathStored(aPath); - mRecorder->RecordEvent(RecordedPushClip(this, const_cast(aPath))); - mFinalDT->PushClip(GetPathForPathRecording(aPath)); + mRecorder->RecordEvent(RecordedPushClip(this, pathRecording)); + mFinalDT->PushClip(pathRecording->mPath); } void @@ -490,21 +587,7 @@ DrawTargetRecording::OptimizeSourceSurface(SourceSurface *aSurface) const dataSurf = aSurface->GetDataSurface(); } - if (!dataSurf) { - gfxWarning() << "Recording failed to record SourceSurface created from OptimizeSourceSurface"; - // Insert a bogus source surface. - uint8_t *sourceData = new uint8_t[surf->GetSize().width * surf->GetSize().height * BytesPerPixel(surf->GetFormat())]; - memset(sourceData, 0, surf->GetSize().width * surf->GetSize().height * BytesPerPixel(surf->GetFormat())); - mRecorder->RecordEvent( - RecordedSourceSurfaceCreation(retSurf, sourceData, - surf->GetSize().width * BytesPerPixel(surf->GetFormat()), - surf->GetSize(), surf->GetFormat())); - delete [] sourceData; - } else { - mRecorder->RecordEvent( - RecordedSourceSurfaceCreation(retSurf, dataSurf->GetData(), dataSurf->Stride(), - dataSurf->GetSize(), dataSurf->GetFormat())); - } + StoreSourceSurface(mRecorder, retSurf, dataSurf, "OptimizeSourceSurface"); return retSurf.forget(); } @@ -517,22 +600,7 @@ DrawTargetRecording::CreateSourceSurfaceFromNativeSurface(const NativeSurface &a RefPtr retSurf = new SourceSurfaceRecording(surf, mRecorder); RefPtr dataSurf = surf->GetDataSurface(); - - if (!dataSurf) { - gfxWarning() << "Recording failed to record SourceSurface created from OptimizeSourceSurface"; - // Insert a bogus source surface. - uint8_t *sourceData = new uint8_t[surf->GetSize().width * surf->GetSize().height * BytesPerPixel(surf->GetFormat())]; - memset(sourceData, 0, surf->GetSize().width * surf->GetSize().height * BytesPerPixel(surf->GetFormat())); - mRecorder->RecordEvent( - RecordedSourceSurfaceCreation(retSurf, sourceData, - surf->GetSize().width * BytesPerPixel(surf->GetFormat()), - surf->GetSize(), surf->GetFormat())); - delete [] sourceData; - } else { - mRecorder->RecordEvent( - RecordedSourceSurfaceCreation(retSurf, dataSurf->GetData(), dataSurf->Stride(), - dataSurf->GetSize(), dataSurf->GetFormat())); - } + StoreSourceSurface(mRecorder, retSurf, dataSurf, "CreateSourceSurfaceFromNativeSurface"); return retSurf.forget(); } @@ -540,8 +608,7 @@ DrawTargetRecording::CreateSourceSurfaceFromNativeSurface(const NativeSurface &a already_AddRefed DrawTargetRecording::CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFormat) const { - RefPtr dt = mFinalDT->CreateSimilarDrawTarget(aSize, aFormat); - return MakeAndAddRef(mRecorder.get(), dt); + return MakeAndAddRef(this, aSize, aFormat); } already_AddRefed @@ -573,17 +640,54 @@ DrawTargetRecording::SetTransform(const Matrix &aTransform) mFinalDT->SetTransform(aTransform); } -void -DrawTargetRecording::EnsureStored(const Path *aPath) +already_AddRefed +DrawTargetRecording::EnsurePathStored(const Path *aPath) { - if (!mRecorder->HasStoredPath(aPath)) { - if (aPath->GetBackendType() != BackendType::RECORDING) { - gfxWarning() << "Cannot record this fill path properly!"; - } else { - PathRecording *recPath = const_cast(static_cast(aPath)); - mRecorder->RecordEvent(RecordedPathCreation(recPath)); - mRecorder->AddStoredPath(aPath); - recPath->mStoredRecorders.push_back(mRecorder); + RefPtr pathRecording; + if (aPath->GetBackendType() == BackendType::RECORDING) { + pathRecording = const_cast(static_cast(aPath)); + if (mRecorder->HasStoredObject(aPath)) { + return pathRecording.forget(); + } + } else { + MOZ_ASSERT(!mRecorder->HasStoredObject(aPath)); + FillRule fillRule = aPath->GetFillRule(); + RefPtr builder = mFinalDT->CreatePathBuilder(fillRule); + RefPtr builderRecording = + new PathBuilderRecording(builder, fillRule); + aPath->StreamToSink(builderRecording); + pathRecording = builderRecording->Finish().downcast(); + } + + mRecorder->RecordEvent(RecordedPathCreation(pathRecording)); + mRecorder->AddStoredObject(pathRecording); + pathRecording->mStoredRecorders.push_back(mRecorder); + + return pathRecording.forget(); +} + +void +DrawTargetRecording::EnsurePatternDependenciesStored(const Pattern &aPattern) +{ + switch (aPattern.GetType()) { + case PatternType::COLOR: + // No dependencies here. + return; + case PatternType::LINEAR_GRADIENT: + { + MOZ_ASSERT(mRecorder->HasStoredObject(static_cast(&aPattern)->mStops)); + return; + } + case PatternType::RADIAL_GRADIENT: + { + MOZ_ASSERT(mRecorder->HasStoredObject(static_cast(&aPattern)->mStops)); + return; + } + case PatternType::SURFACE: + { + const SurfacePattern *pat = static_cast(&aPattern); + EnsureSurfaceStored(mRecorder, pat->mSurface, "EnsurePatternDependenciesStored"); + return; } } } diff --git a/gfx/2d/DrawTargetRecording.h b/gfx/2d/DrawTargetRecording.h index 9bf7b2f7d9..b192a8741f 100644 --- a/gfx/2d/DrawTargetRecording.h +++ b/gfx/2d/DrawTargetRecording.h @@ -1,4 +1,5 @@ /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: set ts=8 sts=2 et sw=2 tw=80: * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ @@ -17,10 +18,22 @@ class DrawTargetRecording : public DrawTarget public: MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawTargetRecording, override) DrawTargetRecording(DrawEventRecorder *aRecorder, DrawTarget *aDT, bool aHasData = false); + + /** + * Used for creating a DrawTargetRecording for a CreateSimilarDrawTarget call. + * + * @param aDT DrawTargetRecording on which CreateSimilarDrawTarget was called + * @param aSize size for the similar DrawTarget + * @param aFormat format for the similar DrawTarget + */ + DrawTargetRecording(const DrawTargetRecording *aDT, const IntSize &aSize, + SurfaceFormat aFormat); + ~DrawTargetRecording(); virtual DrawTargetType GetType() const override { return mFinalDT->GetType(); } virtual BackendType GetBackendType() const override { return mFinalDT->GetBackendType(); } + virtual bool IsRecording() const override { return true; } virtual already_AddRefed Snapshot() override; @@ -275,7 +288,8 @@ public: private: Path *GetPathForPathRecording(const Path *aPath) const; - void EnsureStored(const Path *aPath); + already_AddRefed EnsurePathStored(const Path *aPath); + void EnsurePatternDependenciesStored(const Pattern &aPattern); RefPtr mRecorder; RefPtr mFinalDT; diff --git a/gfx/2d/DrawTargetSkia.cpp b/gfx/2d/DrawTargetSkia.cpp index 0f752b25e9..e4810473b6 100644 --- a/gfx/2d/DrawTargetSkia.cpp +++ b/gfx/2d/DrawTargetSkia.cpp @@ -575,7 +575,8 @@ DrawTargetSkia::FillGlyphs(ScaledFont *aFont, { if (aFont->GetType() != FontType::MAC && aFont->GetType() != FontType::SKIA && - aFont->GetType() != FontType::GDI) { + aFont->GetType() != FontType::GDI && + aFont->GetType() != FontType::DWRITE) { return; } diff --git a/gfx/2d/Factory.cpp b/gfx/2d/Factory.cpp index 7ebb9c8e4f..703e369d7e 100644 --- a/gfx/2d/Factory.cpp +++ b/gfx/2d/Factory.cpp @@ -21,6 +21,7 @@ #if defined(WIN32) #include "ScaledFontWin.h" +#include "NativeFontResourceGDI.h" #endif #ifdef XP_DARWIN @@ -36,6 +37,7 @@ #include "DrawTargetD2D.h" #include "DrawTargetD2D1.h" #include "ScaledFontDWrite.h" +#include "NativeFontResourceDWrite.h" #include #include "HelpersD2D.h" #endif @@ -48,6 +50,7 @@ #include "DrawEventRecorder.h" +#include "Preferences.h" #include "Logging.h" #include "mozilla/CheckedInt.h" @@ -152,31 +155,9 @@ HasCPUIDBit(unsigned int level, CPUIDRegister reg, unsigned int bit) namespace mozilla { namespace gfx { -// These values we initialize with should match those in -// PreferenceAccess::RegisterAll method. -int32_t PreferenceAccess::sGfxLogLevel = LOG_DEFAULT; - -PreferenceAccess* PreferenceAccess::sAccess = nullptr; -PreferenceAccess::~PreferenceAccess() -{ -} - -// Just a placeholder, the derived class will set the variable to default -// if the preference doesn't exist. -void PreferenceAccess::LivePref(const char* aName, int32_t* aVar, int32_t aDef) -{ - *aVar = aDef; -} - -// This will be called with the derived class, so we will want to register -// the callbacks with it. -void PreferenceAccess::SetAccess(PreferenceAccess* aAccess) { - sAccess = aAccess; - if (sAccess) { - RegisterAll(); - } -} - +int32_t LoggingPrefs::sGfxLogLevel = + PreferenceAccess::RegisterLivePref("gfx.logging.level", &sGfxLogLevel, + LOG_DEFAULT); #ifdef WIN32 ID3D10Device1 *Factory::mD3D10Device; @@ -552,7 +533,7 @@ Factory::CreateScaledFontForNativeFont(const NativeFont &aNativeFont, Float aSiz #if defined(USE_CAIRO) || defined(USE_SKIA) case NativeFontType::GDI_FONT_FACE: { - return MakeAndAddRef(static_cast(aNativeFont.mFont), aSize); + return MakeAndAddRef(static_cast(aNativeFont.mFont), aSize); } #endif #endif @@ -574,20 +555,35 @@ Factory::CreateScaledFontForNativeFont(const NativeFont &aNativeFont, Float aSiz } } -already_AddRefed -Factory::CreateScaledFontForTrueTypeData(uint8_t *aData, uint32_t aSize, - uint32_t aFaceIndex, Float aGlyphSize, - FontType aType) +already_AddRefed +Factory::CreateNativeFontResource(uint8_t *aData, uint32_t aSize, + FontType aType) { switch (aType) { #ifdef WIN32 case FontType::DWRITE: { - return MakeAndAddRef(aData, aSize, aFaceIndex, aGlyphSize); + return NativeFontResourceDWrite::Create(aData, aSize, + /* aNeedsCairo = */ false); } #endif + case FontType::CAIRO: + { +#ifdef WIN32 + if (GetDirect3D11Device()) { + return NativeFontResourceDWrite::Create(aData, aSize, + /* aNeedsCairo = */ true); + } else { + return NativeFontResourceGDI::Create(aData, aSize, + /* aNeedsCairo = */ true); + } +#else + gfxWarning() << "Unable to create cairo scaled font from truetype data"; + return nullptr; +#endif + } default: - gfxWarning() << "Unable to create requested font type from truetype data"; + gfxWarning() << "Unable to create requested font resource from truetype data"; return nullptr; } } @@ -803,6 +799,15 @@ Factory::D2DCleanup() DrawTargetD2D::CleanupD2D(); } +already_AddRefed +Factory::CreateScaledFontForDWriteFont(IDWriteFont* aFont, + IDWriteFontFamily* aFontFamily, + IDWriteFontFace* aFontFace, + float aSize) +{ + return MakeAndAddRef(aFont, aFontFamily, aFontFace, aSize); +} + #endif // XP_WIN #ifdef USE_SKIA_GPU diff --git a/gfx/2d/Logging.h b/gfx/2d/Logging.h index cf76d35828..f6b1ddaac4 100644 --- a/gfx/2d/Logging.h +++ b/gfx/2d/Logging.h @@ -62,24 +62,9 @@ inline mozilla::LogLevel PRLogLevelForLevel(int aLevel) { } #endif -class PreferenceAccess +class LoggingPrefs { public: - virtual ~PreferenceAccess(); - - // This should connect the variable aVar to be updated whenever a preference - // aName is modified. aDefault would be used if the preference is undefined, - // so that we always get the valid value for aVar. - virtual void LivePref(const char* aName, int32_t* aVar, int32_t aDefault); - -public: - static void SetAccess(PreferenceAccess* aAccess); - -public: - // For each preference that needs to be accessed in Moz2D, add a variable - // to hold it, as well as the call to LivePref in the RegisterAll() method - // below. - // Used to choose the level of logging we get. The higher the number, // the more logging we get. Value of zero will give you no logging, // 1 just errors, 2 adds warnings and 3 adds logging/debug. 4 is used to @@ -88,15 +73,6 @@ public: // in addition to setting the value to 4, you will need to set an // environment variable NSPR_LOG_MODULES to gfx:4. See prlog.h for details. static int32_t sGfxLogLevel; - -private: - static void RegisterAll() { - // The default values (last parameter) should match the initialization - // values in Factory.cpp, otherwise the standalone Moz2D will get different - // defaults. - sAccess->LivePref("gfx.logging.level", &sGfxLogLevel, LOG_DEFAULT); - } - static PreferenceAccess* sAccess; }; /// Graphics logging is available in both debug and release builds and is @@ -164,7 +140,7 @@ struct BasicLogger // OutputMessage below. If making any changes here, also make it // in the appropriate places in that method. static bool ShouldOutputMessage(int aLevel) { - if (PreferenceAccess::sGfxLogLevel >= aLevel) { + if (LoggingPrefs::sGfxLogLevel >= aLevel) { #if defined(MOZ_WIDGET_GONK) || defined(MOZ_WIDGET_ANDROID) return true; #else @@ -173,7 +149,7 @@ struct BasicLogger return true; } else #endif - if ((PreferenceAccess::sGfxLogLevel >= LOG_DEBUG_PRLOG) || + if ((LoggingPrefs::sGfxLogLevel >= LOG_DEBUG_PRLOG) || (aLevel < LOG_DEBUG)) { return true; } @@ -197,7 +173,7 @@ struct BasicLogger // If making any logic changes to this method, you should probably // make the corresponding change in the ShouldOutputMessage method // above. - if (PreferenceAccess::sGfxLogLevel >= aLevel) { + if (LoggingPrefs::sGfxLogLevel >= aLevel) { #if defined(MOZ_WIDGET_GONK) || defined(MOZ_WIDGET_ANDROID) printf_stderr("%s%s", aString.c_str(), aNoNewline ? "" : "\n"); #else @@ -206,7 +182,7 @@ struct BasicLogger PR_LogPrint("%s%s", aString.c_str(), aNoNewline ? "" : "\n"); } else #endif - if ((PreferenceAccess::sGfxLogLevel >= LOG_DEBUG_PRLOG) || + if ((LoggingPrefs::sGfxLogLevel >= LOG_DEBUG_PRLOG) || (aLevel < LOG_DEBUG)) { printf("%s%s", aString.c_str(), aNoNewline ? "" : "\n"); } diff --git a/gfx/2d/NativeFontResourceDWrite.cpp b/gfx/2d/NativeFontResourceDWrite.cpp new file mode 100644 index 0000000000..10b0486de8 --- /dev/null +++ b/gfx/2d/NativeFontResourceDWrite.cpp @@ -0,0 +1,287 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "NativeFontResourceDWrite.h" + +#include + +#include "DrawTargetD2D.h" +#include "Logging.h" +#include "mozilla/RefPtr.h" + +namespace mozilla { +namespace gfx { + +static Atomic sNextFontFileKey; +static std::unordered_map sFontFileStreams; + +class DWriteFontFileLoader : public IDWriteFontFileLoader +{ +public: + DWriteFontFileLoader() + { + } + + // IUnknown interface + IFACEMETHOD(QueryInterface)(IID const& iid, OUT void** ppObject) + { + if (iid == __uuidof(IDWriteFontFileLoader)) { + *ppObject = static_cast(this); + return S_OK; + } else if (iid == __uuidof(IUnknown)) { + *ppObject = static_cast(this); + return S_OK; + } else { + return E_NOINTERFACE; + } + } + + IFACEMETHOD_(ULONG, AddRef)() + { + return 1; + } + + IFACEMETHOD_(ULONG, Release)() + { + return 1; + } + + // IDWriteFontFileLoader methods + /** + * Important! Note the key here has to be a uint64_t that will have been + * generated by incrementing sNextFontFileKey. + */ + virtual HRESULT STDMETHODCALLTYPE + CreateStreamFromKey(void const* fontFileReferenceKey, + UINT32 fontFileReferenceKeySize, + OUT IDWriteFontFileStream** fontFileStream); + + /** + * Gets the singleton loader instance. Note that when using this font + * loader, the key must be a uint64_t that has been generated by incrementing + * sNextFontFileKey. + * Also note that this is _not_ threadsafe. + */ + static IDWriteFontFileLoader* Instance() + { + if (!mInstance) { + mInstance = new DWriteFontFileLoader(); + DrawTargetD2D::GetDWriteFactory()-> + RegisterFontFileLoader(mInstance); + } + return mInstance; + } + +private: + static IDWriteFontFileLoader* mInstance; +}; + +class DWriteFontFileStream : public IDWriteFontFileStream +{ +public: + /** + * Used by the FontFileLoader to create a new font stream, + * this font stream is created from data in memory. The memory + * passed may be released after object creation, it will be + * copied internally. + * + * @param aData Font data + */ + DWriteFontFileStream(uint8_t *aData, uint32_t aSize, uint64_t aFontFileKey); + ~DWriteFontFileStream(); + + // IUnknown interface + IFACEMETHOD(QueryInterface)(IID const& iid, OUT void** ppObject) + { + if (iid == __uuidof(IDWriteFontFileStream)) { + *ppObject = static_cast(this); + return S_OK; + } else if (iid == __uuidof(IUnknown)) { + *ppObject = static_cast(this); + return S_OK; + } else { + return E_NOINTERFACE; + } + } + + IFACEMETHOD_(ULONG, AddRef)() + { + ++mRefCnt; + return mRefCnt; + } + + IFACEMETHOD_(ULONG, Release)() + { + --mRefCnt; + if (mRefCnt == 0) { + delete this; + return 0; + } + return mRefCnt; + } + + // IDWriteFontFileStream methods + virtual HRESULT STDMETHODCALLTYPE ReadFileFragment(void const** fragmentStart, + UINT64 fileOffset, + UINT64 fragmentSize, + OUT void** fragmentContext); + + virtual void STDMETHODCALLTYPE ReleaseFileFragment(void* fragmentContext); + + virtual HRESULT STDMETHODCALLTYPE GetFileSize(OUT UINT64* fileSize); + + virtual HRESULT STDMETHODCALLTYPE GetLastWriteTime(OUT UINT64* lastWriteTime); + +private: + std::vector mData; + uint32_t mRefCnt; + uint64_t mFontFileKey; +}; + +IDWriteFontFileLoader* DWriteFontFileLoader::mInstance = nullptr; + +HRESULT STDMETHODCALLTYPE +DWriteFontFileLoader::CreateStreamFromKey(const void *fontFileReferenceKey, + UINT32 fontFileReferenceKeySize, + IDWriteFontFileStream **fontFileStream) +{ + if (!fontFileReferenceKey || !fontFileStream) { + return E_POINTER; + } + + uint64_t fontFileKey = *static_cast(fontFileReferenceKey); + auto found = sFontFileStreams.find(fontFileKey); + if (found == sFontFileStreams.end()) { + *fontFileStream = nullptr; + return E_FAIL; + } + + found->second->AddRef(); + *fontFileStream = found->second; + return S_OK; +} + +DWriteFontFileStream::DWriteFontFileStream(uint8_t *aData, uint32_t aSize, + uint64_t aFontFileKey) + : mRefCnt(0) + , mFontFileKey(aFontFileKey) +{ + mData.resize(aSize); + memcpy(&mData.front(), aData, aSize); +} + +DWriteFontFileStream::~DWriteFontFileStream() +{ + sFontFileStreams.erase(mFontFileKey); +} + +HRESULT STDMETHODCALLTYPE +DWriteFontFileStream::GetFileSize(UINT64 *fileSize) +{ + *fileSize = mData.size(); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE +DWriteFontFileStream::GetLastWriteTime(UINT64 *lastWriteTime) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE +DWriteFontFileStream::ReadFileFragment(const void **fragmentStart, + UINT64 fileOffset, + UINT64 fragmentSize, + void **fragmentContext) +{ + // We are required to do bounds checking. + if (fileOffset + fragmentSize > mData.size()) { + return E_FAIL; + } + + // truncate the 64 bit fileOffset to size_t sized index into mData + size_t index = static_cast(fileOffset); + + // We should be alive for the duration of this. + *fragmentStart = &mData[index]; + *fragmentContext = nullptr; + return S_OK; +} + +void STDMETHODCALLTYPE +DWriteFontFileStream::ReleaseFileFragment(void *fragmentContext) +{ +} + +/* static */ +already_AddRefed +NativeFontResourceDWrite::Create(uint8_t *aFontData, uint32_t aDataLength, + bool aNeedsCairo) +{ + IDWriteFactory *factory = DrawTargetD2D::GetDWriteFactory(); + if (!factory) { + gfxWarning() << "Failed to get DWrite Factory."; + return nullptr; + } + + uint64_t fontFileKey = sNextFontFileKey++; + RefPtr ffsRef = + new DWriteFontFileStream(aFontData, aDataLength, fontFileKey); + sFontFileStreams[fontFileKey] = ffsRef; + + RefPtr fontFile; + HRESULT hr = + factory->CreateCustomFontFileReference(&fontFileKey, sizeof(fontFileKey), + DWriteFontFileLoader::Instance(), + getter_AddRefs(fontFile)); + if (FAILED(hr)) { + gfxWarning() << "Failed to load font file from data!"; + return nullptr; + } + + BOOL isSupported; + DWRITE_FONT_FILE_TYPE fileType; + DWRITE_FONT_FACE_TYPE faceType; + UINT32 numberOfFaces; + hr = fontFile->Analyze(&isSupported, &fileType, &faceType, &numberOfFaces); + if (FAILED(hr) || !isSupported) { + gfxWarning() << "Font file is not supported."; + return nullptr; + } + + RefPtr fontResource = + new NativeFontResourceDWrite(factory, fontFile.forget(), faceType, + numberOfFaces, aNeedsCairo); + return fontResource.forget(); +} + +already_AddRefed +NativeFontResourceDWrite::CreateScaledFont(uint32_t aIndex, uint32_t aGlyphSize) +{ + if (aIndex >= mNumberOfFaces) { + gfxWarning() << "Font face index is too high for font resource."; + return nullptr; + } + + IDWriteFontFile *fontFile = mFontFile; + RefPtr fontFace; + if (FAILED(mFactory->CreateFontFace(mFaceType, 1, &fontFile, aIndex, + DWRITE_FONT_SIMULATIONS_NONE, getter_AddRefs(fontFace)))) { + gfxWarning() << "Failed to create font face from font file data."; + return nullptr; + } + + RefPtr scaledFont = new ScaledFontDWrite(fontFace, aGlyphSize); + if (mNeedsCairo && !scaledFont->PopulateCairoScaledFont()) { + gfxWarning() << "Unable to create cairo scaled font DWrite font."; + return nullptr; + } + + return scaledFont.forget(); +} + +} // gfx +} // mozilla diff --git a/gfx/2d/NativeFontResourceDWrite.h b/gfx/2d/NativeFontResourceDWrite.h new file mode 100644 index 0000000000..0c7bf9d933 --- /dev/null +++ b/gfx/2d/NativeFontResourceDWrite.h @@ -0,0 +1,56 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_gfx_NativeFontResourceDWrite_h +#define mozilla_gfx_NativeFontResourceDWrite_h + +#include + +#include "2D.h" +#include "mozilla/AlreadyAddRefed.h" + +namespace mozilla { +namespace gfx { + +class NativeFontResourceDWrite final : public NativeFontResource +{ +public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(NativeFontResourceDWrite) + /** + * Creates a NativeFontResourceDWrite if data is valid. Note aFontData will be + * copied if required and so can be released after calling. + * + * @param aFontData the SFNT data. + * @param aDataLength length of data. + * @param aNeedsCairo whether the ScaledFont created needs a cairo scaled font + * @return Referenced NativeFontResourceDWrite or nullptr if invalid. + */ + static already_AddRefed + Create(uint8_t *aFontData, uint32_t aDataLength, bool aNeedsCairo); + + already_AddRefed + CreateScaledFont(uint32_t aIndex, uint32_t aGlyphSize) final; + +private: + NativeFontResourceDWrite(IDWriteFactory *aFactory, + already_AddRefed aFontFile, + DWRITE_FONT_FACE_TYPE aFaceType, + uint32_t aNumberOfFaces, bool aNeedsCairo) + : mFactory(aFactory), mFontFile(aFontFile), mFaceType(aFaceType) + , mNumberOfFaces(aNumberOfFaces), mNeedsCairo(aNeedsCairo) + {} + + IDWriteFactory *mFactory; + RefPtr mFontFile; + DWRITE_FONT_FACE_TYPE mFaceType; + uint32_t mNumberOfFaces; + bool mNeedsCairo; +}; + +} // gfx +} // mozilla + +#endif // mozilla_gfx_NativeFontResourceDWrite_h \ No newline at end of file diff --git a/gfx/2d/NativeFontResourceGDI.cpp b/gfx/2d/NativeFontResourceGDI.cpp new file mode 100644 index 0000000000..ba72538bb5 --- /dev/null +++ b/gfx/2d/NativeFontResourceGDI.cpp @@ -0,0 +1,112 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "NativeFontResourceGDI.h" + +#include "Logging.h" +#include "mozilla/RefPtr.h" +#include "ScaledFontWin.h" +#include "SFNTData.h" + +namespace mozilla { +namespace gfx { + +/* static */ +already_AddRefed +NativeFontResourceGDI::Create(uint8_t *aFontData, uint32_t aDataLength, + bool aNeedsCairo) +{ + UniquePtr sfntData = SFNTData::Create(aFontData, aDataLength); + if (!sfntData) { + gfxWarning() << "Failed to create SFNTData for ScaledFontWin."; + return nullptr; + } + + Vector fontNames; + if (!sfntData->GetU16FullNames(fontNames)) { + gfxWarning() << "Failed to get font names from font."; + return nullptr; + } + + // lfFaceName has a maximum length including null. + for (size_t i = 0; i < fontNames.length(); ++i) { + if (fontNames[i].size() > LF_FACESIZE - 1) { + fontNames[i].resize(LF_FACESIZE - 1); + } + // Add null to end for easy copying later. + fontNames[i].append(1, '\0'); + } + + DWORD numberOfFontsAdded; + HANDLE fontResourceHandle = ::AddFontMemResourceEx(aFontData, aDataLength, + 0, &numberOfFontsAdded); + if (!fontResourceHandle) { + gfxWarning() << "Failed to add memory font resource."; + return nullptr; + } + + if (numberOfFontsAdded != fontNames.length()) { + gfxWarning() << + "Number of fonts added doesn't match number of names extracted."; + } + + RefPtr fontResouce = + new NativeFontResourceGDI(fontResourceHandle, Move(fontNames), aNeedsCairo); + + return fontResouce.forget(); +} + +NativeFontResourceGDI::~NativeFontResourceGDI() +{ + ::RemoveFontMemResourceEx(mFontResourceHandle); +} + +already_AddRefed +NativeFontResourceGDI::CreateScaledFont(uint32_t aIndex, uint32_t aGlyphSize) +{ + if (aIndex >= mFontNames.length()) { + gfxWarning() << "Font index is too high for font resource."; + return nullptr; + } + + if (mFontNames[aIndex].empty()) { + gfxWarning() << "Font name for index is empty."; + return nullptr; + } + + LOGFONTW logFont; + logFont.lfHeight = 0; + logFont.lfWidth = 0; + logFont.lfEscapement = 0; + logFont.lfOrientation = 0; + logFont.lfWeight = FW_DONTCARE; + logFont.lfItalic = FALSE; + logFont.lfUnderline = FALSE; + logFont.lfStrikeOut = FALSE; + logFont.lfCharSet = DEFAULT_CHARSET; + logFont.lfOutPrecision = OUT_DEFAULT_PRECIS; + logFont.lfClipPrecision = CLIP_DEFAULT_PRECIS; + logFont.lfQuality = DEFAULT_QUALITY; + logFont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; + + // Copy name to mLogFont (null already included in font name). We cast here + // because for VS2015 char16_t != wchar_t, even though they are both 16 bit. + mFontNames[aIndex].copy(reinterpret_cast(logFont.lfFaceName), + mFontNames[aIndex].length()); + + // Constructor for ScaledFontWin dereferences and copies the LOGFONT, so we + // are safe to pass this reference. + RefPtr scaledFont = new ScaledFontWin(&logFont, aGlyphSize); + if (mNeedsCairo && !scaledFont->PopulateCairoScaledFont()) { + gfxWarning() << "Unable to create cairo scaled font DWrite font."; + return nullptr; + } + + return scaledFont.forget(); +} + +} // gfx +} // mozilla diff --git a/gfx/2d/NativeFontResourceGDI.h b/gfx/2d/NativeFontResourceGDI.h new file mode 100644 index 0000000000..aa5bceb974 --- /dev/null +++ b/gfx/2d/NativeFontResourceGDI.h @@ -0,0 +1,57 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_gfx_NativeFontResourceGDI_h +#define mozilla_gfx_NativeFontResourceGDI_h + +#include + +#include "2D.h" +#include "mozilla/AlreadyAddRefed.h" +#include "mozilla/Vector.h" +#include "u16string.h" + +namespace mozilla { +namespace gfx { + +class NativeFontResourceGDI final : public NativeFontResource +{ +public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(NativeFontResourceGDI) + /** + * Creates a NativeFontResourceGDI if data is valid. Note aFontData will be + * copied if required and so can be released after calling. + * + * @param aFontData the SFNT data. + * @param aDataLength length of data. + * @param aNeedsCairo whether the ScaledFont created need a cairo scaled font + * @return Referenced NativeFontResourceGDI or nullptr if invalid. + */ + static already_AddRefed + Create(uint8_t *aFontData, uint32_t aDataLength, bool aNeedsCairo); + + ~NativeFontResourceGDI(); + + already_AddRefed + CreateScaledFont(uint32_t aIndex, uint32_t aGlyphSize) final; + +private: + NativeFontResourceGDI(HANDLE aFontResourceHandle, + Vector&& aFontNames, + bool aNeedsCairo) + : mFontResourceHandle(aFontResourceHandle), mFontNames(Move(aFontNames)) + , mNeedsCairo(aNeedsCairo) + {} + + HANDLE mFontResourceHandle; + Vector mFontNames; + bool mNeedsCairo; +}; + +} // gfx +} // mozilla + +#endif // mozilla_gfx_NativeFontResourceGDI_h \ No newline at end of file diff --git a/gfx/2d/PathRecording.cpp b/gfx/2d/PathRecording.cpp index 03fd4cb5a5..d41d6cf393 100644 --- a/gfx/2d/PathRecording.cpp +++ b/gfx/2d/PathRecording.cpp @@ -79,7 +79,7 @@ PathBuilderRecording::Finish() PathRecording::~PathRecording() { for (size_t i = 0; i < mStoredRecorders.size(); i++) { - mStoredRecorders[i]->RemoveStoredPath(this); + mStoredRecorders[i]->RemoveStoredObject(this); mStoredRecorders[i]->RecordEvent(RecordedPathDestruction(this)); } } diff --git a/gfx/2d/Preferences.cpp b/gfx/2d/Preferences.cpp new file mode 100644 index 0000000000..87a2a496ef --- /dev/null +++ b/gfx/2d/Preferences.cpp @@ -0,0 +1,60 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "Preferences.h" + +#include "mozilla/Assertions.h" +#include "mozilla/Vector.h" + +namespace mozilla { +namespace gfx { + +static PreferenceAccess* sAccess = nullptr; + +struct Int32Pref +{ + const char* name; + int32_t* varPtr; +}; + +static Vector& Int32Prefs() +{ + static Vector* sInt32Prefs = new Vector(); + return *sInt32Prefs; +} + +/* static */ +int32_t +PreferenceAccess::RegisterLivePref(const char* aName, int32_t* aVar, + int32_t aDefault) +{ + Int32Prefs().append(Int32Pref{ aName, aVar }); + return aDefault; +} + +/* static */ +void +PreferenceAccess::SetAccess(PreferenceAccess* aAccess) +{ + sAccess = aAccess; + if (!sAccess) { + return; + } + +#if defined(DEBUG) + static uint32_t sProvideAccessCount; + MOZ_ASSERT(!sProvideAccessCount++, + "ProvideAccess must only be called with non-nullptr once."); +#endif + + for (Int32Pref pref : Int32Prefs()) { + sAccess->LivePref(pref.name, pref.varPtr, *pref.varPtr); + } + Int32Prefs().clearAndFree(); +} + +} // namespace gfx +} // namespace mozilla \ No newline at end of file diff --git a/gfx/2d/Preferences.h b/gfx/2d/Preferences.h new file mode 100644 index 0000000000..2c673f40d2 --- /dev/null +++ b/gfx/2d/Preferences.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_gfx_Preferences_h +#define mozilla_gfx_Preferences_h + +namespace mozilla { +namespace gfx { + +class PreferenceAccess +{ +public: + virtual ~PreferenceAccess() {}; + + // This will be called with the derived class, so we will can register the + // callbacks with it. + static void SetAccess(PreferenceAccess* aAccess); + + static int32_t RegisterLivePref(const char* aName, int32_t* aVar, + int32_t aDefault); +protected: + // This should connect the variable aVar to be updated whenever a preference + // aName is modified. aDefault would be used if the preference is undefined, + // so that we always get the valid value for aVar. + virtual void LivePref(const char* aName, int32_t* aVar, int32_t aDefault) = 0; +}; + +} // namespace gfx +} // namespace mozilla + +#endif // mozilla_gfx_Preferences_h diff --git a/gfx/2d/RecordedEvent.cpp b/gfx/2d/RecordedEvent.cpp index 1b3876976f..c386453d83 100644 --- a/gfx/2d/RecordedEvent.cpp +++ b/gfx/2d/RecordedEvent.cpp @@ -4,11 +4,13 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "RecordedEvent.h" -#include "PathRecording.h" +#include "PathRecording.h" +#include "RecordingTypes.h" #include "Tools.h" #include "Filters.h" #include "Logging.h" +#include "SFNTData.h" namespace mozilla { namespace gfx { @@ -27,6 +29,16 @@ static std::string NameFromBackend(BackendType aType) } } +already_AddRefed +Translator::CreateDrawTarget(ReferencePtr aRefPtr, const IntSize &aSize, + SurfaceFormat aFormat) +{ + RefPtr newDT = + GetReferenceDrawTarget()->CreateSimilarDrawTarget(aSize, aFormat); + AddDrawTarget(aRefPtr, newDT); + return newDT.forget(); +} + #define LOAD_EVENT_TYPE(_typeenum, _class) \ case _typeenum: return new _class(aStream) @@ -66,6 +78,8 @@ RecordedEvent::LoadEventFromStream(std::istream &aStream, EventType aType) LOAD_EVENT_TYPE(MASKSURFACE, RecordedMaskSurface); LOAD_EVENT_TYPE(FILTERNODESETATTRIBUTE, RecordedFilterNodeSetAttribute); LOAD_EVENT_TYPE(FILTERNODESETINPUT, RecordedFilterNodeSetInput); + LOAD_EVENT_TYPE(CREATESIMILARDRAWTARGET, RecordedCreateSimilarDrawTarget); + LOAD_EVENT_TYPE(FONTDATA, RecordedFontData); default: return nullptr; } @@ -139,6 +153,10 @@ RecordedEvent::GetEventName(EventType aType) return "SetAttribute"; case FILTERNODESETINPUT: return "SetInput"; + case CREATESIMILARDRAWTARGET: + return "CreateSimilarDrawTarget"; + case FONTDATA: + return "FontData"; default: return "Unknown"; } @@ -366,10 +384,9 @@ void RecordedDrawTargetCreation::PlayEvent(Translator *aTranslator) const { RefPtr newDT = - aTranslator->GetReferenceDrawTarget()->CreateSimilarDrawTarget(mSize, mFormat); - aTranslator->AddDrawTarget(mRefPtr, newDT); + aTranslator->CreateDrawTarget(mRefPtr, mSize, mFormat); - if (mHasExistingData) { + if (newDT && mHasExistingData) { Rect dataRect(0, 0, mExistingData->GetSize().width, mExistingData->GetSize().height); newDT->DrawSurface(mExistingData, dataRect, dataRect); } @@ -452,6 +469,36 @@ RecordedDrawTargetDestruction::OutputSimpleEventInfo(stringstream &aStringStream aStringStream << "[" << mRefPtr << "] DrawTarget Destruction"; } +void +RecordedCreateSimilarDrawTarget::PlayEvent(Translator *aTranslator) const +{ + RefPtr newDT = + aTranslator->GetReferenceDrawTarget()->CreateSimilarDrawTarget(mSize, mFormat); + aTranslator->AddDrawTarget(mRefPtr, newDT); +} + +void +RecordedCreateSimilarDrawTarget::RecordToStream(ostream &aStream) const +{ + WriteElement(aStream, mRefPtr); + WriteElement(aStream, mSize); + WriteElement(aStream, mFormat); +} + +RecordedCreateSimilarDrawTarget::RecordedCreateSimilarDrawTarget(istream &aStream) + : RecordedEvent(CREATESIMILARDRAWTARGET) +{ + ReadElement(aStream, mRefPtr); + ReadElement(aStream, mSize); + ReadElement(aStream, mFormat); +} + +void +RecordedCreateSimilarDrawTarget::OutputSimpleEventInfo(stringstream &aStringStream) const +{ + aStringStream << "[" << mRefPtr << "] CreateSimilarDrawTarget (Size: " << mSize.width << "x" << mSize.height << ")"; +} + struct GenericPattern { GenericPattern(const PatternStorage &aStorage, Translator *aTranslator) @@ -1344,17 +1391,75 @@ RecordedSnapshot::OutputSimpleEventInfo(stringstream &aStringStream) const aStringStream << "[" << mRefPtr << "] Snapshot Created (DT: " << mDT << ")"; } -RecordedScaledFontCreation::~RecordedScaledFontCreation() +RecordedFontData::~RecordedFontData() { - delete [] mData; + delete[] mData; +} + +void +RecordedFontData::PlayEvent(Translator *aTranslator) const +{ + RefPtr fontResource = + Factory::CreateNativeFontResource(mData, mFontDetails.size, + aTranslator->GetDesiredFontType()); + aTranslator->AddNativeFontResource(mFontDetails.fontDataKey, fontResource); +} + +void +RecordedFontData::RecordToStream(std::ostream &aStream) const +{ + MOZ_ASSERT(mGetFontFileDataSucceeded); + + WriteElement(aStream, mFontDetails.fontDataKey); + WriteElement(aStream, mFontDetails.size); + aStream.write((const char*)mData, mFontDetails.size); +} + +void +RecordedFontData::OutputSimpleEventInfo(stringstream &aStringStream) const +{ + aStringStream << "Font Data of size " << mFontDetails.size; +} + +void +RecordedFontData::SetFontData(const uint8_t *aData, uint32_t aSize, uint32_t aIndex, Float aGlyphSize) +{ + mData = new uint8_t[aSize]; + memcpy(mData, aData, aSize); + mFontDetails.fontDataKey = SFNTData::GetUniqueKey(aData, aSize); + mFontDetails.size = aSize; + mFontDetails.index = aIndex; + mFontDetails.glyphSize = aGlyphSize; +} + +bool +RecordedFontData::GetFontDetails(RecordedFontDetails& fontDetails) +{ + if (!mGetFontFileDataSucceeded) { + return false; + } + + fontDetails.fontDataKey = mFontDetails.fontDataKey; + fontDetails.size = mFontDetails.size; + fontDetails.glyphSize = mFontDetails.glyphSize; + fontDetails.index = mFontDetails.index; + return true; +} + +RecordedFontData::RecordedFontData(istream &aStream) + : RecordedEvent(FONTDATA) +{ + ReadElement(aStream, mFontDetails.fontDataKey); + ReadElement(aStream, mFontDetails.size); + mData = new uint8_t[mFontDetails.size]; + aStream.read((char*)mData, mFontDetails.size); } void RecordedScaledFontCreation::PlayEvent(Translator *aTranslator) const { - RefPtr scaledFont = - Factory::CreateScaledFontForTrueTypeData(mData, mSize, mIndex, mGlyphSize, - aTranslator->GetDesiredFontType()); + NativeFontResource *fontResource = aTranslator->LookupNativeFontResource(mFontDataKey); + RefPtr scaledFont = fontResource->CreateScaledFont(mIndex, mGlyphSize); aTranslator->AddScaledFont(mRefPtr, scaledFont); } @@ -1362,10 +1467,9 @@ void RecordedScaledFontCreation::RecordToStream(std::ostream &aStream) const { WriteElement(aStream, mRefPtr); + WriteElement(aStream, mFontDataKey); WriteElement(aStream, mIndex); WriteElement(aStream, mGlyphSize); - WriteElement(aStream, mSize); - aStream.write((const char*)mData, mSize); } void @@ -1374,25 +1478,13 @@ RecordedScaledFontCreation::OutputSimpleEventInfo(stringstream &aStringStream) c aStringStream << "[" << mRefPtr << "] ScaledFont Created"; } -void -RecordedScaledFontCreation::SetFontData(const uint8_t *aData, uint32_t aSize, uint32_t aIndex, Float aGlyphSize) -{ - mData = new uint8_t[aSize]; - memcpy(mData, aData, aSize); - mSize = aSize; - mIndex = aIndex; - mGlyphSize = aGlyphSize; -} - RecordedScaledFontCreation::RecordedScaledFontCreation(istream &aStream) : RecordedEvent(SCALEDFONTCREATION) { ReadElement(aStream, mRefPtr); + ReadElement(aStream, mFontDataKey); ReadElement(aStream, mIndex); ReadElement(aStream, mGlyphSize); - ReadElement(aStream, mSize); - mData = new uint8_t[mSize]; - aStream.read((char*)mData, mSize); } void @@ -1479,6 +1571,7 @@ RecordedFilterNodeSetAttribute::PlayEvent(Translator *aTranslator) const REPLAY_SET_ATTRIBUTE(Rect, RECT); REPLAY_SET_ATTRIBUTE(IntRect, INTRECT); REPLAY_SET_ATTRIBUTE(Point, POINT); + REPLAY_SET_ATTRIBUTE(Matrix, MATRIX); REPLAY_SET_ATTRIBUTE(Matrix5x4, MATRIX5X4); REPLAY_SET_ATTRIBUTE(Point3D, POINT3D); REPLAY_SET_ATTRIBUTE(Color, COLOR); diff --git a/gfx/2d/RecordedEvent.h b/gfx/2d/RecordedEvent.h index 242bff632a..da94124a15 100644 --- a/gfx/2d/RecordedEvent.h +++ b/gfx/2d/RecordedEvent.h @@ -10,20 +10,24 @@ #include #include #include -#include "RecordingTypes.h" -#include "PathRecording.h" +#include namespace mozilla { namespace gfx { +struct PathOp; +class PathRecording; + +const uint32_t kMagicInt = 0xc001feed; + // A change in major revision means a change in event binary format, causing // loss of backwards compatibility. Old streams will not work in a player // using a newer major revision. And new streams will not work in a player // using an older major revision. -const uint16_t kMajorRevision = 3; +const uint16_t kMajorRevision = 4; // A change in minor revision means additions of new events. New streams will // not play in older players. -const uint16_t kMinorRevision = 2; +const uint16_t kMinorRevision = 0; struct ReferencePtr { @@ -58,6 +62,14 @@ struct ReferencePtr uint64_t mLongPtr; }; +struct RecordedFontDetails +{ + uint64_t fontDataKey; + uint32_t size; + uint32_t index; + Float glyphSize; +}; + // Used by the Azure drawing debugger (player2d) inline std::string StringFromPtr(ReferencePtr aPtr) { @@ -77,6 +89,7 @@ public: virtual FilterNode *LookupFilterNode(ReferencePtr aRefPtr) = 0; virtual GradientStops *LookupGradientStops(ReferencePtr aRefPtr) = 0; virtual ScaledFont *LookupScaledFont(ReferencePtr aRefPtr) = 0; + virtual NativeFontResource *LookupNativeFontResource(uint64_t aKey) = 0; virtual void AddDrawTarget(ReferencePtr aRefPtr, DrawTarget *aDT) = 0; virtual void RemoveDrawTarget(ReferencePtr aRefPtr) = 0; virtual void AddPath(ReferencePtr aRefPtr, Path *aPath) = 0; @@ -89,7 +102,12 @@ public: virtual void RemoveGradientStops(ReferencePtr aRefPtr) = 0; virtual void AddScaledFont(ReferencePtr aRefPtr, ScaledFont *aScaledFont) = 0; virtual void RemoveScaledFont(ReferencePtr aRefPtr) = 0; + virtual void AddNativeFontResource(uint64_t aKey, + NativeFontResource *aNativeFontResource) = 0; + virtual already_AddRefed CreateDrawTarget(ReferencePtr aRefPtr, + const IntSize &aSize, + SurfaceFormat aFormat); virtual DrawTarget *GetReferenceDrawTarget() = 0; virtual FontType GetDesiredFontType() = 0; }; @@ -171,10 +189,14 @@ public: FILTERNODEDESTRUCTION, DRAWFILTER, FILTERNODESETATTRIBUTE, - FILTERNODESETINPUT + FILTERNODESETINPUT, + CREATESIMILARDRAWTARGET, + FONTDATA, }; static const uint32_t kTotalEventTypes = RecordedEvent::FILTERNODESETINPUT + 1; + virtual ~RecordedEvent() {} + static std::string GetEventName(EventType aType); virtual void PlayEvent(Translator *aTranslator) const {} @@ -281,6 +303,34 @@ private: MOZ_IMPLICIT RecordedDrawTargetDestruction(std::istream &aStream); }; +class RecordedCreateSimilarDrawTarget : public RecordedEvent +{ +public: + RecordedCreateSimilarDrawTarget(ReferencePtr aRefPtr, const IntSize &aSize, + SurfaceFormat aFormat) + : RecordedEvent(CREATESIMILARDRAWTARGET) + , mRefPtr(aRefPtr) , mSize(aSize), mFormat(aFormat) + { + } + + virtual void PlayEvent(Translator *aTranslator) const; + + virtual void RecordToStream(std::ostream &aStream) const; + virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const; + + virtual std::string GetName() const { return "CreateSimilarDrawTarget"; } + virtual ReferencePtr GetObjectRef() const { return mRefPtr; } + + ReferencePtr mRefPtr; + IntSize mSize; + SurfaceFormat mFormat; + +private: + friend class RecordedEvent; + + MOZ_IMPLICIT RecordedCreateSimilarDrawTarget(std::istream &aStream); +}; + class RecordedFillRect : public RecordedDrawingEvent { public: RecordedFillRect(DrawTarget *aDT, const Rect &aRect, const Pattern &aPattern, const DrawOptions &aOptions) @@ -899,21 +949,59 @@ private: MOZ_IMPLICIT RecordedSnapshot(std::istream &aStream); }; +class RecordedFontData : public RecordedEvent { +public: + + static void FontDataProc(const uint8_t *aData, uint32_t aSize, + uint32_t aIndex, Float aGlyphSize, void* aBaton) + { + auto recordedFontData = static_cast(aBaton); + recordedFontData->SetFontData(aData, aSize, aIndex, aGlyphSize); + } + + explicit RecordedFontData(ScaledFont *aScaledFont) + : RecordedEvent(FONTDATA), mData(nullptr) + { + mGetFontFileDataSucceeded = aScaledFont->GetFontFileData(&FontDataProc, this); + } + + ~RecordedFontData(); + + virtual void PlayEvent(Translator *aTranslator) const; + + virtual void RecordToStream(std::ostream &aStream) const; + virtual void OutputSimpleEventInfo(std::stringstream &aStringStream) const; + + virtual std::string GetName() const { return "Font Data"; } + virtual ReferencePtr GetObjectRef() const { return nullptr; }; + + void SetFontData(const uint8_t *aData, uint32_t aSize, uint32_t aIndex, + Float aGlyphSize); + + bool GetFontDetails(RecordedFontDetails& fontDetails); + +private: + friend class RecordedEvent; + + uint8_t *mData; + RecordedFontDetails mFontDetails; + + bool mGetFontFileDataSucceeded = false; + + MOZ_IMPLICIT RecordedFontData(std::istream &aStream); +}; + class RecordedScaledFontCreation : public RecordedEvent { public: - static void FontDataProc(const uint8_t *aData, uint32_t aSize, uint32_t aIndex, Float aGlyphSize, void* aBaton) - { - static_cast(aBaton)->SetFontData(aData, aSize, aIndex, aGlyphSize); - } - RecordedScaledFontCreation(ReferencePtr aRefPtr, ScaledFont *aScaledFont) - : RecordedEvent(SCALEDFONTCREATION), mRefPtr(aRefPtr), mData(nullptr) + RecordedScaledFontCreation(ReferencePtr aRefPtr, + RecordedFontDetails aFontDetails) + : RecordedEvent(SCALEDFONTCREATION), mRefPtr(aRefPtr) + , mFontDataKey(aFontDetails.fontDataKey) + , mGlyphSize(aFontDetails.glyphSize) , mIndex(aFontDetails.index) { - aScaledFont->GetFontFileData(&FontDataProc, this); } - ~RecordedScaledFontCreation(); - virtual void PlayEvent(Translator *aTranslator) const; virtual void RecordToStream(std::ostream &aStream) const; @@ -922,14 +1010,11 @@ public: virtual std::string GetName() const { return "ScaledFont Creation"; } virtual ReferencePtr GetObjectRef() const { return mRefPtr; } - void SetFontData(const uint8_t *aData, uint32_t aSize, uint32_t aIndex, Float aGlyphSize); - private: friend class RecordedEvent; ReferencePtr mRefPtr; - uint8_t *mData; - uint32_t mSize; + uint64_t mFontDataKey; Float mGlyphSize; uint32_t mIndex; @@ -998,6 +1083,7 @@ public: ARGTYPE_RECT, ARGTYPE_INTRECT, ARGTYPE_POINT, + ARGTYPE_MATRIX, ARGTYPE_MATRIX5X4, ARGTYPE_POINT3D, ARGTYPE_COLOR, diff --git a/gfx/2d/SFNTData.cpp b/gfx/2d/SFNTData.cpp new file mode 100644 index 0000000000..23c42331e1 --- /dev/null +++ b/gfx/2d/SFNTData.cpp @@ -0,0 +1,240 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "SFNTData.h" + +#include + +#include "BigEndianInts.h" +#include "Logging.h" +#include "mozilla/HashFunctions.h" +#include "SFNTNameTable.h" + +namespace mozilla { +namespace gfx { + +#define TRUETYPE_TAG(a, b, c, d) ((a) << 24 | (b) << 16 | (c) << 8 | (d)) + +#pragma pack(push, 1) + +struct TTCHeader +{ + BigEndianUint32 ttcTag; // Always 'ttcf' + BigEndianUint32 version; // Fixed, 0x00010000 + BigEndianUint32 numFonts; +}; + +struct OffsetTable +{ + BigEndianUint32 sfntVersion; // Fixed, 0x00010000 for version 1.0. + BigEndianUint16 numTables; + BigEndianUint16 searchRange; // (Maximum power of 2 <= numTables) x 16. + BigEndianUint16 entrySelector; // Log2(maximum power of 2 <= numTables). + BigEndianUint16 rangeShift; // NumTables x 16-searchRange. +}; + +struct TableDirEntry +{ + BigEndianUint32 tag; // 4 -byte identifier. + BigEndianUint32 checkSum; // CheckSum for this table. + BigEndianUint32 offset; // Offset from beginning of TrueType font file. + BigEndianUint32 length; // Length of this table. + + friend bool operator<(const TableDirEntry& lhs, const uint32_t aTag) + { + return lhs.tag < aTag; + } +}; + +#pragma pack(pop) + +class SFNTData::Font +{ +public: + Font(const OffsetTable *aOffsetTable, const uint8_t *aFontData, + uint32_t aDataLength) + : mFontData(aFontData) + , mFirstDirEntry(reinterpret_cast(aOffsetTable + 1)) + , mEndOfDirEntries(mFirstDirEntry + aOffsetTable->numTables) + , mDataLength(aDataLength) + { + } + + bool GetU16FullName(mozilla::u16string& aU16FullName) + { + const TableDirEntry* dirEntry = + GetDirEntry(TRUETYPE_TAG('n', 'a', 'm', 'e')); + if (!dirEntry) { + gfxWarning() << "Name table entry not found."; + return false; + } + + UniquePtr nameTable = + SFNTNameTable::Create((mFontData + dirEntry->offset), dirEntry->length); + if (!nameTable) { + return false; + } + + return nameTable->GetU16FullName(aU16FullName); + } + +private: + + const TableDirEntry* + GetDirEntry(const uint32_t aTag) + { + const TableDirEntry* foundDirEntry = + std::lower_bound(mFirstDirEntry, mEndOfDirEntries, aTag); + + if (foundDirEntry == mEndOfDirEntries || foundDirEntry->tag != aTag) { + gfxWarning() << "Font data does not contain tag."; + return nullptr; + } + + if (mDataLength < (foundDirEntry->offset + foundDirEntry->length)) { + gfxWarning() << "Font data too short to contain table."; + return nullptr; + } + + return foundDirEntry; + } + + const uint8_t *mFontData; + const TableDirEntry *mFirstDirEntry; + const TableDirEntry *mEndOfDirEntries; + uint32_t mDataLength; +}; + +/* static */ +UniquePtr +SFNTData::Create(const uint8_t *aFontData, uint32_t aDataLength) +{ + MOZ_ASSERT(aFontData); + + // Check to see if this is a font collection. + if (aDataLength < sizeof(TTCHeader)) { + gfxWarning() << "Font data too short."; + return nullptr; + } + + const TTCHeader *ttcHeader = reinterpret_cast(aFontData); + if (ttcHeader->ttcTag == TRUETYPE_TAG('t', 't', 'c', 'f')) { + uint32_t numFonts = ttcHeader->numFonts; + if (aDataLength < sizeof(TTCHeader) + (numFonts * sizeof(BigEndianUint32))) { + gfxWarning() << "Font data too short to contain full TTC Header."; + return nullptr; + } + + UniquePtr sfntData(new SFNTData); + const BigEndianUint32* offset = + reinterpret_cast(aFontData + sizeof(TTCHeader)); + const BigEndianUint32* endOfOffsets = offset + numFonts; + while (offset != endOfOffsets) { + if (!sfntData->AddFont(aFontData, aDataLength, *offset)) { + return nullptr; + } + ++offset; + } + + return Move(sfntData); + } + + UniquePtr sfntData(new SFNTData); + if (!sfntData->AddFont(aFontData, aDataLength, 0)) { + return nullptr; + } + + return Move(sfntData); +} + +/* static */ +uint64_t +SFNTData::GetUniqueKey(const uint8_t *aFontData, uint32_t aDataLength) +{ + uint64_t hash; + UniquePtr sfntData = SFNTData::Create(aFontData, aDataLength); + mozilla::u16string firstName; + if (sfntData && sfntData->GetU16FullName(0, firstName)) { + hash = HashString(firstName.c_str(), firstName.length()); + } else { + gfxWarning() << "Failed to get name from font data hashing whole font."; + hash = HashString(aFontData, aDataLength); + } + + return hash << 32 | aDataLength;; +} + +SFNTData::~SFNTData() +{ + for (size_t i = 0; i < mFonts.length(); ++i) { + delete mFonts[i]; + } +} + +bool +SFNTData::GetU16FullName(uint32_t aIndex, mozilla::u16string& aU16FullName) +{ + if (aIndex >= mFonts.length()) { + gfxWarning() << "aIndex to font data too high."; + return false; + } + + return mFonts[aIndex]->GetU16FullName(aU16FullName); +} + +bool +SFNTData::GetU16FullNames(Vector& aU16FullNames) +{ + bool fontFound = false; + for (size_t i = 0; i < mFonts.length(); ++i) { + mozilla::u16string name; + if (mFonts[i]->GetU16FullName(name)) { + fontFound = true; + } + aU16FullNames.append(Move(name)); + } + + return fontFound; +} + +bool +SFNTData::GetIndexForU16Name(const mozilla::u16string& aU16FullName, + uint32_t* aIndex) +{ + for (size_t i = 0; i < mFonts.length(); ++i) { + mozilla::u16string name; + if (mFonts[i]->GetU16FullName(name) && name == aU16FullName) { + *aIndex = i; + return true; + } + } + + return false; +} + +bool +SFNTData::AddFont(const uint8_t *aFontData, uint32_t aDataLength, + uint32_t aOffset) +{ + uint32_t remainingLength = aDataLength - aOffset; + if (remainingLength < sizeof(OffsetTable)) { + gfxWarning() << "Font data too short to contain OffsetTable " << aOffset; + return false; + } + + const OffsetTable *offsetTable = + reinterpret_cast(aFontData + aOffset); + if (remainingLength < + sizeof(OffsetTable) + (offsetTable->numTables * sizeof(TableDirEntry))) { + gfxWarning() << "Font data too short to contain tables."; + return false; + } + + return mFonts.append(new Font(offsetTable, aFontData, aDataLength)); +} + +} // gfx +} // mozilla diff --git a/gfx/2d/SFNTData.h b/gfx/2d/SFNTData.h new file mode 100644 index 0000000000..5205dfa1c4 --- /dev/null +++ b/gfx/2d/SFNTData.h @@ -0,0 +1,93 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_gfx_SFNTData_h +#define mozilla_gfx_SFNTData_h + +#include "mozilla/UniquePtr.h" +#include "mozilla/Vector.h" +#include "u16string.h" + +namespace mozilla { +namespace gfx { + +class SFNTData final +{ +public: + + /** + * Creates an SFNTData if the header is a format that we understand and + * aDataLength is sufficient for the length information in the header data. + * Note that the data is NOT copied, so must exist the SFNTData's lifetime. + * + * @param aFontData the SFNT data. + * @param aDataLength length + * @return UniquePtr to a SFNTData or nullptr if the header is invalid. + */ + static UniquePtr Create(const uint8_t *aFontData, + uint32_t aDataLength); + + /** + * Creates a unique key for the given font data. + * + * @param aFontData the SFNT data + * @param aDataLength length + * @return unique key to be used for caching + */ + static uint64_t GetUniqueKey(const uint8_t *aFontData, uint32_t aDataLength); + + ~SFNTData(); + + /** + * Gets the full name from the name table of the font corresponding to the + * index. If the full name string is not present it will use the family space + * concatenated with the style. + * This will only read names that are already UTF16. + * + * @param aFontData SFNT data. + * @param aDataLength length of aFontData. + * @param aU16FullName string to be populated with the full name. + * @return true if the full name is successfully read. + */ + bool GetU16FullName(uint32_t aIndex, mozilla::u16string& aU16FullName); + + /** + * Populate a Vector with the first UTF16 full name from each name table of + * the fonts. If the full name string is not present it will use the family + * space concatenated with the style. + * This will only read names that are already UTF16. + * + * @param aU16FullNames the Vector to be populated. + * @return true if at least one name found otherwise false. + */ + bool GetU16FullNames(Vector& aU16FullNames); + + /** + * Returns the index for the first UTF16 name matching aU16FullName. + * + * @param aU16FullName full name to find. + * @param aIndex out param for the index if found. + * @return true if the full name is successfully read. + */ + bool GetIndexForU16Name(const mozilla::u16string& aU16FullName, uint32_t* aIndex); + +private: + + SFNTData() {} + + bool AddFont(const uint8_t *aFontData, uint32_t aDataLength, + uint32_t aOffset); + + // Internal representation of single font in font file. + class Font; + + Vector mFonts; +}; + +} // gfx +} // mozilla + +#endif // mozilla_gfx_SFNTData_h diff --git a/gfx/2d/SFNTNameTable.cpp b/gfx/2d/SFNTNameTable.cpp new file mode 100644 index 0000000000..1977c27371 --- /dev/null +++ b/gfx/2d/SFNTNameTable.cpp @@ -0,0 +1,257 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "SFNTNameTable.h" + +#include "BigEndianInts.h" +#include "Logging.h" +#include "mozilla/Move.h" + +namespace mozilla { +namespace gfx { + +static const BigEndianUint16 FORMAT_0 = 0; + +static const BigEndianUint16 NAME_ID_FAMILY = 1; +static const BigEndianUint16 NAME_ID_STYLE = 2; +static const BigEndianUint16 NAME_ID_FULL = 4; + +static const BigEndianUint16 PLATFORM_ID_UNICODE = 0; +static const BigEndianUint16 PLATFORM_ID_MAC = 1; +static const BigEndianUint16 PLATFORM_ID_MICROSOFT = 3; + +static const BigEndianUint16 ENCODING_ID_MICROSOFT_SYMBOL = 0; +static const BigEndianUint16 ENCODING_ID_MICROSOFT_UNICODEBMP = 1; +static const BigEndianUint16 ENCODING_ID_MICROSOFT_UNICODEFULL = 10; + +static const BigEndianUint16 LANG_ID_MAC_ENGLISH = 0; + +static const BigEndianUint16 LANG_ID_MICROSOFT_EN_US = 0x0409; + +#pragma pack(push, 1) + +// Name table has a header, followed by name records, followed by string data. +struct NameHeader +{ + BigEndianUint16 format; // Format selector (=0). + BigEndianUint16 count; // Number of name records. + BigEndianUint16 stringOffset; // Offset to string storage from start of table. +}; + +struct NameRecord +{ + BigEndianUint16 platformID; + BigEndianUint16 encodingID; // Platform-specific encoding ID + BigEndianUint16 languageID; + BigEndianUint16 nameID; + BigEndianUint16 length; // String length in bytes. + BigEndianUint16 offset; // String offset from start of storage in bytes. +}; + +#pragma pack(pop) + +/* static */ +UniquePtr +SFNTNameTable::Create(const uint8_t *aNameData, uint32_t aDataLength) +{ + MOZ_ASSERT(aNameData); + + if (aDataLength < sizeof(NameHeader)) { + gfxWarning() << "Name data too short to contain NameHeader."; + return nullptr; + } + + const NameHeader *nameHeader = reinterpret_cast(aNameData); + if (nameHeader->format != FORMAT_0) { + gfxWarning() << "Only Name Table Format 0 is supported."; + return nullptr; + } + + uint16_t stringOffset = nameHeader->stringOffset; + + if (stringOffset != + sizeof(NameHeader) + (nameHeader->count * sizeof(NameRecord))) { + gfxWarning() << "Name table string offset is incorrect."; + return nullptr; + } + + if (aDataLength < stringOffset) { + gfxWarning() << "Name data too short to contain name records."; + return nullptr; + } + + return UniquePtr( + new SFNTNameTable(nameHeader, aNameData, aDataLength)); +} + +SFNTNameTable::SFNTNameTable(const NameHeader *aNameHeader, + const uint8_t *aNameData, uint32_t aDataLength) + : mFirstRecord(reinterpret_cast(aNameData + + sizeof(NameHeader))) + , mEndOfRecords(mFirstRecord + aNameHeader->count) + , mStringData(aNameData + aNameHeader->stringOffset) + , mStringDataLength(aDataLength - aNameHeader->stringOffset) +{ + MOZ_ASSERT(reinterpret_cast(aNameHeader) == aNameData); +} + +#if defined(XP_MACOSX) +static const BigEndianUint16 CANONICAL_LANG_ID = LANG_ID_MAC_ENGLISH; +static const BigEndianUint16 PLATFORM_ID = PLATFORM_ID_MAC; +#else +static const BigEndianUint16 CANONICAL_LANG_ID = LANG_ID_MICROSOFT_EN_US; +static const BigEndianUint16 PLATFORM_ID = PLATFORM_ID_MICROSOFT; +#endif + +static bool +IsUTF16Encoding(const NameRecord *aNameRecord) +{ + if (aNameRecord->platformID == PLATFORM_ID_MICROSOFT && + (aNameRecord->encodingID == ENCODING_ID_MICROSOFT_UNICODEBMP || + aNameRecord->encodingID == ENCODING_ID_MICROSOFT_SYMBOL)) { + return true; + } + + if (aNameRecord->platformID == PLATFORM_ID_UNICODE) { + return true; + } + + return false; +} + +static NameRecordMatchers* +CreateCanonicalU16Matchers(const BigEndianUint16& aNameID) +{ + NameRecordMatchers *matchers = new NameRecordMatchers(); + + // First, look for the English name (this will normally succeed). + matchers->append( + [=](const NameRecord *aNameRecord) { + return aNameRecord->nameID == aNameID && + aNameRecord->languageID == CANONICAL_LANG_ID && + aNameRecord->platformID == PLATFORM_ID && + IsUTF16Encoding(aNameRecord); + }); + + // Second, look for all languages. + matchers->append( + [=](const NameRecord *aNameRecord) { + return aNameRecord->nameID == aNameID && + aNameRecord->platformID == PLATFORM_ID && + IsUTF16Encoding(aNameRecord); + }); + +#if defined(XP_MACOSX) + // On Mac may be dealing with font that only has Microsoft name entries. + matchers->append( + [=](const NameRecord *aNameRecord) { + return aNameRecord->nameID == aNameID && + aNameRecord->languageID == LANG_ID_MICROSOFT_EN_US && + aNameRecord->platformID == PLATFORM_ID_MICROSOFT && + IsUTF16Encoding(aNameRecord); + }); + matchers->append( + [=](const NameRecord *aNameRecord) { + return aNameRecord->nameID == aNameID && + aNameRecord->platformID == PLATFORM_ID_MICROSOFT && + IsUTF16Encoding(aNameRecord); + }); +#endif + + return matchers; +} + +static const NameRecordMatchers& +FullNameMatchers() +{ + static const NameRecordMatchers *sFullNameMatchers = + CreateCanonicalU16Matchers(NAME_ID_FULL); + return *sFullNameMatchers; +} + +static const NameRecordMatchers& +FamilyMatchers() +{ + static const NameRecordMatchers *sFamilyMatchers = + CreateCanonicalU16Matchers(NAME_ID_FAMILY); + return *sFamilyMatchers; +} + +static const NameRecordMatchers& +StyleMatchers() +{ + static const NameRecordMatchers *sStyleMatchers = + CreateCanonicalU16Matchers(NAME_ID_STYLE); + return *sStyleMatchers; +} + +bool +SFNTNameTable::GetU16FullName(mozilla::u16string& aU16FullName) +{ + if (ReadU16Name(FullNameMatchers(), aU16FullName)) { + return true; + } + + // If the full name record doesn't exist create the name from the family space + // concatenated with the style. + mozilla::u16string familyName; + if (!ReadU16Name(FamilyMatchers(), familyName)) { + return false; + } + + mozilla::u16string styleName; + if (!ReadU16Name(StyleMatchers(), styleName)) { + return false; + } + + aU16FullName.assign(Move(familyName)); + aU16FullName.append(MOZ_UTF16(" ")); + aU16FullName.append(styleName); + return true; +} + +bool +SFNTNameTable::ReadU16Name(const NameRecordMatchers& aMatchers, + mozilla::u16string& aU16Name) +{ + MOZ_ASSERT(!aMatchers.empty()); + + for (size_t i = 0; i < aMatchers.length(); ++i) { + const NameRecord* record = mFirstRecord; + while (record != mEndOfRecords) { + if (aMatchers[i](record)) { + return ReadU16NameFromRecord(record, aU16Name); + } + ++record; + } + } + + return false; +} + +bool +SFNTNameTable::ReadU16NameFromRecord(const NameRecord *aNameRecord, + mozilla::u16string& aU16Name) +{ + uint32_t offset = aNameRecord->offset; + uint32_t length = aNameRecord->length; + if (mStringDataLength < offset + length) { + gfxWarning() << "Name data too short to contain name string."; + return false; + } + + const uint8_t *startOfName = mStringData + offset; + size_t actualLength = length / sizeof(char16_t); + UniquePtr nameData(new char16_t[actualLength]); + NativeEndian::copyAndSwapFromBigEndian(nameData.get(), startOfName, + actualLength); + + aU16Name.assign(nameData.get(), actualLength); + return true; +} + +} // gfx +} // mozilla diff --git a/gfx/2d/SFNTNameTable.h b/gfx/2d/SFNTNameTable.h new file mode 100644 index 0000000000..f5e2ac31b9 --- /dev/null +++ b/gfx/2d/SFNTNameTable.h @@ -0,0 +1,67 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_gfx_SFNTNameTable_h +#define mozilla_gfx_SFNTNameTable_h + +#include "mozilla/Function.h" +#include "mozilla/UniquePtr.h" +#include "mozilla/Vector.h" +#include "u16string.h" + +namespace mozilla { +namespace gfx { + +struct NameHeader; +struct NameRecord; + +typedef Vector> NameRecordMatchers; + +class SFNTNameTable final +{ +public: + + /** + * Creates a SFNTNameTable if the header data is valid. Note that the data is + * NOT copied, so must exist for the lifetime of the table. + * + * @param aNameData the Name Table data. + * @param aDataLength length + * @return UniquePtr to a SFNTNameTable or nullptr if the header is invalid. + */ + static UniquePtr Create(const uint8_t *aNameData, + uint32_t aDataLength); + + /** + * Gets the full name from the name table. If the full name string is not + * present it will use the family space concatenated with the style. + * This will only read names that are already UTF16. + * + * @param aU16FullName string to be populated with the full name. + * @return true if the full name is successfully read. + */ + bool GetU16FullName(mozilla::u16string& aU16FullName); + +private: + + SFNTNameTable(const NameHeader *aNameHeader, const uint8_t *aNameData, + uint32_t aDataLength); + + bool ReadU16Name(const NameRecordMatchers& aMatchers, mozilla::u16string& aU16Name); + + bool ReadU16NameFromRecord(const NameRecord *aNameRecord, + mozilla::u16string& aU16Name); + + const NameRecord *mFirstRecord; + const NameRecord *mEndOfRecords; + const uint8_t *mStringData; + const uint32_t mStringDataLength; +}; + +} // gfx +} // mozilla + +#endif // mozilla_gfx_SFNTNameTable_h diff --git a/gfx/2d/ScaledFontBase.cpp b/gfx/2d/ScaledFontBase.cpp index d1706e1706..ba3143f761 100644 --- a/gfx/2d/ScaledFontBase.cpp +++ b/gfx/2d/ScaledFontBase.cpp @@ -45,6 +45,33 @@ ScaledFontBase::ScaledFontBase(Float aSize) #endif } +#ifdef USE_CAIRO_SCALED_FONT +bool +ScaledFontBase::PopulateCairoScaledFont() +{ + cairo_font_face_t* cairoFontFace = GetCairoFontFace(); + if (!cairoFontFace) { + return false; + } + + cairo_matrix_t sizeMatrix; + cairo_matrix_t identityMatrix; + + cairo_matrix_init_scale(&sizeMatrix, mSize, mSize); + cairo_matrix_init_identity(&identityMatrix); + + cairo_font_options_t *fontOptions = cairo_font_options_create(); + + mScaledFont = cairo_scaled_font_create(cairoFontFace, &sizeMatrix, + &identityMatrix, fontOptions); + + cairo_font_options_destroy(fontOptions); + cairo_font_face_destroy(cairoFontFace); + + return (cairo_scaled_font_status(mScaledFont) == CAIRO_STATUS_SUCCESS); +} +#endif + #ifdef USE_SKIA SkPath ScaledFontBase::GetSkiaPathForGlyphs(const GlyphBuffer &aBuffer) diff --git a/gfx/2d/ScaledFontBase.h b/gfx/2d/ScaledFontBase.h index 31630a9165..9cbc4e6276 100644 --- a/gfx/2d/ScaledFontBase.h +++ b/gfx/2d/ScaledFontBase.h @@ -45,6 +45,7 @@ public: virtual FontType GetType() const { return FontType::SKIA; } #ifdef USE_CAIRO_SCALED_FONT + bool PopulateCairoScaledFont(); cairo_scaled_font_t* GetCairoScaledFont() { return mScaledFont; } void SetCairoScaledFont(cairo_scaled_font_t* font); #endif @@ -56,6 +57,8 @@ protected: SkPath GetSkiaPathForGlyphs(const GlyphBuffer &aBuffer); #endif #ifdef USE_CAIRO_SCALED_FONT + // Overridders should ensure the cairo_font_face_t has been addrefed. + virtual cairo_font_face_t* GetCairoFontFace() { return nullptr; } cairo_scaled_font_t* mScaledFont; #endif Float mSize; diff --git a/gfx/2d/ScaledFontDWrite.cpp b/gfx/2d/ScaledFontDWrite.cpp index 885140be41..6da47bf4d0 100644 --- a/gfx/2d/ScaledFontDWrite.cpp +++ b/gfx/2d/ScaledFontDWrite.cpp @@ -3,143 +3,26 @@ * 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/. */ +#include "DrawTargetD2D.h" #include "ScaledFontDWrite.h" #include "PathD2D.h" -#include "DrawTargetD2D.h" -#include "Logging.h" + +#ifdef USE_SKIA +#include "PathSkia.h" +#include "skia/include/core/SkPaint.h" +#include "skia/include/core/SkPath.h" +#include "skia/include/ports/SkTypeface_win.h" +#endif #include +#ifdef USE_CAIRO_SCALED_FONT +#include "cairo-win32.h" +#endif + namespace mozilla { namespace gfx { -struct ffReferenceKey -{ - uint8_t *mData; - uint32_t mSize; -}; - -class DWriteFontFileLoader : public IDWriteFontFileLoader -{ -public: - DWriteFontFileLoader() - { - } - - // IUnknown interface - IFACEMETHOD(QueryInterface)(IID const& iid, OUT void** ppObject) - { - if (iid == __uuidof(IDWriteFontFileLoader)) { - *ppObject = static_cast(this); - return S_OK; - } else if (iid == __uuidof(IUnknown)) { - *ppObject = static_cast(this); - return S_OK; - } else { - return E_NOINTERFACE; - } - } - - IFACEMETHOD_(ULONG, AddRef)() - { - return 1; - } - - IFACEMETHOD_(ULONG, Release)() - { - return 1; - } - - // IDWriteFontFileLoader methods - /** - * Important! Note the key here -has- to be a pointer to an - * ffReferenceKey object. - */ - virtual HRESULT STDMETHODCALLTYPE - CreateStreamFromKey(void const* fontFileReferenceKey, - UINT32 fontFileReferenceKeySize, - OUT IDWriteFontFileStream** fontFileStream); - - /** - * Gets the singleton loader instance. Note that when using this font - * loader, the key must be a pointer to an FallibleTArray. This - * array will be empty when the function returns. - */ - static IDWriteFontFileLoader* Instance() - { - if (!mInstance) { - mInstance = new DWriteFontFileLoader(); - DrawTargetD2D::GetDWriteFactory()-> - RegisterFontFileLoader(mInstance); - } - return mInstance; - } - -private: - static IDWriteFontFileLoader* mInstance; -}; - -class DWriteFontFileStream : public IDWriteFontFileStream -{ -public: - /** - * Used by the FontFileLoader to create a new font stream, - * this font stream is created from data in memory. The memory - * passed may be released after object creation, it will be - * copied internally. - * - * @param aData Font data - */ - DWriteFontFileStream(uint8_t *aData, uint32_t aSize); - ~DWriteFontFileStream(); - - // IUnknown interface - IFACEMETHOD(QueryInterface)(IID const& iid, OUT void** ppObject) - { - if (iid == __uuidof(IDWriteFontFileStream)) { - *ppObject = static_cast(this); - return S_OK; - } else if (iid == __uuidof(IUnknown)) { - *ppObject = static_cast(this); - return S_OK; - } else { - return E_NOINTERFACE; - } - } - - IFACEMETHOD_(ULONG, AddRef)() - { - ++mRefCnt; - return mRefCnt; - } - - IFACEMETHOD_(ULONG, Release)() - { - --mRefCnt; - if (mRefCnt == 0) { - delete this; - return 0; - } - return mRefCnt; - } - - // IDWriteFontFileStream methods - virtual HRESULT STDMETHODCALLTYPE ReadFileFragment(void const** fragmentStart, - UINT64 fileOffset, - UINT64 fragmentSize, - OUT void** fragmentContext); - - virtual void STDMETHODCALLTYPE ReleaseFileFragment(void* fragmentContext); - - virtual HRESULT STDMETHODCALLTYPE GetFileSize(OUT UINT64* fileSize); - - virtual HRESULT STDMETHODCALLTYPE GetLastWriteTime(OUT UINT64* lastWriteTime); - -private: - std::vector mData; - uint32_t mRefCnt; -}; - static BYTE GetSystemTextQuality() { @@ -213,99 +96,6 @@ DoGrayscale(IDWriteFontFace *aDWFace, Float ppem) return true; } -IDWriteFontFileLoader* DWriteFontFileLoader::mInstance = nullptr; - -HRESULT STDMETHODCALLTYPE -DWriteFontFileLoader::CreateStreamFromKey(const void *fontFileReferenceKey, - UINT32 fontFileReferenceKeySize, - IDWriteFontFileStream **fontFileStream) -{ - if (!fontFileReferenceKey || !fontFileStream) { - return E_POINTER; - } - - const ffReferenceKey *key = static_cast(fontFileReferenceKey); - *fontFileStream = - new DWriteFontFileStream(key->mData, key->mSize); - - if (!*fontFileStream) { - return E_OUTOFMEMORY; - } - (*fontFileStream)->AddRef(); - return S_OK; -} - -DWriteFontFileStream::DWriteFontFileStream(uint8_t *aData, uint32_t aSize) - : mRefCnt(0) -{ - mData.resize(aSize); - memcpy(&mData.front(), aData, aSize); -} - -DWriteFontFileStream::~DWriteFontFileStream() -{ -} - -HRESULT STDMETHODCALLTYPE -DWriteFontFileStream::GetFileSize(UINT64 *fileSize) -{ - *fileSize = mData.size(); - return S_OK; -} - -HRESULT STDMETHODCALLTYPE -DWriteFontFileStream::GetLastWriteTime(UINT64 *lastWriteTime) -{ - return E_NOTIMPL; -} - -HRESULT STDMETHODCALLTYPE -DWriteFontFileStream::ReadFileFragment(const void **fragmentStart, - UINT64 fileOffset, - UINT64 fragmentSize, - void **fragmentContext) -{ - // We are required to do bounds checking. - if (fileOffset + fragmentSize > mData.size()) { - return E_FAIL; - } - - // truncate the 64 bit fileOffset to size_t sized index into mData - size_t index = static_cast(fileOffset); - - // We should be alive for the duration of this. - *fragmentStart = &mData[index]; - *fragmentContext = nullptr; - return S_OK; -} - -void STDMETHODCALLTYPE -DWriteFontFileStream::ReleaseFileFragment(void *fragmentContext) -{ -} - -ScaledFontDWrite::ScaledFontDWrite(uint8_t *aData, uint32_t aSize, - uint32_t aIndex, Float aGlyphSize) - : ScaledFontBase(aGlyphSize) -{ - IDWriteFactory *factory = DrawTargetD2D::GetDWriteFactory(); - - ffReferenceKey key; - key.mData = aData; - key.mSize = aSize; - - RefPtr fontFile; - if (FAILED(factory->CreateCustomFontFileReference(&key, sizeof(ffReferenceKey), DWriteFontFileLoader::Instance(), getter_AddRefs(fontFile)))) { - gfxWarning() << "Failed to load font file from data!"; - return; - } - - IDWriteFontFile *ff = fontFile; - if (FAILED(factory->CreateFontFace(DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &ff, aIndex, DWRITE_FONT_SIMULATIONS_NONE, getter_AddRefs(mFontFace)))) { - gfxWarning() << "Failed to create font face from font file data!"; - } -} - already_AddRefed ScaledFontDWrite::GetPathForGlyphs(const GlyphBuffer &aBuffer, const DrawTarget *aTarget) { @@ -323,6 +113,20 @@ ScaledFontDWrite::GetPathForGlyphs(const GlyphBuffer &aBuffer, const DrawTarget return pathBuilder->Finish(); } + +#ifdef USE_SKIA +SkTypeface* +ScaledFontDWrite::GetSkTypeface() +{ + MOZ_ASSERT(mFont); + if (!mTypeface) { + IDWriteFactory *factory = DrawTargetD2D::GetDWriteFactory(); + mTypeface = SkCreateTypefaceFromDWriteFont(factory, mFontFace, mFont, mFontFamily); + } + return mTypeface; +} +#endif + void ScaledFontDWrite::CopyGlyphsToBuilder(const GlyphBuffer &aBuffer, PathBuilder *aBuilder, BackendType aBackendType, const Matrix *aTransformHint) { @@ -431,5 +235,17 @@ ScaledFontDWrite::GetDefaultAAMode() return defaultMode; } +#ifdef USE_CAIRO_SCALED_FONT +cairo_font_face_t* +ScaledFontDWrite::GetCairoFontFace() +{ + if (!mFontFace) { + return nullptr; + } + + return cairo_dwrite_font_face_create_for_dwrite_fontface(nullptr, mFontFace); +} +#endif + } } diff --git a/gfx/2d/ScaledFontDWrite.h b/gfx/2d/ScaledFontDWrite.h index 5e1a564a48..65f25d89ff 100644 --- a/gfx/2d/ScaledFontDWrite.h +++ b/gfx/2d/ScaledFontDWrite.h @@ -20,9 +20,18 @@ public: MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(ScaledFontDwrite) ScaledFontDWrite(IDWriteFontFace *aFont, Float aSize) : ScaledFontBase(aSize) + , mFont(nullptr) + , mFontFamily(nullptr) , mFontFace(aFont) {} - ScaledFontDWrite(uint8_t *aData, uint32_t aSize, uint32_t aIndex, Float aGlyphSize); + + ScaledFontDWrite(IDWriteFont* aFont, IDWriteFontFamily* aFontFamily, + IDWriteFontFace *aFontFace, Float aSize) + : ScaledFontBase(aSize) + , mFont(aFont) + , mFontFamily(aFontFamily) + , mFontFace(aFontFace) + {} virtual FontType GetType() const { return FontType::DWRITE; } @@ -36,14 +45,17 @@ public: virtual AntialiasMode GetDefaultAAMode(); #ifdef USE_SKIA - virtual SkTypeface* GetSkTypeface() - { - MOZ_ASSERT(false, "Skia and DirectWrite do not mix"); - return nullptr; - } + virtual SkTypeface* GetSkTypeface(); #endif + RefPtr mFont; + RefPtr mFontFamily; RefPtr mFontFace; + +protected: +#ifdef USE_CAIRO_SCALED_FONT + cairo_font_face_t* GetCairoFontFace() override; +#endif }; class GlyphRenderingOptionsDWrite : public GlyphRenderingOptions diff --git a/gfx/2d/ScaledFontWin.cpp b/gfx/2d/ScaledFontWin.cpp index 5747274c18..4b22dc2fdc 100644 --- a/gfx/2d/ScaledFontWin.cpp +++ b/gfx/2d/ScaledFontWin.cpp @@ -4,21 +4,77 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "ScaledFontWin.h" -#include "ScaledFontBase.h" + +#include "AutoHelpersWin.h" +#include "Logging.h" +#include "SFNTData.h" #ifdef USE_SKIA #include "skia/include/ports/SkTypeface_win.h" #endif +#ifdef USE_CAIRO_SCALED_FONT +#include "cairo-win32.h" +#endif + namespace mozilla { namespace gfx { -ScaledFontWin::ScaledFontWin(LOGFONT* aFont, Float aSize) +ScaledFontWin::ScaledFontWin(LOGFONTW* aFont, Float aSize) : ScaledFontBase(aSize) , mLogFont(*aFont) { } +bool +ScaledFontWin::GetFontFileData(FontFileDataOutput aDataCallback, void *aBaton) +{ + AutoDC dc; + AutoSelectFont font(dc.GetDC(), &mLogFont); + + // Check for a font collection first. + uint32_t table = 0x66637474; // 'ttcf' + uint32_t tableSize = ::GetFontData(dc.GetDC(), table, 0, nullptr, 0); + if (tableSize == GDI_ERROR) { + // Try as if just a single font. + table = 0; + tableSize = ::GetFontData(dc.GetDC(), table, 0, nullptr, 0); + if (tableSize == GDI_ERROR) { + return false; + } + } + + UniquePtr fontData(new uint8_t[tableSize]); + + uint32_t sizeGot = + ::GetFontData(dc.GetDC(), table, 0, fontData.get(), tableSize); + if (sizeGot != tableSize) { + return false; + } + + // If it's a font collection then attempt to get the index. + uint32_t index = 0; + if (table != 0) { + UniquePtr sfntData = SFNTData::Create(fontData.get(), + tableSize); + if (!sfntData) { + gfxWarning() << "Failed to create SFNTData for GetFontFileData."; + return false; + } + + // We cast here because for VS2015 char16_t != wchar_t, even though they are + // both 16 bit. + if (!sfntData->GetIndexForU16Name( + reinterpret_cast(mLogFont.lfFaceName), &index)) { + gfxWarning() << "Failed to get index for face name."; + return false; + } + } + + aDataCallback(fontData.get(), tableSize, index, mSize, aBaton); + return true; +} + #ifdef USE_SKIA SkTypeface* ScaledFontWin::GetSkTypeface() { @@ -29,6 +85,16 @@ SkTypeface* ScaledFontWin::GetSkTypeface() } #endif +#ifdef USE_CAIRO_SCALED_FONT +cairo_font_face_t* +ScaledFontWin::GetCairoFontFace() +{ + if (mLogFont.lfFaceName[0] == 0) { + return nullptr; + } + return cairo_win32_font_face_create_for_logfontw(&mLogFont); +} +#endif } } diff --git a/gfx/2d/ScaledFontWin.h b/gfx/2d/ScaledFontWin.h index 20c95ed3db..f697a34106 100644 --- a/gfx/2d/ScaledFontWin.h +++ b/gfx/2d/ScaledFontWin.h @@ -16,17 +16,26 @@ class ScaledFontWin : public ScaledFontBase { public: MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(ScaledFontWin) - ScaledFontWin(LOGFONT* aFont, Float aSize); + ScaledFontWin(LOGFONTW* aFont, Float aSize); virtual FontType GetType() const { return FontType::GDI; } + + bool GetFontFileData(FontFileDataOutput aDataCallback, void *aBaton) override; + #ifdef USE_SKIA virtual SkTypeface* GetSkTypeface(); #endif + +protected: +#ifdef USE_CAIRO_SCALED_FONT + cairo_font_face_t* GetCairoFontFace() override; +#endif + private: #ifdef USE_SKIA friend class DrawTargetSkia; #endif - LOGFONT mLogFont; + LOGFONTW mLogFont; }; } diff --git a/gfx/2d/moz.build b/gfx/2d/moz.build index 8a189aed89..c42f0ae223 100644 --- a/gfx/2d/moz.build +++ b/gfx/2d/moz.build @@ -22,6 +22,7 @@ EXPORTS.mozilla.gfx += [ 'Coord.h', 'CriticalSection.h', 'DataSurfaceHelpers.h', + 'DrawEventRecorder.h', 'DrawTargetTiled.h', 'Filters.h', 'Helpers.h', @@ -37,7 +38,10 @@ EXPORTS.mozilla.gfx += [ 'PathHelpers.h', 'PatternHelpers.h', 'Point.h', + 'Preferences.h', 'Quaternion.h', + 'RecordedEvent.h', + 'RecordingTypes.h', 'Rect.h', 'Scale.h', 'ScaleFactor.h', @@ -67,6 +71,8 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': 'ExtendInputEffectD2D1.cpp', 'FilterNodeD2D1.cpp', 'JobScheduler_win32.cpp', + 'NativeFontResourceDWrite.cpp', + 'NativeFontResourceGDI.cpp', 'PathD2D.cpp', 'RadialGradientEffectD2D1.cpp', 'ScaledFontDWrite.cpp', @@ -154,11 +160,14 @@ UNIFIED_SOURCES += [ 'PathCairo.cpp', 'PathHelpers.cpp', 'PathRecording.cpp', + 'Preferences.cpp', 'Quaternion.cpp', 'RecordedEvent.cpp', 'Scale.cpp', 'ScaledFontBase.cpp', 'ScaledFontCairo.cpp', + 'SFNTData.cpp', + 'SFNTNameTable.cpp', 'SourceSurfaceCairo.cpp', 'SourceSurfaceRawData.cpp', ] @@ -195,10 +204,3 @@ if CONFIG['MOZ_X11']: CXXFLAGS += CONFIG['XCFLAGS'] LOCAL_INCLUDES += CONFIG['SKIA_INCLUDES'] - -if CONFIG['OS_ARCH'] == 'WINNT': - # Due to bug 796023, we can't have -DUNICODE and -D_UNICODE; defining those - # macros changes the type of LOGFONT to LOGFONTW instead of LOGFONTA. This - # changes the symbol names of exported C++ functions that use LOGFONT. - del DEFINES['UNICODE'] - del DEFINES['_UNICODE'] diff --git a/gfx/2d/u16string.h b/gfx/2d/u16string.h new file mode 100644 index 0000000000..61380ee6b3 --- /dev/null +++ b/gfx/2d/u16string.h @@ -0,0 +1,24 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_gfx_u16string_h +#define mozilla_gfx_u16string_h + +#include + +#include "mozilla/Char16.h" + +namespace mozilla { + +#if defined(_MSC_VER) +typedef std::u16string u16string; +#else +typedef std::basic_string u16string; +#endif + +} // mozilla + +#endif // mozilla_gfx_u16string_h diff --git a/gfx/gl/moz.build b/gfx/gl/moz.build index abf637db35..94b1d588ca 100644 --- a/gfx/gl/moz.build +++ b/gfx/gl/moz.build @@ -170,8 +170,5 @@ CFLAGS += CONFIG['TK_CFLAGS'] LOCAL_INCLUDES += CONFIG['SKIA_INCLUDES'] -if CONFIG['OS_ARCH'] == 'WINNT': - del DEFINES['UNICODE'] - if CONFIG['CLANG_CXX']: CXXFLAGS += ['-Wshadow'] diff --git a/gfx/skia/generate_mozbuild.py b/gfx/skia/generate_mozbuild.py index ee16c67b86..da3ee16433 100755 --- a/gfx/skia/generate_mozbuild.py +++ b/gfx/skia/generate_mozbuild.py @@ -73,6 +73,10 @@ if CONFIG['GKMEDIAS_SHARED_LIBRARY']: DEFINES['SKIA_DLL'] = 1 DEFINES['GR_DLL'] = 1 +if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': + DEFINES['UNICODE'] = True + DEFINES['_UNICODE'] = True + # We should autogenerate these SSE related flags. if CONFIG['_MSC_VER']: @@ -83,6 +87,7 @@ if CONFIG['_MSC_VER']: SOURCES['skia/src/opts/SkBitmapProcState_opts_SSSE3.cpp'].flags += ['/arch:SSE2 -DSK_CPU_SSE_LEVEL=31'] SOURCES['skia/src/opts/SkBlitRow_opts_SSE2.cpp'].flags += ['/arch:SSE2 -DSK_CPU_SSE_LEVEL=20'] SOURCES['skia/src/opts/SkBlitRow_opts_SSE4.cpp'].flags += ['/arch:SSE2 -DSK_CPU_SSE_LEVEL=41'] + SOURCES['skia/src/opts/SkOpts_sse2.cpp'].flags += ['/arch:SSE2 -DSK_CPU_SSE_LEVEL=20'] SOURCES['skia/src/opts/SkOpts_ssse3.cpp'].flags += ['/arch:SSE2 -DSK_CPU_SSE_LEVEL=31'] SOURCES['skia/src/opts/SkOpts_sse41.cpp'].flags += ['/arch:SSE2 -DSK_CPU_SSE_LEVEL=41'] SOURCES['skia/src/opts/SkOpts_avx.cpp'].flags += ['/arch:AVX -DSK_CPU_SSE_LEVEL=51'] @@ -92,6 +97,7 @@ if CONFIG['INTEL_ARCHITECTURE'] and CONFIG['GNU_CC']: SOURCES['skia/src/opts/SkBitmapProcState_opts_SSSE3.cpp'].flags += ['-mssse3'] SOURCES['skia/src/opts/SkBlitRow_opts_SSE2.cpp'].flags += CONFIG['SSE2_FLAGS'] SOURCES['skia/src/opts/SkBlitRow_opts_SSE4.cpp'].flags += ['-msse4.1'] + SOURCES['skia/src/opts/SkOpts_sse2.cpp'].flags += CONFIG['SSE2_FLAGS'] SOURCES['skia/src/opts/SkOpts_ssse3.cpp'].flags += ['-mssse3'] SOURCES['skia/src/opts/SkOpts_sse41.cpp'].flags += ['-msse4.1'] SOURCES['skia/src/opts/SkOpts_avx.cpp'].flags += ['-mavx'] @@ -222,6 +228,7 @@ def generate_separated_sources(platform_sources): 'intel': { # There is currently no x86-specific opt for SkTextureCompression 'skia/src/opts/opts_check_x86.cpp', + 'skia/src/opts/SkOpts_sse2.cpp', 'skia/src/opts/SkOpts_ssse3.cpp', 'skia/src/opts/SkOpts_sse41.cpp', 'skia/src/opts/SkOpts_avx.cpp', diff --git a/gfx/skia/moz.build b/gfx/skia/moz.build index a2cb943f0a..6a17c043ac 100644 --- a/gfx/skia/moz.build +++ b/gfx/skia/moz.build @@ -603,6 +603,7 @@ if CONFIG['INTEL_ARCHITECTURE']: 'skia/src/opts/SkBlitRow_opts_SSE2.cpp', 'skia/src/opts/SkBlitRow_opts_SSE4.cpp', 'skia/src/opts/SkOpts_avx.cpp', + 'skia/src/opts/SkOpts_sse2.cpp', 'skia/src/opts/SkOpts_sse41.cpp', 'skia/src/opts/SkOpts_ssse3.cpp', ] @@ -690,6 +691,10 @@ if CONFIG['GKMEDIAS_SHARED_LIBRARY']: DEFINES['SKIA_DLL'] = 1 DEFINES['GR_DLL'] = 1 +if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': + DEFINES['UNICODE'] = True + DEFINES['_UNICODE'] = True + # We should autogenerate these SSE related flags. if CONFIG['_MSC_VER']: @@ -700,6 +705,7 @@ if CONFIG['_MSC_VER']: SOURCES['skia/src/opts/SkBitmapProcState_opts_SSSE3.cpp'].flags += ['/arch:SSE2 -DSK_CPU_SSE_LEVEL=31'] SOURCES['skia/src/opts/SkBlitRow_opts_SSE2.cpp'].flags += ['/arch:SSE2 -DSK_CPU_SSE_LEVEL=20'] SOURCES['skia/src/opts/SkBlitRow_opts_SSE4.cpp'].flags += ['/arch:SSE2 -DSK_CPU_SSE_LEVEL=41'] + SOURCES['skia/src/opts/SkOpts_sse2.cpp'].flags += ['/arch:SSE2 -DSK_CPU_SSE_LEVEL=20'] SOURCES['skia/src/opts/SkOpts_ssse3.cpp'].flags += ['/arch:SSE2 -DSK_CPU_SSE_LEVEL=31'] SOURCES['skia/src/opts/SkOpts_sse41.cpp'].flags += ['/arch:SSE2 -DSK_CPU_SSE_LEVEL=41'] SOURCES['skia/src/opts/SkOpts_avx.cpp'].flags += ['/arch:AVX -DSK_CPU_SSE_LEVEL=51'] @@ -709,6 +715,7 @@ if CONFIG['INTEL_ARCHITECTURE'] and CONFIG['GNU_CC']: SOURCES['skia/src/opts/SkBitmapProcState_opts_SSSE3.cpp'].flags += ['-mssse3'] SOURCES['skia/src/opts/SkBlitRow_opts_SSE2.cpp'].flags += CONFIG['SSE2_FLAGS'] SOURCES['skia/src/opts/SkBlitRow_opts_SSE4.cpp'].flags += ['-msse4.1'] + SOURCES['skia/src/opts/SkOpts_sse2.cpp'].flags += CONFIG['SSE2_FLAGS'] SOURCES['skia/src/opts/SkOpts_ssse3.cpp'].flags += ['-mssse3'] SOURCES['skia/src/opts/SkOpts_sse41.cpp'].flags += ['-msse4.1'] SOURCES['skia/src/opts/SkOpts_avx.cpp'].flags += ['-mavx'] diff --git a/gfx/skia/skia/include/ports/SkTypeface_win.h b/gfx/skia/skia/include/ports/SkTypeface_win.h index b7373986c9..72104555d4 100644 --- a/gfx/skia/skia/include/ports/SkTypeface_win.h +++ b/gfx/skia/skia/include/ports/SkTypeface_win.h @@ -9,6 +9,7 @@ #define SkTypeface_win_DEFINED #include "SkTypeface.h" +#include #ifdef SK_BUILD_FOR_WIN @@ -41,6 +42,16 @@ class SkFontMgr; class SkRemotableFontMgr; struct IDWriteFactory; +/** + * Like the other Typeface create methods, this returns a new reference to the + * corresponding typeface for the specified dwrite font. The caller is responsible + * for calling unref() when it is finished. + */ +SK_API SkTypeface* SkCreateTypefaceFromDWriteFont(IDWriteFactory* aFactory, + IDWriteFontFace* aFontFace, + IDWriteFont* aFont, + IDWriteFontFamily* aFontFamily); + SK_API SkFontMgr* SkFontMgr_New_GDI(); SK_API SkFontMgr* SkFontMgr_New_DirectWrite(IDWriteFactory* factory = NULL); diff --git a/gfx/skia/skia/src/core/SkOpts.cpp b/gfx/skia/skia/src/core/SkOpts.cpp index 77666f06b3..fc70a570db 100644 --- a/gfx/skia/skia/src/core/SkOpts.cpp +++ b/gfx/skia/skia/src/core/SkOpts.cpp @@ -85,6 +85,7 @@ namespace SkOpts { decltype(matrix_affine) matrix_affine = sk_default::matrix_affine; // Each Init_foo() is defined in src/opts/SkOpts_foo.cpp. + void Init_sse2(); void Init_ssse3(); void Init_sse41(); void Init_sse42() {} @@ -97,6 +98,7 @@ namespace SkOpts { #if defined(SK_CPU_X86) && !defined(SK_BUILD_FOR_IOS) uint32_t abcd[] = {0,0,0,0}; cpuid(abcd); + if (abcd[3] & (1<<26)) { Init_sse2(); } if (abcd[2] & (1<< 9)) { Init_ssse3(); } if (abcd[2] & (1<<19)) { Init_sse41(); } if (abcd[2] & (1<<20)) { Init_sse42(); } diff --git a/gfx/skia/skia/src/gpu/gl/win/GrGLCreateNativeInterface_win.cpp b/gfx/skia/skia/src/gpu/gl/win/GrGLCreateNativeInterface_win.cpp index b0eaa548f1..b3766d9a82 100644 --- a/gfx/skia/skia/src/gpu/gl/win/GrGLCreateNativeInterface_win.cpp +++ b/gfx/skia/skia/src/gpu/gl/win/GrGLCreateNativeInterface_win.cpp @@ -17,7 +17,7 @@ class AutoLibraryUnload { public: AutoLibraryUnload(const char* moduleName) { - fModule = LoadLibrary(moduleName); + fModule = LoadLibraryA(moduleName); } ~AutoLibraryUnload() { if (fModule) { diff --git a/gfx/skia/skia/src/opts/SkOpts_sse2.cpp b/gfx/skia/skia/src/opts/SkOpts_sse2.cpp new file mode 100644 index 0000000000..8cb5bd0274 --- /dev/null +++ b/gfx/skia/skia/src/opts/SkOpts_sse2.cpp @@ -0,0 +1,44 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkOpts.h" +#define SK_OPTS_NS sk_sse2 +#include "SkBlitMask_opts.h" +#include "SkBlitRow_opts.h" +#include "SkBlurImageFilter_opts.h" +#include "SkColorCubeFilter_opts.h" +#include "SkMatrix_opts.h" +#include "SkMorphologyImageFilter_opts.h" +#include "SkUtils_opts.h" +#include "SkXfermode_opts.h" + +namespace SkOpts { + void Init_sse2() { + memset16 = sk_sse2::memset16; + memset32 = sk_sse2::memset32; + create_xfermode = sk_sse2::create_xfermode; + color_cube_filter_span = sk_sse2::color_cube_filter_span; + + box_blur_xx = sk_sse2::box_blur_xx; + box_blur_xy = sk_sse2::box_blur_xy; + box_blur_yx = sk_sse2::box_blur_yx; + + dilate_x = sk_sse2::dilate_x; + dilate_y = sk_sse2::dilate_y; + erode_x = sk_sse2::erode_x; + erode_y = sk_sse2::erode_y; + + blit_mask_d32_a8 = sk_sse2::blit_mask_d32_a8; + + blit_row_color32 = sk_sse2::blit_row_color32; + + matrix_translate = sk_sse2::matrix_translate; + matrix_scale_translate = sk_sse2::matrix_scale_translate; + matrix_affine = sk_sse2::matrix_affine; + } +} + diff --git a/gfx/skia/skia/src/opts/SkXfermode_opts.h b/gfx/skia/skia/src/opts/SkXfermode_opts.h index 69f2b420f5..5a037ceb03 100644 --- a/gfx/skia/skia/src/opts/SkXfermode_opts.h +++ b/gfx/skia/skia/src/opts/SkXfermode_opts.h @@ -15,7 +15,7 @@ namespace { // Most xfermodes can be done most efficiently 4 pixels at a time in 8 or 16-bit fixed point. -#define XFERMODE(Name) static Sk4px SK_VECTORCALL Name(Sk4px s, Sk4px d) +#define XFERMODE(Name) inline Sk4px Name(const Sk4px& d, const Sk4px& s) XFERMODE(Clear) { return Sk4px::DupPMColor(0); } XFERMODE(Src) { return s; } @@ -23,13 +23,13 @@ XFERMODE(Dst) { return d; } XFERMODE(SrcIn) { return s.approxMulDiv255(d.alphas() ); } XFERMODE(SrcOut) { return s.approxMulDiv255(d.alphas().inv()); } XFERMODE(SrcOver) { return s + d.approxMulDiv255(s.alphas().inv()); } -XFERMODE(DstIn) { return SrcIn (d,s); } -XFERMODE(DstOut) { return SrcOut (d,s); } -XFERMODE(DstOver) { return SrcOver(d,s); } +XFERMODE(DstIn) { return SrcIn (s,d); } +XFERMODE(DstOut) { return SrcOut (s,d); } +XFERMODE(DstOver) { return SrcOver(s,d); } // [ S * Da + (1 - Sa) * D] XFERMODE(SrcATop) { return (s * d.alphas() + d * s.alphas().inv()).div255(); } -XFERMODE(DstATop) { return SrcATop(d,s); } +XFERMODE(DstATop) { return SrcATop(s,d); } //[ S * (1 - Da) + (1 - Sa) * D ] XFERMODE(Xor) { return (s * d.alphas().inv() + d * s.alphas().inv()).div255(); } // [S + D ] @@ -79,7 +79,7 @@ XFERMODE(HardLight) { auto colors = (both + isLite.thenElse(lite, dark)).div255(); return alphas.zeroColors() + colors.zeroAlphas(); } -XFERMODE(Overlay) { return HardLight(d,s); } +XFERMODE(Overlay) { return HardLight(s,d); } XFERMODE(Darken) { auto sa = s.alphas(), @@ -110,7 +110,7 @@ XFERMODE(Lighten) { #undef XFERMODE // Some xfermodes use math like divide or sqrt that's best done in floats 1 pixel at a time. -#define XFERMODE(Name) static Sk4f SK_VECTORCALL Name(Sk4f d, Sk4f s) +#define XFERMODE(Name) inline Sk4f Name(const Sk4f& d, const Sk4f& s) static inline Sk4f a_rgb(const Sk4f& a, const Sk4f& rgb) { static_assert(SK_A32_SHIFT == 24, ""); @@ -181,15 +181,15 @@ XFERMODE(SoftLight) { // A reasonable fallback mode for doing AA is to simply apply the transfermode first, // then linearly interpolate the AA. -template -static Sk4px SK_VECTORCALL xfer_aa(Sk4px s, Sk4px d, Sk4px aa) { - Sk4px bw = Mode(s, d); +template +inline Sk4px xfer_aa(const Sk4px& d, const Sk4px& s, const Sk4px& aa) { + Sk4px bw = Mode(d, s); return (bw * aa + d * aa.inv()).div255(); } // For some transfermodes we specialize AA, either for correctness or performance. #define XFERMODE_AA(Name) \ - template <> Sk4px SK_VECTORCALL xfer_aa(Sk4px s, Sk4px d, Sk4px aa) + template <> inline Sk4px xfer_aa(const Sk4px& d, const Sk4px& s, const Sk4px& aa) // Plus' clamp needs to happen after AA. skia:3852 XFERMODE_AA(Plus) { // [ clamp( (1-AA)D + (AA)(S+D) ) == clamp(D + AA*S) ] @@ -198,54 +198,38 @@ XFERMODE_AA(Plus) { // [ clamp( (1-AA)D + (AA)(S+D) ) == clamp(D + AA*S) ] #undef XFERMODE_AA +template class Sk4pxXfermode : public SkProcCoeffXfermode { public: - typedef Sk4px (SK_VECTORCALL *Proc4)(Sk4px, Sk4px); - typedef Sk4px (SK_VECTORCALL *AAProc4)(Sk4px, Sk4px, Sk4px); - - Sk4pxXfermode(const ProcCoeff& rec, SkXfermode::Mode mode, Proc4 proc4, AAProc4 aaproc4) - : INHERITED(rec, mode) - , fProc4(proc4) - , fAAProc4(aaproc4) {} + Sk4pxXfermode(const ProcCoeff& rec, SkXfermode::Mode mode) + : INHERITED(rec, mode) {} void xfer32(SkPMColor dst[], const SkPMColor src[], int n, const SkAlpha aa[]) const override { if (nullptr == aa) { - Sk4px::MapDstSrc(n, dst, src, [&](const Sk4px& dst4, const Sk4px& src4) { - return fProc4(src4, dst4); - }); + Sk4px::MapDstSrc(n, dst, src, Proc4); } else { - Sk4px::MapDstSrcAlpha(n, dst, src, aa, - [&](const Sk4px& dst4, const Sk4px& src4, const Sk4px& alpha) { - return fAAProc4(src4, dst4, alpha); - }); + Sk4px::MapDstSrcAlpha(n, dst, src, aa, AAProc4); } } void xfer16(uint16_t dst[], const SkPMColor src[], int n, const SkAlpha aa[]) const override { if (nullptr == aa) { - Sk4px::MapDstSrc(n, dst, src, [&](const Sk4px& dst4, const Sk4px& src4) { - return fProc4(src4, dst4); - }); + Sk4px::MapDstSrc(n, dst, src, Proc4); } else { - Sk4px::MapDstSrcAlpha(n, dst, src, aa, - [&](const Sk4px& dst4, const Sk4px& src4, const Sk4px& alpha) { - return fAAProc4(src4, dst4, alpha); - }); + Sk4px::MapDstSrcAlpha(n, dst, src, aa, AAProc4); } } private: - Proc4 fProc4; - AAProc4 fAAProc4; typedef SkProcCoeffXfermode INHERITED; }; +template class Sk4fXfermode : public SkProcCoeffXfermode { public: - typedef Sk4f (SK_VECTORCALL *ProcF)(Sk4f, Sk4f); - Sk4fXfermode(const ProcCoeff& rec, SkXfermode::Mode mode, ProcF procf) - : INHERITED(rec, mode) - , fProcF(procf) {} + Sk4fXfermode(const ProcCoeff& rec, SkXfermode::Mode mode) + : INHERITED(rec, mode) {} void xfer32(SkPMColor dst[], const SkPMColor src[], int n, const SkAlpha aa[]) const override { for (int i = 0; i < n; i++) { @@ -273,20 +257,19 @@ private: return c; } inline SkPMColor xfer32(SkPMColor dst, SkPMColor src) const { - return Round(fProcF(Load(dst), Load(src))); + return Round(ProcF(Load(dst), Load(src))); } inline SkPMColor xfer32(SkPMColor dst, SkPMColor src, SkAlpha aa) const { Sk4f s(Load(src)), d(Load(dst)), - b(fProcF(d,s)); + b(ProcF(d,s)); // We do aa in full float precision before going back down to bytes, because we can! Sk4f a = Sk4f(aa) * Sk4f(1.0f/255); b = b*a + d*(Sk4f(1)-a); return Round(b); } - ProcF fProcF; typedef SkProcCoeffXfermode INHERITED; }; @@ -297,7 +280,7 @@ namespace SK_OPTS_NS { static SkXfermode* create_xfermode(const ProcCoeff& rec, SkXfermode::Mode mode) { switch (mode) { #define CASE(Mode) \ - case SkXfermode::k##Mode##_Mode: return new Sk4pxXfermode(rec, mode, &Mode, &xfer_aa) + case SkXfermode::k##Mode##_Mode: return new Sk4pxXfermode >(rec, mode) CASE(Clear); CASE(Src); CASE(Dst); @@ -323,7 +306,7 @@ static SkXfermode* create_xfermode(const ProcCoeff& rec, SkXfermode::Mode mode) #undef CASE #define CASE(Mode) \ - case SkXfermode::k##Mode##_Mode: return new Sk4fXfermode(rec, mode, &Mode) + case SkXfermode::k##Mode##_Mode: return new Sk4fXfermode(rec, mode) CASE(ColorDodge); CASE(ColorBurn); CASE(SoftLight); diff --git a/gfx/skia/skia/src/ports/SkFontHost_win.cpp b/gfx/skia/skia/src/ports/SkFontHost_win.cpp index 2e03a44578..892be56c99 100644 --- a/gfx/skia/skia/src/ports/SkFontHost_win.cpp +++ b/gfx/skia/skia/src/ports/SkFontHost_win.cpp @@ -27,6 +27,7 @@ #include "SkString.h" #include "SkTemplates.h" #include "SkTypeface_win.h" +#include "SkTypeface_win_dw.h" #include "SkTypefaceCache.h" #include "SkUtils.h" @@ -330,6 +331,18 @@ SkTypeface* SkCreateTypefaceFromLOGFONT(const LOGFONT& origLF) { return face; } +/*** + * This guy is public. + */ + +SkTypeface* SkCreateTypefaceFromDWriteFont(IDWriteFactory* aFactory, + IDWriteFontFace* aFontFace, + IDWriteFont* aFont, + IDWriteFontFamily* aFontFamily) +{ + return DWriteFontTypeface::Create(aFactory, aFontFace, aFont, aFontFamily); +} + /** * The created SkTypeface takes ownership of fontMemResource. */ diff --git a/gfx/skia/skia/src/ports/SkOSLibrary_win.cpp b/gfx/skia/skia/src/ports/SkOSLibrary_win.cpp index 69754db375..a1249f893b 100644 --- a/gfx/skia/skia/src/ports/SkOSLibrary_win.cpp +++ b/gfx/skia/skia/src/ports/SkOSLibrary_win.cpp @@ -12,7 +12,7 @@ #include void* DynamicLoadLibrary(const char* libraryName) { - return LoadLibrary(libraryName); + return LoadLibraryA(libraryName); } void* GetProcedureAddress(void* library, const char* functionName) { diff --git a/gfx/src/nsDeviceContext.cpp b/gfx/src/nsDeviceContext.cpp index e6e37f67d1..913a9a9a43 100644 --- a/gfx/src/nsDeviceContext.cpp +++ b/gfx/src/nsDeviceContext.cpp @@ -314,30 +314,10 @@ nsDeviceContext::SetDPI() { float dpi = -1.0f; - // PostScript, PDF and Mac (when printing) all use 72 dpi - // Use a printing DC to determine the other dpi values - if (mPrintingSurface) { - switch (mPrintingSurface->GetType()) { - case gfxSurfaceType::PDF: - case gfxSurfaceType::PS: - case gfxSurfaceType::Quartz: - dpi = 72.0f; - break; -#ifdef XP_WIN - case gfxSurfaceType::Win32: - case gfxSurfaceType::Win32Printing: { - HDC dc = reinterpret_cast(mPrintingSurface.get())->GetDC(); - int32_t OSVal = GetDeviceCaps(dc, LOGPIXELSY); - dpi = 144.0f; - mPrintingScale = float(OSVal) / dpi; - break; - } -#endif - default: - NS_NOTREACHED("Unexpected printing surface type"); - break; - } - + // Use the printing DC to determine DPI values, if we have one. + if (mDeviceContextSpec) { + dpi = mDeviceContextSpec->GetDPI(); + mPrintingScale = mDeviceContextSpec->GetPrintingScale(); mAppUnitsPerDevPixelAtUnitFullZoom = NS_lround((AppUnitsPerCSSPixel() * 96) / dpi); } else { @@ -420,6 +400,12 @@ nsDeviceContext::CreateRenderingContext() return nullptr; } + RefPtr recorder; + nsresult rv = mDeviceContextSpec->GetDrawEventRecorder(getter_AddRefs(recorder)); + if (NS_SUCCEEDED(rv) && recorder) { + dt = gfx::Factory::CreateRecordingDrawTarget(recorder, dt); + } + #ifdef XP_MACOSX dt->AddUserData(&gfxContext::sDontUseAsSourceKey, dt, nullptr); #endif @@ -526,18 +512,16 @@ nsDeviceContext::InitForPrinting(nsIDeviceContextSpec *aDevice) nsresult nsDeviceContext::BeginDocument(const nsAString& aTitle, - char16_t* aPrintToFileName, + const nsAString& aPrintToFileName, int32_t aStartPage, int32_t aEndPage) { - static const char16_t kEmpty[] = { '\0' }; - nsresult rv; + nsresult rv = mPrintingSurface->BeginPrinting(aTitle, aPrintToFileName); - rv = mPrintingSurface->BeginPrinting(aTitle, - nsDependentString(aPrintToFileName ? aPrintToFileName : kEmpty)); - - if (NS_SUCCEEDED(rv) && mDeviceContextSpec) - rv = mDeviceContextSpec->BeginDocument(aTitle, aPrintToFileName, aStartPage, aEndPage); + if (NS_SUCCEEDED(rv) && mDeviceContextSpec) { + rv = mDeviceContextSpec->BeginDocument(aTitle, aPrintToFileName, + aStartPage, aEndPage); + } return rv; } @@ -698,34 +682,7 @@ nsDeviceContext::CalcPrintingSize() gfxSize size(0, 0); switch (mPrintingSurface->GetType()) { - case gfxSurfaceType::Image: - inPoints = false; - size = reinterpret_cast(mPrintingSurface.get())->GetSize(); - break; - -#if defined(MOZ_PDF_PRINTING) - case gfxSurfaceType::PDF: - inPoints = true; - size = reinterpret_cast(mPrintingSurface.get())->GetSize(); - break; -#endif - -#ifdef MOZ_WIDGET_GTK - case gfxSurfaceType::PS: - inPoints = true; - size = reinterpret_cast(mPrintingSurface.get())->GetSize(); - break; -#endif - -#ifdef XP_MACOSX - case gfxSurfaceType::Quartz: - inPoints = true; // this is really only true when we're printing - size = reinterpret_cast(mPrintingSurface.get())->GetSize(); - break; -#endif - #ifdef XP_WIN - case gfxSurfaceType::Win32: case gfxSurfaceType::Win32Printing: { inPoints = false; @@ -740,10 +697,8 @@ nsDeviceContext::CalcPrintingSize() break; } #endif - default: - gfxCriticalError() << "Printing to unknown surface type " << (int)mPrintingSurface->GetType(); - NS_ERROR("trying to print to unknown surface type"); + size = mPrintingSurface->GetSize(); } if (inPoints) { diff --git a/gfx/src/nsDeviceContext.h b/gfx/src/nsDeviceContext.h index 3f54e61adc..975ad620b4 100644 --- a/gfx/src/nsDeviceContext.h +++ b/gfx/src/nsDeviceContext.h @@ -182,8 +182,8 @@ public: * EndDocument() or AbortDocument(). * * @param aTitle - title of Document - * @param aPrintToFileName - name of file to print to, if nullptr - * then don't print to file + * @param aPrintToFileName - name of file to print to, if empty then don't + * print to file * @param aStartPage - starting page number (must be greater than zero) * @param aEndPage - ending page number (must be less than or * equal to number of pages) @@ -191,7 +191,7 @@ public: * @return error status */ nsresult BeginDocument(const nsAString& aTitle, - char16_t* aPrintToFileName, + const nsAString& aPrintToFileName, int32_t aStartPage, int32_t aEndPage); diff --git a/gfx/thebes/gfxContext.cpp b/gfx/thebes/gfxContext.cpp index 47a85ad9ba..659f80cf0c 100644 --- a/gfx/thebes/gfxContext.cpp +++ b/gfx/thebes/gfxContext.cpp @@ -68,7 +68,6 @@ PatternFromState::operator mozilla::gfx::Pattern&() gfxContext::gfxContext(DrawTarget *aTarget, const Point& aDeviceOffset) : mPathIsRect(false) , mTransformChanged(false) - , mRefCairo(nullptr) , mDT(aTarget) , mOriginalDT(aTarget) { @@ -98,9 +97,6 @@ gfxContext::ContextForDrawTarget(DrawTarget* aTarget) gfxContext::~gfxContext() { - if (mRefCairo) { - cairo_destroy(mRefCairo); - } for (int i = mStateStack.Length() - 1; i >= 0; i--) { for (unsigned int c = 0; c < mStateStack[i].pushedClips.Length(); c++) { mDT->PopClip(); @@ -136,25 +132,38 @@ gfxContext::CurrentSurface(gfxFloat *dx, gfxFloat *dy) return nullptr; } -cairo_t * -gfxContext::GetCairo() +static void +DestroyRefCairo(void* aData) { - if (mDT->GetBackendType() == BackendType::CAIRO) { - cairo_t *ctx = - (cairo_t*)mDT->GetNativeSurface(NativeSurfaceType::CAIRO_CONTEXT); - if (ctx) { - return ctx; + cairo_t* refCairo = static_cast(aData); + MOZ_ASSERT(refCairo); + cairo_destroy(refCairo); +} + +/* static */ cairo_t * +gfxContext::RefCairo(DrawTarget* aDT) +{ + // DrawTargets that don't use a Cairo backend can be given a 1x1 "reference" + // |cairo_t*|, stored in the DrawTarget's user data, for doing font-related + // operations. + static UserDataKey sRefCairo; + + cairo_t* refCairo = nullptr; + if (aDT->GetBackendType() == BackendType::CAIRO) { + refCairo = static_cast + (aDT->GetNativeSurface(NativeSurfaceType::CAIRO_CONTEXT)); + if (refCairo) { + return refCairo; } } - if (mRefCairo) { - // Set transform! - return mRefCairo; + refCairo = static_cast(aDT->GetUserData(&sRefCairo)); + if (!refCairo) { + refCairo = cairo_create(gfxPlatform::GetPlatform()->ScreenReferenceSurface()->CairoSurface()); + aDT->AddUserData(&sRefCairo, refCairo, DestroyRefCairo); } - mRefCairo = cairo_create(gfxPlatform::GetPlatform()->ScreenReferenceSurface()->CairoSurface()); - - return mRefCairo; + return refCairo; } void @@ -212,6 +221,7 @@ already_AddRefed gfxContext::GetPath() void gfxContext::SetPath(Path* path) { MOZ_ASSERT(path->GetBackendType() == mDT->GetBackendType() || + path->GetBackendType() == BackendType::RECORDING || (mDT->GetBackendType() == BackendType::DIRECT2D1_1 && path->GetBackendType() == BackendType::DIRECT2D)); mPath = path; mPathBuilder = nullptr; @@ -1373,7 +1383,7 @@ gfxContext::GetRoundOffsetsToPixels(bool *aRoundX, bool *aRoundY) // Print backends set CAIRO_HINT_METRICS_OFF. *aRoundY = true; - cairo_t *cr = GetCairo(); + cairo_t *cr = gfxContext::RefCairo(GetDrawTarget()); cairo_scaled_font_t *scaled_font = cairo_get_scaled_font(cr); // bug 1198921 - this sometimes fails under Windows for whatver reason diff --git a/gfx/thebes/gfxContext.h b/gfx/thebes/gfxContext.h index e2a5c55e45..f7c423e1f8 100644 --- a/gfx/thebes/gfxContext.h +++ b/gfx/thebes/gfxContext.h @@ -85,10 +85,10 @@ public: } /** - * Return the raw cairo_t object. - * XXX this should go away at some point. + * Return the reference cairo_t object from aDT. + * XXX this should be moved into gfxFont at some point. */ - cairo_t *GetCairo(); + static cairo_t* RefCairo(mozilla::gfx::DrawTarget* aDT); mozilla::gfx::DrawTarget *GetDrawTarget() { return mDT; } diff --git a/gfx/thebes/gfxDWriteCommon.cpp b/gfx/thebes/gfxDWriteCommon.cpp index e91388f326..405a6acd72 100644 --- a/gfx/thebes/gfxDWriteCommon.cpp +++ b/gfx/thebes/gfxDWriteCommon.cpp @@ -5,8 +5,128 @@ #include "gfxDWriteCommon.h" +#include + +#include "mozilla/Atomics.h" + +static mozilla::Atomic sNextFontFileKey; +static std::unordered_map sFontFileStreams; + IDWriteFontFileLoader* gfxDWriteFontFileLoader::mInstance = nullptr; +class gfxDWriteFontFileStream final : public IDWriteFontFileStream +{ +public: + /** + * Used by the FontFileLoader to create a new font stream, + * this font stream is created from data in memory. The memory + * passed may be released after object creation, it will be + * copied internally. + * + * @param aData Font data + */ + gfxDWriteFontFileStream(FallibleTArray *aData, + uint64_t aFontFileKey); + ~gfxDWriteFontFileStream(); + + // IUnknown interface + IFACEMETHOD(QueryInterface)(IID const& iid, OUT void** ppObject) + { + if (iid == __uuidof(IDWriteFontFileStream)) { + *ppObject = static_cast(this); + return S_OK; + } + else if (iid == __uuidof(IUnknown)) { + *ppObject = static_cast(this); + return S_OK; + } + else { + return E_NOINTERFACE; + } + } + + IFACEMETHOD_(ULONG, AddRef)() + { + NS_PRECONDITION(int32_t(mRefCnt) >= 0, "illegal refcnt"); + ++mRefCnt; + return mRefCnt; + } + + IFACEMETHOD_(ULONG, Release)() + { + NS_PRECONDITION(0 != mRefCnt, "dup release"); + --mRefCnt; + if (mRefCnt == 0) { + delete this; + return 0; + } + return mRefCnt; + } + + // IDWriteFontFileStream methods + virtual HRESULT STDMETHODCALLTYPE ReadFileFragment(void const** fragmentStart, + UINT64 fileOffset, + UINT64 fragmentSize, + OUT void** fragmentContext); + + virtual void STDMETHODCALLTYPE ReleaseFileFragment(void* fragmentContext); + + virtual HRESULT STDMETHODCALLTYPE GetFileSize(OUT UINT64* fileSize); + + virtual HRESULT STDMETHODCALLTYPE GetLastWriteTime(OUT UINT64* lastWriteTime); + +private: + FallibleTArray mData; + nsAutoRefCnt mRefCnt; + uint64_t mFontFileKey; +}; + +gfxDWriteFontFileStream::gfxDWriteFontFileStream(FallibleTArray *aData, + uint64_t aFontFileKey) + : mFontFileKey(aFontFileKey) +{ + mData.SwapElements(*aData); +} + +gfxDWriteFontFileStream::~gfxDWriteFontFileStream() +{ + sFontFileStreams.erase(mFontFileKey); +} + +HRESULT STDMETHODCALLTYPE +gfxDWriteFontFileStream::GetFileSize(UINT64 *fileSize) +{ + *fileSize = mData.Length(); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE +gfxDWriteFontFileStream::GetLastWriteTime(UINT64 *lastWriteTime) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE +gfxDWriteFontFileStream::ReadFileFragment(const void **fragmentStart, + UINT64 fileOffset, + UINT64 fragmentSize, + void **fragmentContext) +{ + // We are required to do bounds checking. + if (fileOffset + fragmentSize > (UINT64)mData.Length()) { + return E_FAIL; + } + // We should be alive for the duration of this. + *fragmentStart = &mData[fileOffset]; + *fragmentContext = nullptr; + return S_OK; +} + +void STDMETHODCALLTYPE +gfxDWriteFontFileStream::ReleaseFileFragment(void *fragmentContext) +{ +} + HRESULT STDMETHODCALLTYPE gfxDWriteFontFileLoader::CreateStreamFromKey(const void *fontFileReferenceKey, UINT32 fontFileReferenceKeySize, @@ -16,56 +136,42 @@ gfxDWriteFontFileLoader::CreateStreamFromKey(const void *fontFileReferenceKey, return E_POINTER; } - *fontFileStream = - new gfxDWriteFontFileStream( - static_cast(fontFileReferenceKey)->mArray); - - if (!*fontFileStream) { - return E_OUTOFMEMORY; + uint64_t fontFileKey = *static_cast(fontFileReferenceKey); + auto found = sFontFileStreams.find(fontFileKey); + if (found == sFontFileStreams.end()) { + *fontFileStream = nullptr; + return E_FAIL; } - (*fontFileStream)->AddRef(); + + found->second->AddRef(); + *fontFileStream = found->second; return S_OK; } -gfxDWriteFontFileStream::gfxDWriteFontFileStream(FallibleTArray *aData) +/* static */ +HRESULT +gfxDWriteFontFileLoader::CreateCustomFontFile(FallibleTArray& aFontData, + IDWriteFontFile** aFontFile, + IDWriteFontFileStream** aFontFileStream) { - mData.SwapElements(*aData); -} + MOZ_ASSERT(aFontFile); + MOZ_ASSERT(aFontFileStream); -gfxDWriteFontFileStream::~gfxDWriteFontFileStream() -{ -} + IDWriteFactory *factory = gfxWindowsPlatform::GetPlatform()->GetDWriteFactory(); -HRESULT STDMETHODCALLTYPE -gfxDWriteFontFileStream::GetFileSize(UINT64 *fileSize) -{ - *fileSize = mData.Length(); - return S_OK; -} + uint64_t fontFileKey = sNextFontFileKey++; + RefPtr ffsRef = new gfxDWriteFontFileStream(&aFontData, fontFileKey); + sFontFileStreams[fontFileKey] = ffsRef; -HRESULT STDMETHODCALLTYPE -gfxDWriteFontFileStream::GetLastWriteTime(UINT64 *lastWriteTime) -{ - return E_NOTIMPL; -} + RefPtr fontFile; + HRESULT hr = factory->CreateCustomFontFileReference(&fontFileKey, sizeof(fontFileKey), Instance(), getter_AddRefs(fontFile)); + if (FAILED(hr)) { + NS_WARNING("Failed to load font file from data!"); + return hr; + } -HRESULT STDMETHODCALLTYPE -gfxDWriteFontFileStream::ReadFileFragment(const void **fragmentStart, - UINT64 fileOffset, - UINT64 fragmentSize, - void **fragmentContext) -{ - // We are required to do bounds checking. - if (fileOffset + fragmentSize > (UINT64)mData.Length()) { - return E_FAIL; - } - // We should be alive for the duration of this. - *fragmentStart = &mData[fileOffset]; - *fragmentContext = nullptr; - return S_OK; -} + fontFile.forget(aFontFile); + ffsRef.forget(aFontFileStream); -void STDMETHODCALLTYPE -gfxDWriteFontFileStream::ReleaseFileFragment(void *fragmentContext) -{ + return S_OK; } diff --git a/gfx/thebes/gfxDWriteCommon.h b/gfx/thebes/gfxDWriteCommon.h index 1e563282b9..fd46ed555b 100644 --- a/gfx/thebes/gfxDWriteCommon.h +++ b/gfx/thebes/gfxDWriteCommon.h @@ -113,8 +113,7 @@ public: // IDWriteFontFileLoader methods /** - * Important! Note the key here -has- to be a pointer to an - * FallibleTArray. + * Important! Note the key here -has- to be a pointer to a uint64_t. */ virtual HRESULT STDMETHODCALLTYPE CreateStreamFromKey(void const* fontFileReferenceKey, @@ -123,8 +122,7 @@ public: /** * Gets the singleton loader instance. Note that when using this font - * loader, the key must be a pointer to an FallibleTArray. This - * array will be empty when the function returns. + * loader, the key must be a pointer to a unint64_t. */ static IDWriteFontFileLoader* Instance() { @@ -136,71 +134,21 @@ public: return mInstance; } + /** + * Creates a IDWriteFontFile and IDWriteFontFileStream from aFontData. + * aFontData will be empty on return as it swaps out the data. + * + * @param aFontData the font data for the custom font file + * @param aFontFile out param for the created font file + * @param aFontFileStream out param for the corresponding stream + * @return HRESULT of internal calls + */ + static HRESULT CreateCustomFontFile(FallibleTArray& aFontData, + IDWriteFontFile** aFontFile, + IDWriteFontFileStream** aFontFileStream); + private: static IDWriteFontFileLoader* mInstance; }; -class gfxDWriteFontFileStream final : public IDWriteFontFileStream -{ -public: - /** - * Used by the FontFileLoader to create a new font stream, - * this font stream is created from data in memory. The memory - * passed may be released after object creation, it will be - * copied internally. - * - * @param aData Font data - */ - gfxDWriteFontFileStream(FallibleTArray *aData); - ~gfxDWriteFontFileStream(); - - // IUnknown interface - IFACEMETHOD(QueryInterface)(IID const& iid, OUT void** ppObject) - { - if (iid == __uuidof(IDWriteFontFileStream)) { - *ppObject = static_cast(this); - return S_OK; - } else if (iid == __uuidof(IUnknown)) { - *ppObject = static_cast(this); - return S_OK; - } else { - return E_NOINTERFACE; - } - } - - IFACEMETHOD_(ULONG, AddRef)() - { - NS_PRECONDITION(int32_t(mRefCnt) >= 0, "illegal refcnt"); - ++mRefCnt; - return mRefCnt; - } - - IFACEMETHOD_(ULONG, Release)() - { - NS_PRECONDITION(0 != mRefCnt, "dup release"); - --mRefCnt; - if (mRefCnt == 0) { - delete this; - return 0; - } - return mRefCnt; - } - - // IDWriteFontFileStream methods - virtual HRESULT STDMETHODCALLTYPE ReadFileFragment(void const** fragmentStart, - UINT64 fileOffset, - UINT64 fragmentSize, - OUT void** fragmentContext); - - virtual void STDMETHODCALLTYPE ReleaseFileFragment(void* fragmentContext); - - virtual HRESULT STDMETHODCALLTYPE GetFileSize(OUT UINT64* fileSize); - - virtual HRESULT STDMETHODCALLTYPE GetLastWriteTime(OUT UINT64* lastWriteTime); - -private: - FallibleTArray mData; - nsAutoRefCnt mRefCnt; -}; - #endif /* GFX_DWRITECOMMON_H */ diff --git a/gfx/thebes/gfxDWriteFontList.cpp b/gfx/thebes/gfxDWriteFontList.cpp index 7bebc6c873..4f5a5a015f 100644 --- a/gfx/thebes/gfxDWriteFontList.cpp +++ b/gfx/thebes/gfxDWriteFontList.cpp @@ -342,6 +342,24 @@ gfxDWriteFontFamily::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf, AddSizeOfExcludingThis(aMallocSizeOf, aSizes); } +already_AddRefed +gfxDWriteFontFamily::GetDefaultFont() +{ + RefPtr font; + for (UINT32 i = 0; i < mDWFamily->GetFontCount(); i++) { + HRESULT hr = mDWFamily->GetFont(i, getter_AddRefs(font)); + if (FAILED(hr)) { + NS_WARNING("Failed to get default font from existing family"); + continue; + } + + return font.forget(); + } + + NS_WARNING("No available DWrite fonts. Returning null"); + return nullptr; +} + //////////////////////////////////////////////////////////////////////////////// // gfxDWriteFontEntry @@ -792,35 +810,12 @@ gfxDWriteFontList::MakePlatformFont(const nsAString& aFontName, return nullptr; } + RefPtr fontFileStream; RefPtr fontFile; - HRESULT hr; - - /** - * We pass in a pointer to a structure containing a pointer to the array - * containing the font data and a unique identifier. DWrite will - * internally copy what is at that pointer, and pass that to - * CreateStreamFromKey. The array will be empty when the function - * succesfully returns since it swaps out the data. - */ - ffReferenceKey key; - key.mArray = &newFontData; - nsCOMPtr uuidgen = - do_GetService("@mozilla.org/uuid-generator;1"); - if (!uuidgen) { - return nullptr; - } - - rv = uuidgen->GenerateUUIDInPlace(&key.mGUID); - - if (NS_FAILED(rv)) { - return nullptr; - } - - hr = gfxWindowsPlatform::GetPlatform()->GetDWriteFactory()-> - CreateCustomFontFileReference(&key, - sizeof(key), - gfxDWriteFontFileLoader::Instance(), - getter_AddRefs(fontFile)); + HRESULT hr = + gfxDWriteFontFileLoader::CreateCustomFontFile(newFontData, + getter_AddRefs(fontFile), + getter_AddRefs(fontFileStream)); if (FAILED(hr)) { NS_WARNING("Failed to create custom font file reference."); @@ -834,6 +829,7 @@ gfxDWriteFontList::MakePlatformFont(const nsAString& aFontName, gfxDWriteFontEntry *entry = new gfxDWriteFontEntry(uniqueName, fontFile, + fontFileStream, aWeight, aStretch, aStyle); @@ -863,9 +859,9 @@ gfxDWriteFontList::InitFontList() char nowTime[256], nowDate[256]; if (LOG_FONTINIT_ENABLED()) { - GetTimeFormat(LOCALE_INVARIANT, TIME_FORCE24HOURFORMAT, + GetTimeFormatA(LOCALE_INVARIANT, TIME_FORCE24HOURFORMAT, nullptr, nullptr, nowTime, 256); - GetDateFormat(LOCALE_INVARIANT, 0, nullptr, nullptr, nowDate, 256); + GetDateFormatA(LOCALE_INVARIANT, 0, nullptr, nullptr, nowDate, 256); upTime = (double) GetTickCount(); } QueryPerformanceFrequency(&frequency); diff --git a/gfx/thebes/gfxDWriteFontList.h b/gfx/thebes/gfxDWriteFontList.h index 08c8004ebc..99e1df3051 100644 --- a/gfx/thebes/gfxDWriteFontList.h +++ b/gfx/thebes/gfxDWriteFontList.h @@ -57,6 +57,7 @@ public: virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf, FontListSizes* aSizes) const; + already_AddRefed GetDefaultFont(); protected: /** This font family's directwrite fontfamily object */ RefPtr mDWFamily; @@ -126,17 +127,19 @@ public: * * \param aFaceName The name of the corresponding font face. * \param aFontFile DirectWrite fontfile object + * \param aFontFileStream DirectWrite fontfile stream object * \param aWeight Weight of the font * \param aStretch Stretch of the font * \param aStyle italic or oblique of font */ gfxDWriteFontEntry(const nsAString& aFaceName, IDWriteFontFile *aFontFile, + IDWriteFontFileStream *aFontFileStream, uint16_t aWeight, int16_t aStretch, uint8_t aStyle) : gfxFontEntry(aFaceName), mFont(nullptr), mFontFile(aFontFile), - mForceGDIClassic(false) + mFontFileStream(aFontFileStream), mForceGDIClassic(false) { mWeight = aWeight; mStretch = aStretch; @@ -163,6 +166,10 @@ public: virtual void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf, FontListSizes* aSizes) const; + IDWriteFont* GetFont() { + return mFont; + } + protected: friend class gfxDWriteFont; friend class gfxDWriteFontList; @@ -186,6 +193,10 @@ protected: RefPtr mFont; RefPtr mFontFile; + // For custom fonts, we hold a reference to the IDWriteFontFileStream for + // for the IDWriteFontFile, so that the data is available. + RefPtr mFontFileStream; + // font face corresponding to the mFont/mFontFile *without* any DWrite // style simulations applied RefPtr mFontFace; diff --git a/gfx/thebes/gfxDWriteFonts.cpp b/gfx/thebes/gfxDWriteFonts.cpp index 72a5c1f45b..75d7b8d05c 100644 --- a/gfx/thebes/gfxDWriteFonts.cpp +++ b/gfx/thebes/gfxDWriteFonts.cpp @@ -82,7 +82,7 @@ gfxDWriteFont::gfxDWriteFont(gfxFontEntry *aFontEntry, , mAllowManualShowGlyphs(true) { gfxDWriteFontEntry *fe = - static_cast(aFontEntry); + static_cast(aFontEntry); nsresult rv; DWRITE_FONT_SIMULATIONS sims = DWRITE_FONT_SIMULATIONS_NONE; if ((GetStyle()->style != NS_FONT_STYLE_NORMAL) && @@ -103,6 +103,21 @@ gfxDWriteFont::gfxDWriteFont(gfxFontEntry *aFontEntry, return; } + mFont = fe->GetFont(); + if (!mFont) { + gfxPlatformFontList* fontList = gfxPlatformFontList::PlatformFontList(); + gfxDWriteFontFamily* defaultFontFamily = + static_cast(fontList->GetDefaultFont(aFontStyle)); + + mFont = defaultFontFamily->GetDefaultFont(); + NS_WARNING("Using default font"); + } + + HRESULT hr = mFont->GetFontFamily(getter_AddRefs(mFontFamily)); + if (FAILED(hr)) { + MOZ_ASSERT(false); + } + ComputeMetrics(anAAOption); } @@ -232,7 +247,7 @@ gfxDWriteFont::ComputeMetrics(AntialiasOption anAAOption) UINT32 ucs = L' '; UINT16 glyph; - HRESULT hr = mFontFace->GetGlyphIndicesA(&ucs, 1, &glyph); + HRESULT hr = mFontFace->GetGlyphIndices(&ucs, 1, &glyph); if (FAILED(hr)) { mMetrics->spaceWidth = 0; } else { @@ -262,7 +277,7 @@ gfxDWriteFont::ComputeMetrics(AntialiasOption anAAOption) if (mMetrics->aveCharWidth < 1) { ucs = L'x'; - if (SUCCEEDED(mFontFace->GetGlyphIndicesA(&ucs, 1, &glyph))) { + if (SUCCEEDED(mFontFace->GetGlyphIndices(&ucs, 1, &glyph))) { mMetrics->aveCharWidth = MeasureGlyphWidth(glyph); } if (mMetrics->aveCharWidth < 1) { @@ -272,7 +287,7 @@ gfxDWriteFont::ComputeMetrics(AntialiasOption anAAOption) } ucs = L'0'; - if (SUCCEEDED(mFontFace->GetGlyphIndicesA(&ucs, 1, &glyph))) { + if (SUCCEEDED(mFontFace->GetGlyphIndices(&ucs, 1, &glyph))) { mMetrics->zeroOrAveCharWidth = MeasureGlyphWidth(glyph); } if (mMetrics->zeroOrAveCharWidth < 1) { @@ -462,7 +477,8 @@ gfxDWriteFont::SetupCairoFont(gfxContext *aContext) // the cairo_t, precluding any further drawing. return false; } - cairo_set_scaled_font(aContext->GetCairo(), scaledFont); + cairo_set_scaled_font(gfxContext::RefCairo(aContext->GetDrawTarget()), + scaledFont); return true; } @@ -687,6 +703,10 @@ gfxDWriteFont::GetScaledFont(mozilla::gfx::DrawTarget *aTarget) mAzureScaledFont = Factory::CreateScaledFontWithCairo(nativeFont, GetAdjustedSize(), GetCairoScaledFont()); + } else if (aTarget->GetBackendType() == BackendType::SKIA) { + mAzureScaledFont = + Factory::CreateScaledFontForDWriteFont(mFont, mFontFamily, + mFontFace, GetAdjustedSize()); } else { mAzureScaledFont = Factory::CreateScaledFontForNativeFont(nativeFont, GetAdjustedSize()); diff --git a/gfx/thebes/gfxDWriteFonts.h b/gfx/thebes/gfxDWriteFonts.h index 58de169df3..a8869a2898 100644 --- a/gfx/thebes/gfxDWriteFonts.h +++ b/gfx/thebes/gfxDWriteFonts.h @@ -91,6 +91,8 @@ protected: bool GetForceGDIClassic(); RefPtr mFontFace; + RefPtr mFont; + RefPtr mFontFamily; cairo_font_face_t *mCairoFontFace; Metrics *mMetrics; diff --git a/gfx/thebes/gfxFT2FontBase.cpp b/gfx/thebes/gfxFT2FontBase.cpp index 0d8055d010..c5a1a85b85 100644 --- a/gfx/thebes/gfxFT2FontBase.cpp +++ b/gfx/thebes/gfxFT2FontBase.cpp @@ -178,8 +178,6 @@ gfxFT2FontBase::GetGlyphWidth(DrawTarget& aDrawTarget, uint16_t aGID) bool gfxFT2FontBase::SetupCairoFont(gfxContext *aContext) { - cairo_t *cr = aContext->GetCairo(); - // The scaled font ctm is not relevant right here because // cairo_set_scaled_font does not record the scaled font itself, but // merely the font_face, font_matrix, font_options. The scaled_font used @@ -212,6 +210,7 @@ gfxFT2FontBase::SetupCairoFont(gfxContext *aContext) // what is set here. It's too late to change things here as measuring has // already taken place. We should really be measuring with a different // font for pdf and ps surfaces (bug 403513). - cairo_set_scaled_font(cr, cairoFont); + cairo_set_scaled_font(gfxContext::RefCairo(aContext->GetDrawTarget()), + cairoFont); return true; } diff --git a/gfx/thebes/gfxFont.cpp b/gfx/thebes/gfxFont.cpp index 4bb2784e5b..048b5193f2 100644 --- a/gfx/thebes/gfxFont.cpp +++ b/gfx/thebes/gfxFont.cpp @@ -549,9 +549,9 @@ gfxFontShaper::MergeFontFeatures( } void -gfxShapedText::SetupClusterBoundaries(uint32_t aOffset, +gfxShapedText::SetupClusterBoundaries(uint32_t aOffset, const char16_t *aString, - uint32_t aLength) + uint32_t aLength) { CompressedGlyph *glyphs = GetCharacterGlyphs() + aOffset; @@ -562,8 +562,15 @@ gfxShapedText::SetupClusterBoundaries(uint32_t aOffset, // the ClusterIterator won't be able to tell us if the string // _begins_ with a cluster-extender, so we handle that here - if (aLength && IsClusterExtender(*aString)) { - *glyphs = extendCluster; + if (aLength) { + uint32_t ch = *aString; + if (aLength > 1 && NS_IS_HIGH_SURROGATE(ch) && + NS_IS_LOW_SURROGATE(aString[1])) { + ch = SURROGATE_TO_UCS4(ch, aString[1]); + } + if (IsClusterExtender(ch)) { + *glyphs = extendCluster; + } } while (!iter.AtEnd()) { @@ -3217,7 +3224,8 @@ gfxFont::SetupGlyphExtents(gfxContext *aContext, glyph.x = 0; glyph.y = 0; cairo_text_extents_t extents; - cairo_glyph_extents(aContext->GetCairo(), &glyph, 1, &extents); + cairo_glyph_extents(gfxContext::RefCairo(aContext->GetDrawTarget()), + &glyph, 1, &extents); const Metrics& fontMetrics = GetMetrics(eHorizontal); int32_t appUnitsPerDevUnit = aExtents->GetAppUnitsPerDevUnit(); diff --git a/gfx/thebes/gfxFont.h b/gfx/thebes/gfxFont.h index 82b991d822..618569bf10 100644 --- a/gfx/thebes/gfxFont.h +++ b/gfx/thebes/gfxFont.h @@ -645,8 +645,10 @@ public: void* aHandleFeatureData); protected: - // the font this shaper is working with - gfxFont * mFont; + // the font this shaper is working with. The font owns a nsAutoPtr reference + // to this object, and will destroy it before it dies. Thus, mFont will always + // be valid. + gfxFont* MOZ_NON_OWNING_REF mFont; }; @@ -1802,7 +1804,9 @@ public: { mFont->AddGlyphChangeObserver(this); } - gfxFont* mFont; + // This pointer is nulled by ForgetFont in the gfxFont's + // destructor. Before the gfxFont dies. + gfxFont* MOZ_NON_OWNING_REF mFont; }; friend class GlyphChangeObserver; diff --git a/gfx/thebes/gfxFontEntry.cpp b/gfx/thebes/gfxFontEntry.cpp index 35f5e43000..df0614ff4b 100644 --- a/gfx/thebes/gfxFontEntry.cpp +++ b/gfx/thebes/gfxFontEntry.cpp @@ -342,7 +342,8 @@ gfxFontEntry::GetSVGGlyphExtents(gfxContext *aContext, uint32_t aGlyphId, "font has invalid unitsPerEm"); cairo_matrix_t fontMatrix; - cairo_get_font_matrix(aContext->GetCairo(), &fontMatrix); + cairo_get_font_matrix(gfxContext::RefCairo(aContext->GetDrawTarget()), + &fontMatrix); gfxMatrix svgToAppSpace(fontMatrix.xx, fontMatrix.yx, fontMatrix.xy, fontMatrix.yy, diff --git a/gfx/thebes/gfxGDIFont.cpp b/gfx/thebes/gfxGDIFont.cpp index 112e7af96c..230f4e42b4 100644 --- a/gfx/thebes/gfxGDIFont.cpp +++ b/gfx/thebes/gfxGDIFont.cpp @@ -136,7 +136,7 @@ gfxGDIFont::SetupCairoFont(gfxContext *aContext) // the cairo_t, precluding any further drawing. return false; } - cairo_set_scaled_font(aContext->GetCairo(), mScaledFont); + cairo_set_scaled_font(gfxContext::RefCairo(aContext->GetDrawTarget()), mScaledFont); return true; } diff --git a/gfx/thebes/gfxGDIFontList.cpp b/gfx/thebes/gfxGDIFontList.cpp index 022f26da70..be388f4c03 100644 --- a/gfx/thebes/gfxGDIFontList.cpp +++ b/gfx/thebes/gfxGDIFontList.cpp @@ -1180,11 +1180,11 @@ gfxGDIFontList::ActivateBundledFonts() if (!file) { continue; } - nsCString path; - if (NS_FAILED(file->GetNativePath(path))) { + nsAutoString path; + if (NS_FAILED(file->GetPath(path))) { continue; } - AddFontResourceEx(path.get(), FR_PRIVATE, nullptr); + AddFontResourceExW(path.get(), FR_PRIVATE, nullptr); } } diff --git a/gfx/thebes/gfxGradientCache.cpp b/gfx/thebes/gfxGradientCache.cpp index 6fdb972bce..fa25bd78c8 100644 --- a/gfx/thebes/gfxGradientCache.cpp +++ b/gfx/thebes/gfxGradientCache.cpp @@ -197,9 +197,13 @@ gfxGradientCache::GetGradientStops(const DrawTarget *aDT, nsTArray return nullptr; } -GradientStops * +already_AddRefed gfxGradientCache::GetOrCreateGradientStops(const DrawTarget *aDT, nsTArray& aStops, ExtendMode aExtend) { + if (aDT->IsRecording()) { + return aDT->CreateGradientStops(aStops.Elements(), aStops.Length(), aExtend); + } + RefPtr gs = GetGradientStops(aDT, aStops, aExtend); if (!gs) { gs = aDT->CreateGradientStops(aStops.Elements(), aStops.Length(), aExtend); @@ -213,7 +217,7 @@ gfxGradientCache::GetOrCreateGradientStops(const DrawTarget *aDT, nsTArray& aStops, gfx::ExtendMode aExtend); - static gfx::GradientStops* + static already_AddRefed GetOrCreateGradientStops(const gfx::DrawTarget *aDT, nsTArray& aStops, gfx::ExtendMode aExtend); diff --git a/gfx/thebes/gfxMacFont.cpp b/gfx/thebes/gfxMacFont.cpp index 239899b010..6be3a90ac2 100644 --- a/gfx/thebes/gfxMacFont.cpp +++ b/gfx/thebes/gfxMacFont.cpp @@ -160,7 +160,8 @@ gfxMacFont::SetupCairoFont(gfxContext *aContext) // the cairo_t, precluding any further drawing. return false; } - cairo_set_scaled_font(aContext->GetCairo(), mScaledFont); + cairo_set_scaled_font(gfxContext::RefCairo(aContext->GetDrawTarget()), + mScaledFont); return true; } diff --git a/gfx/thebes/gfxPlatform.cpp b/gfx/thebes/gfxPlatform.cpp index 80b9c68074..d1fcf7a5b9 100644 --- a/gfx/thebes/gfxPlatform.cpp +++ b/gfx/thebes/gfxPlatform.cpp @@ -545,6 +545,10 @@ gfxPlatform::Init() #error "No gfxPlatform implementation available" #endif +#ifdef USE_SKIA + SkGraphics::Init(); +#endif + #ifdef MOZ_GL_DEBUG GLContext::StaticInit(); #endif diff --git a/gfx/thebes/gfxPlatformFontList.cpp b/gfx/thebes/gfxPlatformFontList.cpp index f7ba6278b4..a949dc0ceb 100644 --- a/gfx/thebes/gfxPlatformFontList.cpp +++ b/gfx/thebes/gfxPlatformFontList.cpp @@ -619,24 +619,6 @@ gfxPlatformFontList::GlobalFontFallback(const uint32_t aCh, return data.mBestMatch; } -#ifdef XP_WIN -#include - -// crude hack for using when monitoring process -static void LogRegistryEvent(const wchar_t *msg) -{ - HKEY dummyKey; - HRESULT hr; - wchar_t buf[512]; - - wsprintfW(buf, L" log %s", msg); - hr = RegOpenKeyExW(HKEY_LOCAL_MACHINE, buf, 0, KEY_READ, &dummyKey); - if (SUCCEEDED(hr)) { - RegCloseKey(dummyKey); - } -} -#endif - gfxFontFamily* gfxPlatformFontList::CheckFamily(gfxFontFamily *aFamily) { diff --git a/gfx/thebes/gfxPrefs.cpp b/gfx/thebes/gfxPrefs.cpp index a36e4d1d43..80b6f476e0 100644 --- a/gfx/thebes/gfxPrefs.cpp +++ b/gfx/thebes/gfxPrefs.cpp @@ -7,7 +7,7 @@ #include "mozilla/Preferences.h" #include "MainThreadUtils.h" -#include "mozilla/gfx/Logging.h" +#include "mozilla/gfx/Preferences.h" using namespace mozilla; diff --git a/gfx/thebes/gfxPrefs.h b/gfx/thebes/gfxPrefs.h index f73bb05648..7afe129fe2 100644 --- a/gfx/thebes/gfxPrefs.h +++ b/gfx/thebes/gfxPrefs.h @@ -201,6 +201,7 @@ private: DECL_GFX_PREF(Once, "dom.vr.cardboard.enabled", VRCardboardEnabled, bool, false); DECL_GFX_PREF(Once, "dom.vr.add-test-devices", VRAddTestDevices, int32_t, 1); DECL_GFX_PREF(Live, "dom.w3c_pointer_events.enabled", PointerEventsEnabled, bool, false); + DECL_GFX_PREF(Live, "dom.w3c_touch_events.enabled", TouchEventsEnabled, int32_t, 0); DECL_GFX_PREF(Live, "general.smoothScroll", SmoothScrollEnabled, bool, true); DECL_GFX_PREF(Live, "general.smoothScroll.durationToIntervalRatio", @@ -255,11 +256,11 @@ private: DECL_GFX_PREF(Live, "gfx.SurfaceTexture.detach.enabled", SurfaceTextureDetachEnabled, bool, true); DECL_GFX_PREF(Live, "gfx.testing.device-reset", DeviceResetForTesting, int32_t, 0); DECL_GFX_PREF(Live, "gfx.testing.device-fail", DeviceFailForTesting, bool, false); - DECL_GFX_PREF(Once, "gfx.touch.resample", TouchResampling, bool, false); // These times should be in milliseconds DECL_GFX_PREF(Once, "gfx.touch.resample.delay-threshold", TouchResampleVsyncDelayThreshold, int32_t, 20); DECL_GFX_PREF(Once, "gfx.touch.resample.max-predict", TouchResampleMaxPredict, int32_t, 8); + DECL_GFX_PREF(Once, "gfx.touch.resample.min-delta", TouchResampleMinDelta, int32_t, 2); DECL_GFX_PREF(Once, "gfx.touch.resample.old-touch-threshold",TouchResampleOldTouchThreshold, int32_t, 17); DECL_GFX_PREF(Once, "gfx.touch.resample.vsync-adjust", TouchVsyncSampleAdjust, int32_t, 5); @@ -439,6 +440,7 @@ private: DECL_GFX_PREF(Live, "webgl.msaa-force", WebGLForceMSAA, bool, false); DECL_GFX_PREF(Live, "webgl.prefer-16bpp", WebGLPrefer16bpp, bool, false); DECL_GFX_PREF(Live, "webgl.restore-context-when-visible", WebGLRestoreWhenVisible, bool, true); + DECL_GFX_PREF(Live, "webgl.allow-immediate-queries", WebGLImmediateQueries, bool, false); DECL_GFX_PREF(Live, "webgl.webgl2-compat-mode", WebGL2CompatMode, bool, false); diff --git a/gfx/thebes/gfxSVGGlyphs.h b/gfx/thebes/gfxSVGGlyphs.h index 130ac86b47..d07649ad7f 100644 --- a/gfx/thebes/gfxSVGGlyphs.h +++ b/gfx/thebes/gfxSVGGlyphs.h @@ -68,7 +68,7 @@ private: nsBaseHashtable mGlyphIdMap; - nsAutoCString mSVGGlyphsDocumentURI; + nsCString mSVGGlyphsDocumentURI; }; /** diff --git a/gfx/thebes/gfxWindowsNativeDrawing.cpp b/gfx/thebes/gfxWindowsNativeDrawing.cpp index 88f00bd766..fc0404381a 100644 --- a/gfx/thebes/gfxWindowsNativeDrawing.cpp +++ b/gfx/thebes/gfxWindowsNativeDrawing.cpp @@ -12,8 +12,12 @@ #include "gfxAlphaRecovery.h" #include "gfxPattern.h" #include "mozilla/gfx/2D.h" +#include "mozilla/gfx/Helpers.h" #include "gfx2DGlue.h" +#include "cairo.h" +#include "cairo-win32.h" + using namespace mozilla; using namespace mozilla::gfx; @@ -43,12 +47,21 @@ gfxWindowsNativeDrawing::BeginNativeDrawing() { if (mRenderState == RENDER_STATE_INIT) { RefPtr surf; - - if (mContext->GetCairo()) { - surf = mContext->CurrentSurface(&mDeviceOffset.x, &mDeviceOffset.y); + DrawTarget* drawTarget = mContext->GetDrawTarget(); + cairo_t* cairo = nullptr; + if (drawTarget->GetBackendType() == BackendType::CAIRO) { + cairo = static_cast + (drawTarget->GetNativeSurface(NativeSurfaceType::CAIRO_CONTEXT)); + if (cairo) { + cairo_surface_t* s = cairo_get_target(cairo); + if (s) { + mDeviceOffset = mContext->GetDeviceOffset(); + surf = gfxASurface::Wrap(s); + } + } } - if (surf && surf->CairoStatus()) + if (surf && surf->CairoStatus() != 0) return nullptr; gfxMatrix m = mContext->CurrentMatrix(); @@ -72,7 +85,7 @@ gfxWindowsNativeDrawing::BeginNativeDrawing() // grab the DC. This can fail if there is a complex clipping path, // in which case we'll have to fall back. mWinSurface = static_cast(static_cast(surf.get())); - mDC = mWinSurface->GetDCWithClip(mContext); + mDC = cairo_win32_get_dc_with_clip(cairo); if (mDC) { if (mTransformType == TRANSLATION_ONLY) { @@ -149,8 +162,8 @@ gfxWindowsNativeDrawing::BeginNativeDrawing() } GetViewportOrgEx(mDC, &mOrigViewportOrigin); SetViewportOrgEx(mDC, - mOrigViewportOrigin.x + (int)mDeviceOffset.x, - mOrigViewportOrigin.y + (int)mDeviceOffset.y, + mOrigViewportOrigin.x - (int)mDeviceOffset.x, + mOrigViewportOrigin.y - (int)mDeviceOffset.y, nullptr); return mDC; @@ -252,26 +265,22 @@ gfxWindowsNativeDrawing::PaintToContext() black->Stride(), black->GetSize(), SurfaceFormat::B8G8R8A8); + { + DrawTarget* dt = mContext->GetDrawTarget(); + AutoRestoreTransform autoRestoreTransform(dt); - mContext->Save(); - mContext->SetMatrix( - mContext->CurrentMatrix().Translate(mNativeRect.TopLeft())); - mContext->NewPath(); - mContext->Rectangle(gfxRect(gfxPoint(0.0, 0.0), mNativeRect.Size())); + Matrix newTransform = dt->GetTransform(); + newTransform.PreTranslate(ToPoint(mNativeRect.TopLeft())); + dt->SetTransform(newTransform); - RefPtr pat = new gfxPattern(source, Matrix()); - - gfxMatrix m; - m.Scale(mScale.width, mScale.height); - pat->SetMatrix(m); - - if (mNativeDrawFlags & DO_NEAREST_NEIGHBOR_FILTERING) - pat->SetFilter(Filter::LINEAR); - - pat->SetExtend(ExtendMode::CLAMP); - mContext->SetPattern(pat); - mContext->Fill(); - mContext->Restore(); + Rect rect(Point(0.0, 0.0), ToSize(mNativeRect.Size())); + Matrix m = Matrix::Scaling(1.0 / mScale.width, 1.0 / mScale.height); + Filter filter = (mNativeDrawFlags & DO_NEAREST_NEIGHBOR_FILTERING) + ? Filter::LINEAR + : Filter::GOOD; + SurfacePattern pat(source, ExtendMode::CLAMP, m, filter); + dt->FillRect(rect, pat); + } mRenderState = RENDER_STATE_DONE; } else { diff --git a/gfx/thebes/gfxWindowsNativeDrawing.h b/gfx/thebes/gfxWindowsNativeDrawing.h index 3490326c29..25589fc5b7 100644 --- a/gfx/thebes/gfxWindowsNativeDrawing.h +++ b/gfx/thebes/gfxWindowsNativeDrawing.h @@ -91,7 +91,7 @@ private: // what state the rendering is in uint8_t mRenderState; - gfxPoint mDeviceOffset; + mozilla::gfx::Point mDeviceOffset; RefPtr mBlackPattern, mWhitePattern; enum TransformType { diff --git a/gfx/thebes/gfxWindowsPlatform.cpp b/gfx/thebes/gfxWindowsPlatform.cpp index ac122cd866..5d7d0d3c43 100644 --- a/gfx/thebes/gfxWindowsPlatform.cpp +++ b/gfx/thebes/gfxWindowsPlatform.cpp @@ -690,9 +690,7 @@ gfxWindowsPlatform::CreatePlatformFontList() #ifdef CAIRO_HAS_DWRITE_FONT // bug 630201 - older pre-RTM versions of Direct2D/DirectWrite cause odd // crashers so blacklist them altogether - if (IsNotWin7PreRTM() && GetDWriteFactory() && - // Skia doesn't support DirectWrite fonts yet. - (gfxPlatform::GetDefaultContentBackend() != BackendType::SKIA)) { + if (IsNotWin7PreRTM() && GetDWriteFactory()) { pfl = new gfxDWriteFontList(); if (NS_SUCCEEDED(pfl->InitFontList())) { return pfl; @@ -2996,7 +2994,7 @@ gfxWindowsPlatform::CreateHardwareVsyncSource() bool gfxWindowsPlatform::SupportsApzTouchInput() const { - int value = Preferences::GetInt("dom.w3c_touch_events.enabled", 0); + int value = gfxPrefs::TouchEventsEnabled(); return value == 1 || value == 2; } diff --git a/gfx/thebes/gfxWindowsSurface.cpp b/gfx/thebes/gfxWindowsSurface.cpp index d219a454d5..27b165da2a 100644 --- a/gfx/thebes/gfxWindowsSurface.cpp +++ b/gfx/thebes/gfxWindowsSurface.cpp @@ -172,12 +172,6 @@ gfxWindowsSurface::~gfxWindowsSurface() } } -HDC -gfxWindowsSurface::GetDCWithClip(gfxContext *ctx) -{ - return cairo_win32_get_dc_with_clip (ctx->GetCairo()); -} - HDC gfxWindowsSurface::GetDC() { @@ -214,6 +208,10 @@ gfxWindowsSurface::BeginPrinting(const nsAString& aTitle, { #ifdef NS_PRINTING #define DOC_TITLE_LENGTH (MAX_PATH-1) + if (!mForPrinting) { + return NS_OK; + } + DOCINFOW docinfo; nsString titleStr(aTitle); @@ -241,6 +239,10 @@ nsresult gfxWindowsSurface::EndPrinting() { #ifdef NS_PRINTING + if (!mForPrinting) { + return NS_OK; + } + int result = ::EndDoc(mDC); if (result <= 0) return NS_ERROR_FAILURE; @@ -255,6 +257,10 @@ nsresult gfxWindowsSurface::AbortPrinting() { #ifdef NS_PRINTING + if (!mForPrinting) { + return NS_OK; + } + int result = ::AbortDoc(mDC); if (result <= 0) return NS_ERROR_FAILURE; @@ -268,6 +274,10 @@ nsresult gfxWindowsSurface::BeginPage() { #ifdef NS_PRINTING + if (!mForPrinting) { + return NS_OK; + } + int result = ::StartPage(mDC); if (result <= 0) return NS_ERROR_FAILURE; @@ -281,8 +291,11 @@ nsresult gfxWindowsSurface::EndPage() { #ifdef NS_PRINTING - if (mForPrinting) - cairo_surface_show_page(CairoSurface()); + if (!mForPrinting) { + return NS_OK; + } + + cairo_surface_show_page(CairoSurface()); int result = ::EndPage(mDC); if (result <= 0) return NS_ERROR_FAILURE; diff --git a/gfx/thebes/gfxWindowsSurface.h b/gfx/thebes/gfxWindowsSurface.h index 7e8b51746d..0f5e2f58b9 100644 --- a/gfx/thebes/gfxWindowsSurface.h +++ b/gfx/thebes/gfxWindowsSurface.h @@ -53,8 +53,6 @@ public: HDC GetDC(); - HDC GetDCWithClip(gfxContext *); - already_AddRefed GetAsImageSurface(); nsresult BeginPrinting(const nsAString& aTitle, const nsAString& aPrintToFileName); diff --git a/gfx/thebes/moz.build b/gfx/thebes/moz.build index d902477a5b..c2831a361f 100644 --- a/gfx/thebes/moz.build +++ b/gfx/thebes/moz.build @@ -310,6 +310,3 @@ DEFINES['GRAPHITE2_STATIC'] = True if CONFIG['GKMEDIAS_SHARED_LIBRARY']: DEFINES['OTS_DLL'] = True - -if CONFIG['OS_ARCH'] == 'WINNT': - del DEFINES['UNICODE'] diff --git a/ipc/chromium/src/base/hash_tables.h b/ipc/chromium/src/base/hash_tables.h index 3f4440dc3d..26abc5b60e 100644 --- a/ipc/chromium/src/base/hash_tables.h +++ b/ipc/chromium/src/base/hash_tables.h @@ -24,8 +24,26 @@ #pragma push_macro("_SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS") #define _SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS #endif + +// Suppress -Wshadow warnings from stlport headers. +#ifdef __GNUC__ +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wshadow" +# if MOZ_GCC_VERSION_AT_LEAST(4, 9, 0) +# pragma GCC diagnostic ignored "-Wshadow-local" +# endif +#endif + #include #include + +#ifdef __GNUC__ +# if MOZ_GCC_VERSION_AT_LEAST(4, 9, 0) +# pragma GCC diagnostic pop // -Wshadow-local +# endif +# pragma GCC diagnostic pop // -Wshadow +#endif + #ifdef COMPILER_MSVC #pragma pop_macro("_SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS") #endif diff --git a/ipc/chromium/src/base/histogram.cc b/ipc/chromium/src/base/histogram.cc index 97b10e25e6..918afba916 100644 --- a/ipc/chromium/src/base/histogram.cc +++ b/ipc/chromium/src/base/histogram.cc @@ -436,7 +436,8 @@ Histogram::Histogram(const std::string& name, Sample minimum, bucket_count_(bucket_count), flags_(kNoFlags), ranges_(bucket_count + 1, 0), - range_checksum_(0) { + range_checksum_(0), + recording_enabled_(true) { Initialize(); } @@ -449,7 +450,8 @@ Histogram::Histogram(const std::string& name, TimeDelta minimum, bucket_count_(bucket_count), flags_(kNoFlags), ranges_(bucket_count + 1, 0), - range_checksum_(0) { + range_checksum_(0), + recording_enabled_(true) { Initialize(); } @@ -558,8 +560,7 @@ const std::string Histogram::GetAsciiBucketRange(size_t i) const { // Update histogram data with new sample. void Histogram::Accumulate(Sample value, Count count, size_t index) { // Note locking not done in this version!!! - sample_.AccumulateWithExponentialStats(value, count, index, - flags_ & kExtendedStatisticsFlag); + sample_.AccumulateWithLinearStats(value, count, index); } void Histogram::SetBucketRange(size_t i, Sample value) { @@ -741,19 +742,6 @@ void Histogram::SampleSet::AccumulateWithLinearStats(Sample value, sum_squares_ += static_cast(count) * value * value; } -void Histogram::SampleSet::AccumulateWithExponentialStats(Sample value, - Count count, - size_t index, - bool computeExtendedStatistics) { - Accumulate(value, count, index); - if (computeExtendedStatistics) { - DCHECK_GE(value, 0); - float value_log = logf(static_cast(value) + 1.0f); - log_sum_ += count * value_log; - log_sum_squares_ += count * value_log * value_log; - } -} - Count Histogram::SampleSet::TotalCount() const { Count total = 0; for (Counts::const_iterator it = counts_.begin(); diff --git a/ipc/chromium/src/base/histogram.h b/ipc/chromium/src/base/histogram.h index 289206d30c..1b94bf18b9 100644 --- a/ipc/chromium/src/base/histogram.h +++ b/ipc/chromium/src/base/histogram.h @@ -41,6 +41,7 @@ #define BASE_METRICS_HISTOGRAM_H_ #pragma once +#include "mozilla/Atomics.h" #include "mozilla/MemoryReporting.h" #include @@ -292,7 +293,6 @@ class Histogram { enum Flags { kNoFlags = 0, kUmaTargetedHistogramFlag = 0x1, // Histogram should be UMA uploaded. - kExtendedStatisticsFlag = 0x2, // OK to gather extended statistics on histograms. // Indicate that the histogram was pickled to be sent across an IPC Channel. // If we observe this flag on a histogram being aggregated into after IPC, @@ -335,10 +335,6 @@ class Histogram { // Accessor for histogram to make routine additions. void AccumulateWithLinearStats(Sample value, Count count, size_t index); - // Alternate routine for exponential histograms. - // computeExpensiveStatistics should be true if we want to compute log sums. - void AccumulateWithExponentialStats(Sample value, Count count, size_t index, - bool computeExtendedStatistics); // Accessor methods. Count counts(size_t i) const { return counts_[i]; } @@ -405,6 +401,12 @@ class Histogram { void Add(int value); void Subtract(int value); + // TODO: Currently recording_enabled_ is not used by any Histogram class, but + // rather examined only by the telemetry code (via IsRecordingEnabled). + // Move handling to Histogram's Add() etc after simplifying Histogram. + void SetRecordingEnabled(bool aEnabled) { recording_enabled_ = aEnabled; }; + bool IsRecordingEnabled() const { return recording_enabled_; }; + // This method is an interface, used only by BooleanHistogram. virtual void AddBoolean(bool value); @@ -589,6 +591,9 @@ class Histogram { // have been corrupted. uint32_t range_checksum_; + // When false, new samples are completely ignored. + mozilla::Atomic recording_enabled_; + DISALLOW_COPY_AND_ASSIGN(Histogram); }; diff --git a/ipc/chromium/src/base/message_loop.h b/ipc/chromium/src/base/message_loop.h index 1ec889d3a9..553022a83e 100644 --- a/ipc/chromium/src/base/message_loop.h +++ b/ipc/chromium/src/base/message_loop.h @@ -233,9 +233,9 @@ public: int32_t id() const { return id_; } // Optional call to connect the thread name with this loop. - void set_thread_name(const std::string& thread_name) { + void set_thread_name(const std::string& aThreadName) { DCHECK(thread_name_.empty()) << "Should not rename this thread!"; - thread_name_ = thread_name; + thread_name_ = aThreadName; } const std::string& thread_name() const { return thread_name_; } @@ -324,8 +324,8 @@ public: int sequence_num; // Secondary sort key for run time. bool nestable; // OK to dispatch from a nested loop. - PendingTask(Task* task, bool nestable) - : task(task), sequence_num(0), nestable(nestable) { + PendingTask(Task* aTask, bool aNestable) + : task(aTask), sequence_num(0), nestable(aNestable) { } // Used to support sorting. @@ -463,7 +463,7 @@ public: // class MessageLoopForUI : public MessageLoop { public: - explicit MessageLoopForUI(Type type=TYPE_UI) : MessageLoop(type) { + explicit MessageLoopForUI(Type aType=TYPE_UI) : MessageLoop(aType) { } // Returns the MessageLoopForUI of the current thread. diff --git a/ipc/chromium/src/base/process.h b/ipc/chromium/src/base/process.h index d6bfa64bc7..3dd009a074 100644 --- a/ipc/chromium/src/base/process.h +++ b/ipc/chromium/src/base/process.h @@ -29,8 +29,8 @@ typedef pid_t ProcessId; class Process { public: Process() : process_(0), last_working_set_size_(0) {} - explicit Process(ProcessHandle handle) : - process_(handle), last_working_set_size_(0) {} + explicit Process(ProcessHandle aHandle) : + process_(aHandle), last_working_set_size_(0) {} // A handle to the current process. static Process Current(); @@ -38,7 +38,7 @@ class Process { // Get/Set the handle for this process. The handle will be 0 if the process // is no longer running. ProcessHandle handle() const { return process_; } - void set_handle(ProcessHandle handle) { process_ = handle; } + void set_handle(ProcessHandle aHandle) { process_ = aHandle; } // Get the PID for this process. ProcessId pid() const; diff --git a/ipc/chromium/src/base/process_util_mac.mm b/ipc/chromium/src/base/process_util_mac.mm index dc5b0114de..77453d5ed4 100644 --- a/ipc/chromium/src/base/process_util_mac.mm +++ b/ipc/chromium/src/base/process_util_mac.mm @@ -129,6 +129,7 @@ bool LaunchApp(const std::vector& argv, break; case PROCESS_ARCH_PPC: cpu_types[0] = CPU_TYPE_POWERPC; + break; default: cpu_types[0] = CPU_TYPE_ANY; break; diff --git a/ipc/chromium/src/base/revocable_store.h b/ipc/chromium/src/base/revocable_store.h index 17516c92ba..c92a033dce 100644 --- a/ipc/chromium/src/base/revocable_store.h +++ b/ipc/chromium/src/base/revocable_store.h @@ -20,9 +20,9 @@ class RevocableStore { class StoreRef final { public: NS_INLINE_DECL_THREADSAFE_REFCOUNTING(StoreRef) - explicit StoreRef(RevocableStore* store) : store_(store) { } + explicit StoreRef(RevocableStore* aStore) : store_(aStore) { } - void set_store(RevocableStore* store) { store_ = store; } + void set_store(RevocableStore* aStore) { store_ = aStore; } RevocableStore* store() const { return store_; } protected: diff --git a/ipc/chromium/src/base/string_piece.h b/ipc/chromium/src/base/string_piece.h index 90edb2efe3..d3b63e4ce7 100644 --- a/ipc/chromium/src/base/string_piece.h +++ b/ipc/chromium/src/base/string_piece.h @@ -54,14 +54,14 @@ class StringPiece { bool empty() const { return length_ == 0; } void clear() { ptr_ = NULL; length_ = 0; } - void set(const char* data, size_type len) { ptr_ = data; length_ = len; } + void set(const char* aData, size_type aLen) { ptr_ = aData; length_ = aLen; } void set(const char* str) { ptr_ = str; length_ = str ? strlen(str) : 0; } - void set(const void* data, size_type len) { - ptr_ = reinterpret_cast(data); - length_ = len; + void set(const void* aData, size_type aLen) { + ptr_ = reinterpret_cast(aData); + length_ = aLen; } char operator[](size_type i) const { return ptr_[i]; } diff --git a/ipc/chromium/src/base/tracked.h b/ipc/chromium/src/base/tracked.h index 129eea2fef..0869067fff 100644 --- a/ipc/chromium/src/base/tracked.h +++ b/ipc/chromium/src/base/tracked.h @@ -39,10 +39,10 @@ class Location { // Constructor should be called with a long-lived char*, such as __FILE__. // It assumes the provided value will persist as a global constant, and it // will not make a copy of it. - Location(const char* function_name, const char* file_name, int line_number) - : function_name_(function_name), - file_name_(file_name), - line_number_(line_number) { } + Location(const char* aFunctionName, const char* aFilename, int aLineNumber) + : function_name_(aFunctionName), + file_name_(aFilename), + line_number_(aLineNumber) { } // Provide a default constructor for easy of debugging. Location() diff --git a/ipc/chromium/src/chrome/common/child_process_info.h b/ipc/chromium/src/chrome/common/child_process_info.h index 0af06272d1..46aed71729 100644 --- a/ipc/chromium/src/chrome/common/child_process_info.h +++ b/ipc/chromium/src/chrome/common/child_process_info.h @@ -79,10 +79,10 @@ class ChildProcessInfo { } protected: - void set_type(ProcessType type) { type_ = type; } - void set_name(const std::wstring& name) { name_ = name; } - void set_handle(base::ProcessHandle handle) { - process_.set_handle(handle); + void set_type(ProcessType aType) { type_ = aType; } + void set_name(const std::wstring& aName) { name_ = aName; } + void set_handle(base::ProcessHandle aHandle) { + process_.set_handle(aHandle); pid_ = -1; } diff --git a/ipc/chromium/src/chrome/common/ipc_message.cc b/ipc/chromium/src/chrome/common/ipc_message.cc index 1e4216a59a..ab68ea7f46 100644 --- a/ipc/chromium/src/chrome/common/ipc_message.cc +++ b/ipc/chromium/src/chrome/common/ipc_message.cc @@ -25,10 +25,12 @@ namespace IPC { //------------------------------------------------------------------------------ Message::~Message() { + MOZ_COUNT_DTOR(IPC::Message); } Message::Message() : Pickle(sizeof(Header)) { + MOZ_COUNT_CTOR(IPC::Message); header()->routing = header()->type = header()->flags = 0; #if defined(OS_POSIX) header()->num_fds = 0; @@ -42,8 +44,9 @@ Message::Message() } Message::Message(int32_t routing_id, msgid_t type, PriorityValue priority, - MessageCompression compression, const char* const name) + MessageCompression compression, const char* const aName) : Pickle(sizeof(Header)) { + MOZ_COUNT_CTOR(IPC::Message); header()->routing = routing_id; header()->type = type; header()->flags = priority; @@ -65,14 +68,16 @@ Message::Message(int32_t routing_id, msgid_t type, PriorityValue priority, header()->parent_task_id = 0; header()->source_event_type = SourceEventType::Unknown; #endif - InitLoggingVariables(name); + InitLoggingVariables(aName); } Message::Message(const char* data, int data_len) : Pickle(data, data_len) { + MOZ_COUNT_CTOR(IPC::Message); InitLoggingVariables(); } Message::Message(const Message& other) : Pickle(other) { + MOZ_COUNT_CTOR(IPC::Message); InitLoggingVariables(other.name_); #if defined(OS_POSIX) file_descriptor_set_ = other.file_descriptor_set_; @@ -85,6 +90,7 @@ Message::Message(const Message& other) : Pickle(other) { } Message::Message(Message&& other) : Pickle(mozilla::Move(other)) { + MOZ_COUNT_CTOR(IPC::Message); InitLoggingVariables(other.name_); #if defined(OS_POSIX) file_descriptor_set_ = other.file_descriptor_set_.forget(); @@ -96,8 +102,8 @@ Message::Message(Message&& other) : Pickle(mozilla::Move(other)) { #endif } -void Message::InitLoggingVariables(const char* const name) { - name_ = name; +void Message::InitLoggingVariables(const char* const aName) { + name_ = aName; } Message& Message::operator=(const Message& other) { diff --git a/ipc/chromium/src/chrome/common/ipc_message.h b/ipc/chromium/src/chrome/common/ipc_message.h index bb75389422..27f6e519da 100644 --- a/ipc/chromium/src/chrome/common/ipc_message.h +++ b/ipc/chromium/src/chrome/common/ipc_message.h @@ -190,16 +190,16 @@ class Message : public Pickle { return header()->seqno; } - void set_seqno(int32_t seqno) { - header()->seqno = seqno; + void set_seqno(int32_t aSeqno) { + header()->seqno = aSeqno; } const char* const name() const { return name_; } - void set_name(const char* const name) { - name_ = name; + void set_name(const char* const aName) { + name_ = aName; } #if defined(OS_POSIX) diff --git a/layout/base/nsRefreshDriver.cpp b/layout/base/nsRefreshDriver.cpp index f57cdaf80c..7720b607a2 100644 --- a/layout/base/nsRefreshDriver.cpp +++ b/layout/base/nsRefreshDriver.cpp @@ -443,8 +443,11 @@ private: #ifndef ANDROID /* bug 1142079 */ if (XRE_IsParentProcess()) { TimeDuration vsyncLatency = TimeStamp::Now() - aVsyncTimestamp; + uint32_t sample = (uint32_t)vsyncLatency.ToMilliseconds(); Telemetry::Accumulate(Telemetry::FX_REFRESH_DRIVER_CHROME_FRAME_DELAY_MS, - vsyncLatency.ToMilliseconds()); + sample); + Telemetry::Accumulate(Telemetry::FX_REFRESH_DRIVER_SYNC_SCROLL_FRAME_DELAY_MS, + sample); } else if (mVsyncRate != TimeDuration::Forever()) { TimeDuration contentDelay = (TimeStamp::Now() - mLastChildTick) - mVsyncRate; if (contentDelay.ToMilliseconds() < 0 ){ @@ -452,8 +455,11 @@ private: // the reported hardware rate. In those cases, consider that we have 0 delay. contentDelay = TimeDuration::FromMilliseconds(0); } + uint32_t sample = (uint32_t)contentDelay.ToMilliseconds(); Telemetry::Accumulate(Telemetry::FX_REFRESH_DRIVER_CONTENT_FRAME_DELAY_MS, - contentDelay.ToMilliseconds()); + sample); + Telemetry::Accumulate(Telemetry::FX_REFRESH_DRIVER_SYNC_SCROLL_FRAME_DELAY_MS, + sample); } else { // Request the vsync rate from the parent process. Might be a few vsyncs // until the parent responds. diff --git a/layout/generic/nsGfxScrollFrame.cpp b/layout/generic/nsGfxScrollFrame.cpp index e128a9a2d3..dea913bff1 100644 --- a/layout/generic/nsGfxScrollFrame.cpp +++ b/layout/generic/nsGfxScrollFrame.cpp @@ -41,6 +41,7 @@ #include "mozilla/dom/Element.h" #include #include "mozilla/MathAlgorithms.h" +#include "mozilla/Telemetry.h" #include "FrameLayerBuilder.h" #include "nsSMILKeySpline.h" #include "nsSubDocumentFrame.h" @@ -1510,6 +1511,8 @@ public: , mCallee(nullptr) , mOneDevicePixelInAppUnits(aPresContext->DevPixelsToAppUnits(1)) { + Telemetry::SetHistogramRecordingEnabled( + Telemetry::FX_REFRESH_DRIVER_SYNC_SCROLL_FRAME_DELAY_MS, true); } NS_INLINE_DECL_REFCOUNTING(AsyncSmoothMSDScroll, override) @@ -1598,6 +1601,8 @@ private: // Private destructor, to discourage deletion outside of Release(): ~AsyncSmoothMSDScroll() { RemoveObserver(); + Telemetry::SetHistogramRecordingEnabled( + Telemetry::FX_REFRESH_DRIVER_SYNC_SCROLL_FRAME_DELAY_MS, false); } nsRefreshDriver* RefreshDriver(ScrollFrameHelper* aCallee) { @@ -1634,12 +1639,17 @@ public: explicit AsyncScroll(nsPoint aStartPos) : AsyncScrollBase(aStartPos) , mCallee(nullptr) - {} + { + Telemetry::SetHistogramRecordingEnabled( + Telemetry::FX_REFRESH_DRIVER_SYNC_SCROLL_FRAME_DELAY_MS, true); + } private: // Private destructor, to discourage deletion outside of Release(): ~AsyncScroll() { RemoveObserver(); + Telemetry::SetHistogramRecordingEnabled( + Telemetry::FX_REFRESH_DRIVER_SYNC_SCROLL_FRAME_DELAY_MS, false); } public: diff --git a/layout/media/symbols.def.in b/layout/media/symbols.def.in index 48fb8be9eb..f53906e4b9 100644 --- a/layout/media/symbols.def.in +++ b/layout/media/symbols.def.in @@ -521,6 +521,7 @@ _moz_cairo_transform _moz_cairo_translate _moz_cairo_user_to_device _moz_cairo_user_to_device_distance +_moz_cairo_win32_font_face_create_for_logfontw _moz_cairo_win32_font_face_create_for_logfontw_hfont _moz_cairo_win32_get_dc_with_clip _moz_cairo_win32_get_system_text_quality diff --git a/layout/printing/PrintTranslator.cpp b/layout/printing/PrintTranslator.cpp new file mode 100644 index 0000000000..686e99b4a3 --- /dev/null +++ b/layout/printing/PrintTranslator.cpp @@ -0,0 +1,102 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "PrintTranslator.h" + +#include "gfxContext.h" +#include "nsDeviceContext.h" +#include "mozilla/gfx/RecordedEvent.h" +#include "mozilla/gfx/RecordingTypes.h" +#include "mozilla/UniquePtr.h" + +using namespace mozilla::gfx; + +namespace mozilla { +namespace layout { + +PrintTranslator::PrintTranslator(nsDeviceContext* aDeviceContext) + : mDeviceContext(aDeviceContext) +{ + RefPtr context = mDeviceContext->CreateRenderingContext(); + mBaseDT = context->GetDrawTarget(); +} + +bool +PrintTranslator::TranslateRecording(std::istream& aRecording) +{ + uint32_t magicInt; + ReadElement(aRecording, magicInt); + if (magicInt != mozilla::gfx::kMagicInt) { + return false; + } + + uint16_t majorRevision; + ReadElement(aRecording, majorRevision); + if (majorRevision != kMajorRevision) { + return false; + } + + uint16_t minorRevision; + ReadElement(aRecording, minorRevision); + if (minorRevision > kMinorRevision) { + return false; + } + + int32_t eventType; + ReadElement(aRecording, eventType); + while (aRecording.good()) { + UniquePtr recordedEvent( + RecordedEvent::LoadEventFromStream(aRecording, + static_cast(eventType))); + + // Make sure that the whole event was read from the stream successfully. + if (!aRecording.good() || !recordedEvent) { + return false; + } + + recordedEvent->PlayEvent(this); + ReadElement(aRecording, eventType); + } + + return true; +} + +already_AddRefed +PrintTranslator::CreateDrawTarget(ReferencePtr aRefPtr, + const gfx::IntSize &aSize, + gfx::SurfaceFormat aFormat) +{ + RefPtr context = mDeviceContext->CreateRenderingContext(); + if (!context) { + NS_WARNING("Failed to create rendering context for print."); + return nullptr; + } + + RefPtr drawTarget = context->GetDrawTarget(); + AddDrawTarget(aRefPtr, drawTarget); + return drawTarget.forget(); +} + +FontType +PrintTranslator::GetDesiredFontType() +{ + switch (mBaseDT->GetBackendType()) { + case BackendType::DIRECT2D: + return FontType::DWRITE; + case BackendType::CAIRO: + return FontType::CAIRO; + case BackendType::SKIA: + return FontType::SKIA; + case BackendType::COREGRAPHICS: + case BackendType::COREGRAPHICS_ACCELERATED: + return FontType::COREGRAPHICS; + default: + return FontType::CAIRO; + } +} + +} // namespace layout +} // namespace mozilla \ No newline at end of file diff --git a/layout/printing/PrintTranslator.h b/layout/printing/PrintTranslator.h new file mode 100644 index 0000000000..92d8bbed2b --- /dev/null +++ b/layout/printing/PrintTranslator.h @@ -0,0 +1,178 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_layout_PrintTranslator_h +#define mozilla_layout_PrintTranslator_h + +#include + +#include "mozilla/gfx/2D.h" +#include "mozilla/gfx/Filters.h" +#include "mozilla/gfx/RecordedEvent.h" +#include "nsRefPtrHashtable.h" + +class nsDeviceContext; + +namespace mozilla { +namespace layout { + +using gfx::Translator; +using gfx::ReferencePtr; +using gfx::DrawTarget; +using gfx::Path; +using gfx::SourceSurface; +using gfx::FilterNode; +using gfx::GradientStops; +using gfx::ScaledFont; +using gfx::NativeFontResource; + +class PrintTranslator final : public Translator +{ +public: + explicit PrintTranslator(nsDeviceContext* aDeviceContext); + + bool TranslateRecording(std::istream& aRecording); + + DrawTarget* LookupDrawTarget(ReferencePtr aRefPtr) final + { + DrawTarget* result = mDrawTargets.GetWeak(aRefPtr); + MOZ_ASSERT(result); + return result; + } + + Path* LookupPath(ReferencePtr aRefPtr) final + { + Path* result = mPaths.GetWeak(aRefPtr); + MOZ_ASSERT(result); + return result; + } + + SourceSurface* LookupSourceSurface(ReferencePtr aRefPtr) final + { + SourceSurface* result = mSourceSurfaces.GetWeak(aRefPtr); + MOZ_ASSERT(result); + return result; + } + + FilterNode* LookupFilterNode(ReferencePtr aRefPtr) final + { + FilterNode* result = mFilterNodes.GetWeak(aRefPtr); + MOZ_ASSERT(result); + return result; + } + + GradientStops* LookupGradientStops(ReferencePtr aRefPtr) final + { + GradientStops* result = mGradientStops.GetWeak(aRefPtr); + MOZ_ASSERT(result); + return result; + } + + ScaledFont* LookupScaledFont(ReferencePtr aRefPtr) final + { + ScaledFont* result = mScaledFonts.GetWeak(aRefPtr); + MOZ_ASSERT(result); + return result; + } + + NativeFontResource* LookupNativeFontResource(uint64_t aKey) final + { + NativeFontResource* result = mNativeFontResources.GetWeak(aKey); + MOZ_ASSERT(result); + return result; + } + + void AddDrawTarget(ReferencePtr aRefPtr, DrawTarget *aDT) final + { + mDrawTargets.Put(aRefPtr, aDT); + } + + void AddPath(ReferencePtr aRefPtr, Path *aPath) final + { + mPaths.Put(aRefPtr, aPath); + } + + void AddSourceSurface(ReferencePtr aRefPtr, SourceSurface *aSurface) final + { + mSourceSurfaces.Put(aRefPtr, aSurface); + } + + void AddFilterNode(ReferencePtr aRefPtr, FilterNode *aFilter) final + { + mFilterNodes.Put(aRefPtr, aFilter); + } + + void AddGradientStops(ReferencePtr aRefPtr, GradientStops *aStops) final + { + mGradientStops.Put(aRefPtr, aStops); + } + + void AddScaledFont(ReferencePtr aRefPtr, ScaledFont *aScaledFont) final + { + mScaledFonts.Put(aRefPtr, aScaledFont); + } + + void AddNativeFontResource(uint64_t aKey, + NativeFontResource *aScaledFontResouce) final + { + mNativeFontResources.Put(aKey, aScaledFontResouce); + } + + void RemoveDrawTarget(ReferencePtr aRefPtr) final + { + mDrawTargets.Remove(aRefPtr); + } + + void RemovePath(ReferencePtr aRefPtr) final + { + mPaths.Remove(aRefPtr); + } + + void RemoveSourceSurface(ReferencePtr aRefPtr) final + { + mSourceSurfaces.Remove(aRefPtr); + } + + void RemoveFilterNode(ReferencePtr aRefPtr) final + { + mFilterNodes.Remove(aRefPtr); + } + + void RemoveGradientStops(ReferencePtr aRefPtr) final + { + mGradientStops.Remove(aRefPtr); + } + + void RemoveScaledFont(ReferencePtr aRefPtr) final + { + mScaledFonts.Remove(aRefPtr); + } + + already_AddRefed CreateDrawTarget(ReferencePtr aRefPtr, + const gfx::IntSize &aSize, + gfx::SurfaceFormat aFormat) final; + + mozilla::gfx::DrawTarget* GetReferenceDrawTarget() final { return mBaseDT; } + + mozilla::gfx::FontType GetDesiredFontType() final; + +private: + RefPtr mDeviceContext; + RefPtr mBaseDT; + + nsRefPtrHashtable, DrawTarget> mDrawTargets; + nsRefPtrHashtable, Path> mPaths; + nsRefPtrHashtable, SourceSurface> mSourceSurfaces; + nsRefPtrHashtable, FilterNode> mFilterNodes; + nsRefPtrHashtable, GradientStops> mGradientStops; + nsRefPtrHashtable, ScaledFont> mScaledFonts; + nsRefPtrHashtable mNativeFontResources; +}; + +} // namespace layout +} // namespace mozilla + +#endif // mozilla_layout_PrintTranslator_h diff --git a/layout/printing/ipc/PRemotePrintJob.ipdl b/layout/printing/ipc/PRemotePrintJob.ipdl new file mode 100644 index 0000000000..d89e077098 --- /dev/null +++ b/layout/printing/ipc/PRemotePrintJob.ipdl @@ -0,0 +1,47 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +include protocol PPrinting; + +namespace mozilla { +namespace layout { + +async protocol PRemotePrintJob +{ + manager PPrinting; + +both: + // Tell either side to abort printing and clean up. + async AbortPrint(nsresult aRv); + +parent: + // Initialize the real print device with the given information. + async InitializePrint(nsString aDocumentTitle, nsString aPrintToFile, + int32_t aStartPage, int32_t aEndPage); + + // Translate the stored page recording and play back the events to the real + // print device. + // This will always deallocate the shared memory. + async ProcessPage(Shmem aStoredPage); + + // This informs the real print device that we've finished, so it can trigger + // the actual print. + async FinalizePrint(); + + +child: + // Inform the child that the print has been initialized in the parent or has + // failed with result aRv. + async PrintInitializationResult(nsresult aRv); + + // Inform the child that the latest page has been processed remotely. + async PageProcessed(); + + async __delete__(); +}; + +} // namespace layout +} // namespace mozilla diff --git a/layout/printing/ipc/RemotePrintJobChild.cpp b/layout/printing/ipc/RemotePrintJobChild.cpp new file mode 100644 index 0000000000..6e930ec653 --- /dev/null +++ b/layout/printing/ipc/RemotePrintJobChild.cpp @@ -0,0 +1,102 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "RemotePrintJobChild.h" + +#include "mozilla/unused.h" +#include "nsPagePrintTimer.h" +#include "nsPrintEngine.h" + +namespace mozilla { +namespace layout { + +RemotePrintJobChild::RemotePrintJobChild() +{ + MOZ_COUNT_CTOR(RemotePrintJobChild); +} + +nsresult +RemotePrintJobChild::InitializePrint(const nsString& aDocumentTitle, + const nsString& aPrintToFile, + const int32_t& aStartPage, + const int32_t& aEndPage) +{ + // Print initialization can sometimes display a dialog in the parent, so we + // need to spin a nested event loop until initialization completes. + Unused << SendInitializePrint(aDocumentTitle, aPrintToFile, aStartPage, + aEndPage); + while (!mPrintInitialized) { + Unused << NS_ProcessNextEvent(); + } + + return mInitializationResult; +} + +bool +RemotePrintJobChild::RecvPrintInitializationResult(const nsresult& aRv) +{ + mPrintInitialized = true; + mInitializationResult = aRv; + return true; +} + +void +RemotePrintJobChild::ProcessPage(Shmem& aStoredPage) +{ + MOZ_ASSERT(mPagePrintTimer); + + mPagePrintTimer->WaitForRemotePrint(); + Unused << SendProcessPage(aStoredPage); +} + +bool +RemotePrintJobChild::RecvPageProcessed() +{ + MOZ_ASSERT(mPagePrintTimer); + + mPagePrintTimer->RemotePrintFinished(); + return true; +} + +bool +RemotePrintJobChild::RecvAbortPrint(const nsresult& aRv) +{ + MOZ_ASSERT(mPrintEngine); + + mPrintEngine->CleanupOnFailure(aRv, true); + return true; +} + +void +RemotePrintJobChild::SetPagePrintTimer(nsPagePrintTimer* aPagePrintTimer) +{ + MOZ_ASSERT(aPagePrintTimer); + + mPagePrintTimer = aPagePrintTimer; +} + +void +RemotePrintJobChild::SetPrintEngine(nsPrintEngine* aPrintEngine) +{ + MOZ_ASSERT(aPrintEngine); + + mPrintEngine = aPrintEngine; +} + +RemotePrintJobChild::~RemotePrintJobChild() +{ + MOZ_COUNT_DTOR(RemotePrintJobChild); +} + +void +RemotePrintJobChild::ActorDestroy(ActorDestroyReason aWhy) +{ + mPagePrintTimer = nullptr; + mPrintEngine = nullptr; +} + +} // namespace layout +} // namespace mozilla diff --git a/layout/printing/ipc/RemotePrintJobChild.h b/layout/printing/ipc/RemotePrintJobChild.h new file mode 100644 index 0000000000..f545559a0d --- /dev/null +++ b/layout/printing/ipc/RemotePrintJobChild.h @@ -0,0 +1,58 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_layout_RemotePrintJobChild_h +#define mozilla_layout_RemotePrintJobChild_h + +#include "mozilla/layout/PRemotePrintJobChild.h" + +#include "mozilla/RefPtr.h" + +class nsPagePrintTimer; +class nsPrintEngine; + +namespace mozilla { +namespace layout { + +class RemotePrintJobChild final : public PRemotePrintJobChild +{ +public: + NS_INLINE_DECL_REFCOUNTING(RemotePrintJobChild) + + RemotePrintJobChild(); + + void ActorDestroy(ActorDestroyReason aWhy) final; + + nsresult InitializePrint(const nsString& aDocumentTitle, + const nsString& aPrintToFile, + const int32_t& aStartPage, + const int32_t& aEndPage); + + bool RecvPrintInitializationResult(const nsresult& aRv) final; + + void ProcessPage(Shmem& aStoredPage); + + bool RecvPageProcessed() final; + + bool RecvAbortPrint(const nsresult& aRv) final; + + void SetPagePrintTimer(nsPagePrintTimer* aPagePrintTimer); + + void SetPrintEngine(nsPrintEngine* aPrintEngine); + +private: + ~RemotePrintJobChild() final; + + bool mPrintInitialized = false; + nsresult mInitializationResult = NS_OK; + RefPtr mPagePrintTimer; + RefPtr mPrintEngine; +}; + +} // namespace layout +} // namespace mozilla + +#endif // mozilla_layout_RemotePrintJobChild_h diff --git a/layout/printing/ipc/RemotePrintJobParent.cpp b/layout/printing/ipc/RemotePrintJobParent.cpp new file mode 100644 index 0000000000..38ac1c762d --- /dev/null +++ b/layout/printing/ipc/RemotePrintJobParent.cpp @@ -0,0 +1,165 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "RemotePrintJobParent.h" + +#include + +#include "gfxContext.h" +#include "mozilla/Attributes.h" +#include "mozilla/unused.h" +#include "nsComponentManagerUtils.h" +#include "nsDeviceContext.h" +#include "nsIDeviceContextSpec.h" +#include "nsIPrintSettings.h" +#include "PrintTranslator.h" + +namespace mozilla { +namespace layout { + +RemotePrintJobParent::RemotePrintJobParent(nsIPrintSettings* aPrintSettings) + : mPrintSettings(aPrintSettings) +{ + MOZ_COUNT_CTOR(RemotePrintJobParent); +} + +bool +RemotePrintJobParent::RecvInitializePrint(const nsString& aDocumentTitle, + const nsString& aPrintToFile, + const int32_t& aStartPage, + const int32_t& aEndPage) +{ + nsresult rv = InitializePrintDevice(aDocumentTitle, aPrintToFile, aStartPage, + aEndPage); + if (NS_FAILED(rv)) { + Unused << SendPrintInitializationResult(rv); + Unused << Send__delete__(this); + return true; + } + + mPrintTranslator.reset(new PrintTranslator(mPrintDeviceContext)); + Unused << SendPrintInitializationResult(NS_OK); + + return true; +} + +nsresult +RemotePrintJobParent::InitializePrintDevice(const nsString& aDocumentTitle, + const nsString& aPrintToFile, + const int32_t& aStartPage, + const int32_t& aEndPage) +{ + nsresult rv; + nsCOMPtr deviceContextSpec = + do_CreateInstance("@mozilla.org/gfx/devicecontextspec;1", &rv); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + rv = deviceContextSpec->Init(nullptr, mPrintSettings, false); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + mPrintDeviceContext = new nsDeviceContext(); + rv = mPrintDeviceContext->InitForPrinting(deviceContextSpec); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + rv = mPrintDeviceContext->BeginDocument(aDocumentTitle, aPrintToFile, + aStartPage, aEndPage); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + return NS_OK; +} + +bool +RemotePrintJobParent::RecvProcessPage(Shmem&& aStoredPage) +{ + nsresult rv = PrintPage(aStoredPage); + + // Always deallocate the shared memory no matter what the result. + if (!DeallocShmem(aStoredPage)) { + NS_WARNING("Failed to deallocated shared memory, remote print will abort."); + rv = NS_ERROR_FAILURE; + } + + if (NS_FAILED(rv)) { + Unused << SendAbortPrint(rv); + } else { + Unused << SendPageProcessed(); + } + + return true; +} + +nsresult +RemotePrintJobParent::PrintPage(const Shmem& aStoredPage) +{ + MOZ_ASSERT(mPrintDeviceContext); + + nsresult rv = mPrintDeviceContext->BeginPage(); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + std::istringstream recording(std::string(aStoredPage.get(), + aStoredPage.Size())); + mPrintTranslator->TranslateRecording(recording); + + rv = mPrintDeviceContext->EndPage(); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + return NS_OK; +} + +bool +RemotePrintJobParent::RecvFinalizePrint() +{ + // EndDocument is sometimes called in the child even when BeginDocument has + // not been called. See bug 1223332. + if (mPrintDeviceContext) { + nsresult rv = mPrintDeviceContext->EndDocument(); + + // Too late to abort the child just log. + NS_WARN_IF(NS_FAILED(rv)); + } + + + Unused << Send__delete__(this); + return true; +} + +bool +RemotePrintJobParent::RecvAbortPrint(const nsresult& aRv) +{ + if (mPrintDeviceContext) { + Unused << mPrintDeviceContext->AbortDocument(); + } + + Unused << Send__delete__(this); + return true; +} + +RemotePrintJobParent::~RemotePrintJobParent() +{ + MOZ_COUNT_DTOR(RemotePrintJobParent); +} + +void +RemotePrintJobParent::ActorDestroy(ActorDestroyReason aWhy) +{ +} + +} // namespace layout +} // namespace mozilla + + diff --git a/layout/printing/ipc/RemotePrintJobParent.h b/layout/printing/ipc/RemotePrintJobParent.h new file mode 100644 index 0000000000..764eedc523 --- /dev/null +++ b/layout/printing/ipc/RemotePrintJobParent.h @@ -0,0 +1,59 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_layout_RemotePrintJobParent_h +#define mozilla_layout_RemotePrintJobParent_h + +#include "mozilla/layout/PRemotePrintJobParent.h" + +#include "nsCOMPtr.h" +#include "mozilla/RefPtr.h" +#include "mozilla/UniquePtr.h" + +class nsDeviceContext; +class nsIPrintSettings; +class PrintTranslator; + +namespace mozilla { +namespace layout { + +class RemotePrintJobParent final : public PRemotePrintJobParent +{ +public: + explicit RemotePrintJobParent(nsIPrintSettings* aPrintSettings); + + void ActorDestroy(ActorDestroyReason aWhy) final; + + bool RecvInitializePrint(const nsString& aDocumentTitle, + const nsString& aPrintToFile, + const int32_t& aStartPage, + const int32_t& aEndPage) final; + + bool RecvProcessPage(Shmem&& aStoredPage) final; + + bool RecvFinalizePrint() final; + + bool RecvAbortPrint(const nsresult& aRv) final; + +private: + ~RemotePrintJobParent() final; + + nsresult InitializePrintDevice(const nsString& aDocumentTitle, + const nsString& aPrintToFile, + const int32_t& aStartPage, + const int32_t& aEndPage); + + nsresult PrintPage(const Shmem& aStoredPage); + + nsCOMPtr mPrintSettings; + RefPtr mPrintDeviceContext; + UniquePtr mPrintTranslator; +}; + +} // namespace layout +} // namespace mozilla + +#endif // mozilla_layout_RemotePrintJobParent_h diff --git a/layout/printing/moz.build b/layout/printing/moz.build index 9ffc51de10..a5996a9742 100644 --- a/layout/printing/moz.build +++ b/layout/printing/moz.build @@ -10,21 +10,34 @@ XPIDL_SOURCES += [ 'nsIPrintStatusFeedback.idl', ] +EXPORTS.mozilla.layout += [ + 'ipc/RemotePrintJobChild.h', + 'ipc/RemotePrintJobParent.h', +] + XPIDL_MODULE = 'layout_printing' UNIFIED_SOURCES += [ + 'ipc/RemotePrintJobChild.cpp', + 'ipc/RemotePrintJobParent.cpp', 'nsPagePrintTimer.cpp', 'nsPrintData.cpp', 'nsPrintEngine.cpp', 'nsPrintObject.cpp', 'nsPrintPreviewListener.cpp', + 'PrintTranslator.cpp', ] +IPDL_SOURCES = [ + 'ipc/PRemotePrintJob.ipdl', +] + +include('/ipc/chromium/chromium-config.mozbuild') + FINAL_LIBRARY = 'xul' LOCAL_INCLUDES += [ '../base', '/dom/base', ] - if CONFIG['GNU_CXX']: CXXFLAGS += ['-Wshadow'] diff --git a/layout/printing/nsPagePrintTimer.cpp b/layout/printing/nsPagePrintTimer.cpp index 9b897092ec..8e206e743a 100644 --- a/layout/printing/nsPagePrintTimer.cpp +++ b/layout/printing/nsPagePrintTimer.cpp @@ -4,6 +4,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "nsPagePrintTimer.h" + +#include "mozilla/unused.h" #include "nsIContentViewer.h" #include "nsIServiceManager.h" #include "nsPrintEngine.h" @@ -112,25 +114,38 @@ nsPagePrintTimer::Notify(nsITimer *timer) return NS_OK; } - // There are three things that call Notify with different values for timer: + // There are four things that call Notify with different values for timer: // 1) the delay between pages (timer == mTimer) // 2) canvasPrintState done (timer == null) // 3) the watch dog timer (timer == mWatchDogTimer) - if (timer && timer == mWatchDogTimer) { + // 4) the waiting for remote print "timer" (timer == mWaitingForRemotePrint) + if (!timer) { + // Reset the counter since a mozPrintCallback has finished. + mWatchDogCount = 0; + } else if (timer == mTimer) { + // Reset the watchdog timer before the start of every page. + mWatchDogCount = 0; + mTimer = nullptr; + } else if (timer == mWaitingForRemotePrint) { + mWaitingForRemotePrint = nullptr; + + // If we are still waiting for the page delay timer, don't let the + // notification from the remote print job trigger the next page. + if (mTimer) { + return NS_OK; + } + } else if (timer == mWatchDogTimer) { mWatchDogCount++; if (mWatchDogCount > WATCH_DOG_MAX_COUNT) { Fail(); return NS_OK; } - } else if(!timer) { - // Reset the counter since a mozPrintCallback has finished. - mWatchDogCount = 0; } if (mDocViewerPrint) { bool donePrePrint = mPrintEngine->PrePrintPage(); - if (donePrePrint) { + if (donePrePrint && !mWaitingForRemotePrint) { StopWatchDogTimer(); NS_DispatchToMainThread(this); } else { @@ -143,11 +158,33 @@ nsPagePrintTimer::Notify(nsITimer *timer) return NS_OK; } + +void +nsPagePrintTimer::WaitForRemotePrint() +{ + nsresult result; + mWaitingForRemotePrint = do_CreateInstance("@mozilla.org/timer;1", &result); + if (NS_FAILED(result)) { + NS_WARNING("Failed to wait for remote print, we might time-out."); + mWaitingForRemotePrint = nullptr; + } +} + +void +nsPagePrintTimer::RemotePrintFinished() +{ + if (!mWaitingForRemotePrint) { + return; + } + + mozilla::Unused << + mWaitingForRemotePrint->InitWithCallback(this, 0, nsITimer::TYPE_ONE_SHOT); +} + nsresult nsPagePrintTimer::Start(nsPrintObject* aPO) { mPrintObj = aPO; - mWatchDogCount = 0; mDone = false; return StartTimer(false); } diff --git a/layout/printing/nsPagePrintTimer.h b/layout/printing/nsPagePrintTimer.h index 396effbf75..6cd4332b01 100644 --- a/layout/printing/nsPagePrintTimer.h +++ b/layout/printing/nsPagePrintTimer.h @@ -47,6 +47,9 @@ public: void Stop(); + void WaitForRemotePrint(); + void RemotePrintFinished(); + private: ~nsPagePrintTimer(); @@ -59,6 +62,7 @@ private: nsCOMPtr mDocViewerPrint; nsCOMPtr mTimer; nsCOMPtr mWatchDogTimer; + nsCOMPtr mWaitingForRemotePrint; uint32_t mDelay; uint32_t mFiringCount; nsPrintObject * mPrintObj; diff --git a/layout/printing/nsPrintEngine.cpp b/layout/printing/nsPrintEngine.cpp index 4ba8ed64d2..de26a45b24 100644 --- a/layout/printing/nsPrintEngine.cpp +++ b/layout/printing/nsPrintEngine.cpp @@ -75,6 +75,8 @@ static const char kPrintingPromptService[] = "@mozilla.org/embedcomp/printingpro #include "nsISelectionController.h" // Misc +#include "mozilla/gfx/DrawEventRecorder.h" +#include "mozilla/layout/RemotePrintJobChild.h" #include "nsISupportsUtils.h" #include "nsIScriptContext.h" #include "nsIDOMDocument.h" @@ -90,6 +92,7 @@ static const char kPrintingPromptService[] = "@mozilla.org/embedcomp/printingpro #include "nsWidgetsCID.h" #include "nsIDeviceContextSpec.h" +#include "nsDeviceContextSpecProxy.h" #include "nsViewManager.h" #include "nsView.h" #include "nsRenderingContext.h" @@ -568,9 +571,13 @@ nsPrintEngine::DoCommonPrint(bool aIsPrintPreview, mPrt->mPrintSettings->SetPrintOptions(nsIPrintSettings::kEnableSelectionRB, isSelection || mPrt->mIsIFrameSelected); - nsCOMPtr devspec - (do_CreateInstance("@mozilla.org/gfx/devicecontextspec;1", &rv)); - NS_ENSURE_SUCCESS(rv, rv); + nsCOMPtr devspec; + if (XRE_IsContentProcess() && Preferences::GetBool("print.print_via_parent")) { + devspec = new nsDeviceContextSpecProxy(); + } else { + devspec = do_CreateInstance("@mozilla.org/gfx/devicecontextspec;1", &rv); + NS_ENSURE_SUCCESS(rv, rv); + } nsScriptSuppressor scriptSuppressor(this); if (!aIsPrintPreview) { @@ -1676,14 +1683,15 @@ nsPrintEngine::SetupToPrintContent() mPrt->OnStartPrinting(); } - char16_t* fileName = nullptr; + nsAutoString fileNameStr; // check to see if we are printing to a file bool isPrintToFile = false; mPrt->mPrintSettings->GetPrintToFile(&isPrintToFile); if (isPrintToFile) { - // On some platforms The BeginDocument needs to know the name of the file - // and it uses the PrintService to get it, so we need to set it into the PrintService here + // On some platforms The BeginDocument needs to know the name of the file. + char16_t* fileName = nullptr; mPrt->mPrintSettings->GetToFileName(&fileName); + fileNameStr = fileName; } nsAutoString docTitleStr; @@ -1709,7 +1717,8 @@ nsPrintEngine::SetupToPrintContent() // to the "File Name" dialog, this comes back as an error // Don't start printing when regression test are executed if (!mPrt->mDebugFilePtr && mIsDoingPrinting) { - rv = mPrt->mPrintDC->BeginDocument(docTitleStr, fileName, startPage, endPage); + rv = mPrt->mPrintDC->BeginDocument(docTitleStr, fileNameStr, startPage, + endPage); } if (mIsCreatingPrintPreview) { @@ -3478,6 +3487,17 @@ nsPrintEngine::StartPagePrintTimer(nsPrintObject* aPO) RefPtr timer = new nsPagePrintTimer(this, mDocViewerPrint, printPageDelay); timer.forget(&mPagePrintTimer); + + nsCOMPtr printSession; + nsresult rv = mPrt->mPrintSettings->GetPrintSession(getter_AddRefs(printSession)); + if (NS_SUCCEEDED(rv) && printSession) { + RefPtr remotePrintJob; + printSession->GetRemotePrintJob(getter_AddRefs(remotePrintJob)); + if (NS_SUCCEEDED(rv) && remotePrintJob) { + remotePrintJob->SetPagePrintTimer(mPagePrintTimer); + remotePrintJob->SetPrintEngine(this); + } + } } return mPagePrintTimer->Start(aPO); diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 5eb9cddfd8..422b88a5fc 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -1324,6 +1324,13 @@ pref("print.print_edge_left", 0); pref("print.print_edge_right", 0); pref("print.print_edge_bottom", 0); +// Print via the parent process. This is only used when e10s is enabled. +#if defined(XP_WIN) +pref("print.print_via_parent", true); +#else +pref("print.print_via_parent", false); +#endif + // Pref used by the spellchecker extension to control the // maximum number of misspelled words that will be underlined // in a document. @@ -2013,6 +2020,13 @@ pref("network.dnsCacheExpirationGracePeriod", 300); // This preference can be used to turn off DNS prefetch. pref("network.dns.disablePrefetch", true); +// This preference controls whether .onion hostnames are +// rejected before being given to DNS. RFC 7686 +pref("network.dns.blockDotOnion", true); + +// These domains are treated as localhost equivalent +pref("network.dns.localDomains", ""); + // Contols whether or not "localhost" should resolve when offline pref("network.dns.offline-localhost", true); diff --git a/netwerk/cache2/CacheObserver.cpp b/netwerk/cache2/CacheObserver.cpp index e58227bf68..73449376c1 100644 --- a/netwerk/cache2/CacheObserver.cpp +++ b/netwerk/cache2/CacheObserver.cpp @@ -24,6 +24,8 @@ CacheObserver* CacheObserver::sSelf = nullptr; static uint32_t const kDefaultUseNewCache = 1; // Use the new cache by default uint32_t CacheObserver::sUseNewCache = kDefaultUseNewCache; +static bool sUseNewCacheTemp = false; // Temp trigger to not lose early adopters + static int32_t const kAutoDeleteCacheVersion = -1; // Auto-delete off by default static int32_t sAutoDeleteCacheVersion = kAutoDeleteCacheVersion; @@ -134,7 +136,9 @@ CacheObserver::AttachToPreferences() "browser.cache.auto_delete_cache_version", kAutoDeleteCacheVersion); mozilla::Preferences::AddUintVarCache( - &sUseNewCache, "browser.cache.backend", kDefaultUseNewCache); + &sUseNewCache, "browser.cache.use_new_backend", kDefaultUseNewCache); + mozilla::Preferences::AddBoolVarCache( + &sUseNewCacheTemp, "browser.cache.use_new_backend_temp", false); mozilla::Preferences::AddBoolVarCache( &sUseDiskCache, "browser.cache.disk.enable", kDefaultUseDiskCache); @@ -272,6 +276,9 @@ bool const CacheObserver::UseNewCache() { uint32_t useNewCache = sUseNewCache; + if (sUseNewCacheTemp) + useNewCache = 1; + switch (useNewCache) { case 0: // use the old cache backend return false; diff --git a/netwerk/cache2/CacheStorageService.cpp b/netwerk/cache2/CacheStorageService.cpp index 30cbe5e5a5..1885ce9f82 100644 --- a/netwerk/cache2/CacheStorageService.cpp +++ b/netwerk/cache2/CacheStorageService.cpp @@ -1742,8 +1742,7 @@ CacheStorageService::DoomStorageEntries(nsCSubstring const& aContextKey, sGlobalEntryTables->RemoveAndForget(memoryStorageID, memoryEntries); CacheEntryTable* diskEntries; - sGlobalEntryTables->Get(aContextKey, &diskEntries); - if (memoryEntries && diskEntries) { + if (memoryEntries && sGlobalEntryTables->Get(aContextKey, &diskEntries)) { for (auto iter = memoryEntries->Iter(); !iter.Done(); iter.Next()) { auto entry = iter.Data(); RemoveExactEntry(diskEntries, iter.Key(), entry, false); diff --git a/netwerk/dns/mdns/libmdns/nsDNSServiceDiscovery.h b/netwerk/dns/mdns/libmdns/nsDNSServiceDiscovery.h index 48d6019283..9bf2c798a8 100644 --- a/netwerk/dns/mdns/libmdns/nsDNSServiceDiscovery.h +++ b/netwerk/dns/mdns/libmdns/nsDNSServiceDiscovery.h @@ -8,7 +8,7 @@ #include "nsIDNSServiceDiscovery.h" #include "nsCOMPtr.h" -#include "RefPtr.h" +#include "mozilla/RefPtr.h" #include "nsRefPtrHashtable.h" namespace mozilla { diff --git a/netwerk/dns/mdns/libmdns/nsDNSServiceDiscovery.js b/netwerk/dns/mdns/libmdns/nsDNSServiceDiscovery.js index a52252ec1f..5f700dd700 100644 --- a/netwerk/dns/mdns/libmdns/nsDNSServiceDiscovery.js +++ b/netwerk/dns/mdns/libmdns/nsDNSServiceDiscovery.js @@ -16,9 +16,24 @@ function log(aMsg) { dump("-*- nsDNSServiceDiscovery.js : " + aMsg + "\n"); } +function generateUuid() { + var uuidGenerator = Components.classes["@mozilla.org/uuid-generator;1"]. + getService(Ci.nsIUUIDGenerator); + return uuidGenerator.generateUUID().toString(); +} + // Helper class to transform return objects to correct type. -function ListenerWrapper(aListener) { +function ListenerWrapper(aListener, aMdns) { this.listener = aListener; + this.mdns = aMdns; + + this.discoveryStarting = false; + this.stopDiscovery = false; + + this.registrationStarting = false; + this.stopRegistration = false; + + this.uuid = generateUuid(); } ListenerWrapper.prototype = { @@ -39,16 +54,25 @@ ListenerWrapper.prototype = { /* transparent types */ onDiscoveryStarted: function(aServiceType) { + this.discoveryStarting = false; this.listener.onDiscoveryStarted(aServiceType); + + if (this.stopDiscovery) { + this.mdns.stopDiscovery(aServiceType, this); + } }, onDiscoveryStopped: function(aServiceType) { this.listener.onDiscoveryStopped(aServiceType); }, onStartDiscoveryFailed: function(aServiceType, aErrorCode) { - this.listener.onStartDiscoveryFailed(aServiceType); + log('onStartDiscoveryFailed: ' + aServiceType + ' (' + aErrorCode + ')'); + this.discoveryStarting = false; + this.stopDiscovery = true; + this.listener.onStartDiscoveryFailed(aServiceType, aErrorCode); }, onStopDiscoveryFailed: function(aServiceType, aErrorCode) { - this.listener.onStopDiscoveryFailed(aServiceType); + log('onStopDiscoveryFailed: ' + aServiceType + ' (' + aErrorCode + ')'); + this.listener.onStopDiscoveryFailed(aServiceType, aErrorCode); }, /* transform types */ @@ -59,7 +83,12 @@ ListenerWrapper.prototype = { this.listener.onServiceLost(this.makeServiceInfo(aServiceInfo)); }, onServiceRegistered: function(aServiceInfo) { + this.registrationStarting = false; this.listener.onServiceRegistered(this.makeServiceInfo(aServiceInfo)); + + if (this.stopRegistration) { + this.mdns.unregisterService(aServiceInfo, this); + } }, onServiceUnregistered: function(aServiceInfo) { this.listener.onServiceUnregistered(this.makeServiceInfo(aServiceInfo)); @@ -69,12 +98,17 @@ ListenerWrapper.prototype = { }, onRegistrationFailed: function(aServiceInfo, aErrorCode) { + log('onRegistrationFailed: (' + aErrorCode + ')'); + this.registrationStarting = false; + this.stopRegistration = true; this.listener.onRegistrationFailed(this.makeServiceInfo(aServiceInfo), aErrorCode); }, onUnregistrationFailed: function(aServiceInfo, aErrorCode) { + log('onUnregistrationFailed: (' + aErrorCode + ')'); this.listener.onUnregistrationFailed(this.makeServiceInfo(aServiceInfo), aErrorCode); }, onResolveFailed: function(aServiceInfo, aErrorCode) { + log('onResolveFailed: (' + aErrorCode + ')'); this.listener.onResolveFailed(this.makeServiceInfo(aServiceInfo), aErrorCode); } }; @@ -90,27 +124,37 @@ nsDNSServiceDiscovery.prototype = { startDiscovery: function(aServiceType, aListener) { log("startDiscovery"); - let listener = new ListenerWrapper(aListener); + let listener = new ListenerWrapper(aListener, this.mdns); + listener.discoveryStarting = true; this.mdns.startDiscovery(aServiceType, listener); return { QueryInterface: XPCOMUtils.generateQI([Ci.nsICancelable]), cancel: (function() { - this.mdns.stopDiscovery(aServiceType, listener); - }).bind(this) + if (this.discoveryStarting || this.stopDiscovery) { + this.stopDiscovery = true; + return; + } + this.mdns.stopDiscovery(aServiceType, this); + }).bind(listener) }; }, registerService: function(aServiceInfo, aListener) { log("registerService"); - let listener = new ListenerWrapper(aListener); + let listener = new ListenerWrapper(aListener, this.mdns); + listener.registrationStarting = true; this.mdns.registerService(aServiceInfo, listener); return { QueryInterface: XPCOMUtils.generateQI([Ci.nsICancelable]), cancel: (function() { - this.mdns.unregisterService(aServiceInfo, listener); - }).bind(this) + if (this.registrationStarting || this.stopRegistration) { + this.stopRegistration = true; + return; + } + this.mdns.unregisterService(aServiceInfo, this); + }).bind(listener) }; }, diff --git a/netwerk/dns/nsDNSService2.cpp b/netwerk/dns/nsDNSService2.cpp index d571b11844..80447ddcbf 100644 --- a/netwerk/dns/nsDNSService2.cpp +++ b/netwerk/dns/nsDNSService2.cpp @@ -50,6 +50,7 @@ static const char kPrefDnsCacheGrace[] = "network.dnsCacheExpirationGraceP static const char kPrefIPv4OnlyDomains[] = "network.dns.ipv4OnlyDomains"; static const char kPrefDisableIPv6[] = "network.dns.disableIPv6"; static const char kPrefDisablePrefetch[] = "network.dns.disablePrefetch"; +static const char kPrefBlockDotOnion[] = "network.dns.blockDotOnion"; static const char kPrefDnsLocalDomains[] = "network.dns.localDomains"; static const char kPrefDnsOfflineLocalhost[] = "network.dns.offline-localhost"; static const char kPrefDnsNotifyResolution[] = "network.dns.notifyResolution"; @@ -543,6 +544,7 @@ nsDNSService::Init() bool disableIPv6 = false; bool offlineLocalhost = true; bool disablePrefetch = false; + bool blockDotOnion = true; int proxyType = nsIProtocolProxyService::PROXYCONFIG_DIRECT; bool notifyResolution = false; @@ -566,6 +568,7 @@ nsDNSService::Init() prefs->GetCharPref(kPrefDnsLocalDomains, getter_Copies(localDomains)); prefs->GetBoolPref(kPrefDnsOfflineLocalhost, &offlineLocalhost); prefs->GetBoolPref(kPrefDisablePrefetch, &disablePrefetch); + prefs->GetBoolPref(kPrefBlockDotOnion, &blockDotOnion); // If a manual proxy is in use, disable prefetch implicitly prefs->GetIntPref("network.proxy.type", &proxyType); @@ -585,6 +588,7 @@ nsDNSService::Init() prefs->AddObserver(kPrefDisableIPv6, this, false); prefs->AddObserver(kPrefDnsOfflineLocalhost, this, false); prefs->AddObserver(kPrefDisablePrefetch, this, false); + prefs->AddObserver(kPrefBlockDotOnion, this, false); prefs->AddObserver(kPrefDnsNotifyResolution, this, false); // Monitor these to see if there is a change in proxy configuration @@ -618,6 +622,7 @@ nsDNSService::Init() mIPv4OnlyDomains = ipv4OnlyDomains; // exchanges buffer ownership mOfflineLocalhost = offlineLocalhost; mDisableIPv6 = disableIPv6; + mBlockDotOnion = blockDotOnion; // Disable prefetching either by explicit preference or if a manual proxy is configured mDisablePrefetch = disablePrefetch || (proxyType == nsIProtocolProxyService::PROXYCONFIG_MANUAL); @@ -698,22 +703,32 @@ nsDNSService::SetPrefetchEnabled(bool inVal) return NS_OK; } -static inline bool PreprocessHostname(bool aLocalDomain, - const nsACString &aInput, - nsIIDNService *aIDN, - nsACString &aACE) +nsresult +nsDNSService::PreprocessHostname(bool aLocalDomain, + const nsACString &aInput, + nsIIDNService *aIDN, + nsACString &aACE) { + // Enforce RFC 7686 + if (mBlockDotOnion && + StringEndsWith(aInput, NS_LITERAL_CSTRING(".onion"))) { + return NS_ERROR_UNKNOWN_HOST; + } + if (aLocalDomain) { aACE.AssignLiteral("localhost"); - return true; + return NS_OK; } if (!aIDN || IsASCII(aInput)) { aACE = aInput; - return true; + return NS_OK; } - return IsUTF8(aInput) && NS_SUCCEEDED(aIDN->ConvertUTF8toACE(aInput, aACE)); + if (!(IsUTF8(aInput) && NS_SUCCEEDED(aIDN->ConvertUTF8toACE(aInput, aACE)))) { + return NS_ERROR_FAILURE; + } + return NS_OK; } NS_IMETHODIMP @@ -760,8 +775,10 @@ nsDNSService::AsyncResolveExtended(const nsACString &aHostname, return NS_ERROR_OFFLINE; nsCString hostname; - if (!PreprocessHostname(localDomain, aHostname, idn, hostname)) - return NS_ERROR_FAILURE; + nsresult rv = PreprocessHostname(localDomain, aHostname, idn, hostname); + if (NS_FAILED(rv)) { + return rv; + } if (mOffline && (!mOfflineLocalhost || !hostname.LowerCaseEqualsASCII("localhost"))) { @@ -791,9 +808,8 @@ nsDNSService::AsyncResolveExtended(const nsACString &aHostname, // addref for resolver; will be released when OnLookupComplete is called. NS_ADDREF(req); - nsresult rv = res->ResolveHost(req->mHost.get(), flags, af, - req->mNetworkInterface.get(), - req); + rv = res->ResolveHost(req->mHost.get(), flags, af, + req->mNetworkInterface.get(), req); if (NS_FAILED(rv)) { NS_RELEASE(req); NS_RELEASE(*result); @@ -837,8 +853,10 @@ nsDNSService::CancelAsyncResolveExtended(const nsACString &aHostname, return NS_ERROR_OFFLINE; nsCString hostname; - if (!PreprocessHostname(localDomain, aHostname, idn, hostname)) - return NS_ERROR_FAILURE; + nsresult rv = PreprocessHostname(localDomain, aHostname, idn, hostname); + if (NS_FAILED(rv)) { + return rv; + } uint16_t af = GetAFForLookup(hostname, aFlags); @@ -872,8 +890,10 @@ nsDNSService::Resolve(const nsACString &aHostname, NS_ENSURE_TRUE(res, NS_ERROR_OFFLINE); nsCString hostname; - if (!PreprocessHostname(localDomain, aHostname, idn, hostname)) - return NS_ERROR_FAILURE; + nsresult rv = PreprocessHostname(localDomain, aHostname, idn, hostname); + if (NS_FAILED(rv)) { + return rv; + } if (mOffline && (!mOfflineLocalhost || !hostname.LowerCaseEqualsASCII("localhost"))) { @@ -897,7 +917,7 @@ nsDNSService::Resolve(const nsACString &aHostname, uint16_t af = GetAFForLookup(hostname, flags); - nsresult rv = res->ResolveHost(hostname.get(), flags, af, "", &syncReq); + rv = res->ResolveHost(hostname.get(), flags, af, "", &syncReq); if (NS_SUCCEEDED(rv)) { // wait for result while (!syncReq.mDone) diff --git a/netwerk/dns/nsDNSService2.h b/netwerk/dns/nsDNSService2.h index 86156db53f..a33e2dd9b4 100644 --- a/netwerk/dns/nsDNSService2.h +++ b/netwerk/dns/nsDNSService2.h @@ -43,6 +43,11 @@ private: uint16_t GetAFForLookup(const nsACString &host, uint32_t flags); + nsresult PreprocessHostname(bool aLocalDomain, + const nsACString &aInput, + nsIIDNService *aIDN, + nsACString &aACE); + RefPtr mResolver; nsCOMPtr mIDN; @@ -55,6 +60,7 @@ private: nsAdoptingCString mIPv4OnlyDomains; bool mDisableIPv6; bool mDisablePrefetch; + bool mBlockDotOnion; bool mFirstTime; bool mOffline; bool mNotifyResolution; diff --git a/netwerk/dns/nsHostResolver.h b/netwerk/dns/nsHostResolver.h index 25658545b2..4c37ff0d3c 100644 --- a/netwerk/dns/nsHostResolver.h +++ b/netwerk/dns/nsHostResolver.h @@ -14,6 +14,7 @@ #include "mozilla/Mutex.h" #include "nsISupportsImpl.h" #include "nsIDNSListener.h" +#include "nsIDNSService.h" #include "nsString.h" #include "nsTArray.h" #include "GetAddrInfo.h" @@ -279,15 +280,15 @@ public: * to the flags defined on nsIDNSService. */ enum { - RES_BYPASS_CACHE = 1 << 0, - RES_CANON_NAME = 1 << 1, - RES_PRIORITY_MEDIUM = 1 << 2, - RES_PRIORITY_LOW = 1 << 3, - RES_SPECULATE = 1 << 4, - //RES_DISABLE_IPV6 = 1 << 5, // Not used - RES_OFFLINE = 1 << 6, - //RES_DISABLE_IPv4 = 1 << 7, // Not Used - RES_ALLOW_NAME_COLLISION = 1 << 8 + RES_BYPASS_CACHE = nsIDNSService::RESOLVE_BYPASS_CACHE, + RES_CANON_NAME = nsIDNSService::RESOLVE_CANONICAL_NAME, + RES_PRIORITY_MEDIUM = nsIDNSService::RESOLVE_PRIORITY_MEDIUM, + RES_PRIORITY_LOW = nsIDNSService::RESOLVE_PRIORITY_LOW, + RES_SPECULATE = nsIDNSService::RESOLVE_SPECULATE, + //RES_DISABLE_IPV6 = nsIDNSService::RESOLVE_DISABLE_IPV6, // Not used + RES_OFFLINE = nsIDNSService::RESOLVE_OFFLINE, + //RES_DISABLE_IPv4 = nsIDNSService::RESOLVE_DISABLE_IPV4, // Not Used + RES_ALLOW_NAME_COLLISION = nsIDNSService::RESOLVE_ALLOW_NAME_COLLISION }; size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const; diff --git a/netwerk/test/unit/test_dns_onion.js b/netwerk/test/unit/test_dns_onion.js new file mode 100644 index 0000000000..02647b9647 --- /dev/null +++ b/netwerk/test/unit/test_dns_onion.js @@ -0,0 +1,70 @@ +var dns = Cc["@mozilla.org/network/dns-service;1"].getService(Ci.nsIDNSService); +var threadManager = Cc["@mozilla.org/thread-manager;1"].getService(Ci.nsIThreadManager); +var mainThread = threadManager.currentThread; + +var onionPref; +var localdomainPref; +var prefs = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch); + +// check that we don't lookup .onion +var listenerBlock = { + onLookupComplete: function(inRequest, inRecord, inStatus) { + do_check_false(Components.isSuccessCode(inStatus)); + do_test_dontBlock(); + }, + QueryInterface: function(aIID) { + if (aIID.equals(Ci.nsIDNSListener) || + aIID.equals(Ci.nsISupports)) { + return this; + } + throw Cr.NS_ERROR_NO_INTERFACE; + } +}; + +// check that we do lookup .onion (via pref) +var listenerDontBlock = { + onLookupComplete: function(inRequest, inRecord, inStatus) { + var answer = inRecord.getNextAddrAsString(); + do_check_true(answer == "127.0.0.1" || answer == "::1"); + all_done(); + }, + QueryInterface: function(aIID) { + if (aIID.equals(Ci.nsIDNSListener) || + aIID.equals(Ci.nsISupports)) { + return this; + } + throw Cr.NS_ERROR_NO_INTERFACE; + } +}; + +function do_test_dontBlock() { + prefs.setBoolPref("network.dns.blockDotOnion", false); + dns.asyncResolve("private.onion", 0, listenerDontBlock, mainThread); +} + +function do_test_block() { + prefs.setBoolPref("network.dns.blockDotOnion", true); + try { + dns.asyncResolve("private.onion", 0, listenerBlock, mainThread); + } catch (e) { + // it is ok for this negative test to fail fast + do_check_true(true); + do_test_dontBlock(); + } +} + +function all_done() { + // reset locally modified prefs + prefs.setCharPref("network.dns.localDomains", localdomainPref); + prefs.setBoolPref("network.dns.blockDotOnion", onionPref); + do_test_finished(); +} + +function run_test() { + onionPref = prefs.getBoolPref("network.dns.blockDotOnion"); + localdomainPref = prefs.getCharPref("network.dns.localDomains"); + prefs.setCharPref("network.dns.localDomains", "private.onion"); + do_test_block(); + do_test_pending(); +} + diff --git a/netwerk/test/unit/xpcshell.ini b/netwerk/test/unit/xpcshell.ini index b64daeaf96..e2eeaa054e 100644 --- a/netwerk/test/unit/xpcshell.ini +++ b/netwerk/test/unit/xpcshell.ini @@ -187,6 +187,7 @@ skip-if = bits != 32 [test_data_protocol.js] [test_dns_service.js] [test_dns_offline.js] +[test_dns_onion.js] [test_dns_localredirect.js] [test_dns_proxy_bypass.js] [test_duplicate_headers.js] diff --git a/toolkit/components/contentprefs/tests/unit_cps2/head.js b/toolkit/components/contentprefs/tests/unit_cps2/head.js index 90f85fc4f1..c7c17756cb 100644 --- a/toolkit/components/contentprefs/tests/unit_cps2/head.js +++ b/toolkit/components/contentprefs/tests/unit_cps2/head.js @@ -231,7 +231,7 @@ function getGlobalOK(args, expectedVal) { function getOKEx(methodName, args, expectedPrefs, strict, context) { let actualPrefs = []; args.push(makeCallback({ - handleResult: function (pref) actualPrefs.push(pref) + handleResult: pref => actualPrefs.push(pref) })); yield cps[methodName].apply(cps, args); arraysOfArraysOK([actualPrefs], [expectedPrefs], function (actual, expected) { @@ -348,7 +348,7 @@ function dbOK(expectedRows) { handleResult: function (results) { let row = null; while (row = results.getNextRow()) { - actualRows.push(cols.map(function (c) row.getResultByName(c))); + actualRows.push(cols.map(c => row.getResultByName(c))); } }, handleError: function (err) { @@ -373,7 +373,7 @@ function on(event, names, dontRemove) { names.forEach(function (name) { let obs = {}; ["onContentPrefSet", "onContentPrefRemoved"].forEach(function (meth) { - obs[meth] = function () do_throw(meth + " should not be called"); + obs[meth] = () => do_throw(meth + " should not be called"); }); obs["onContentPref" + event] = function () { args[name].push(Array.slice(arguments)); @@ -386,7 +386,7 @@ function on(event, names, dontRemove) { do_execute_soon(function () { if (!dontRemove) - names.forEach(function (n) cps.removeObserverForName(n, observers[n])); + names.forEach(n => cps.removeObserverForName(n, observers[n])); next(args); }); } diff --git a/toolkit/components/contentprefs/tests/unit_cps2/test_getCached.js b/toolkit/components/contentprefs/tests/unit_cps2/test_getCached.js index 07f2188a91..e8ef01f67c 100644 --- a/toolkit/components/contentprefs/tests/unit_cps2/test_getCached.js +++ b/toolkit/components/contentprefs/tests/unit_cps2/test_getCached.js @@ -71,16 +71,12 @@ let tests = [ }, function erroneous() { - do_check_throws(function () - cps.getCachedByDomainAndName(null, "foo", null)); - do_check_throws(function () - cps.getCachedByDomainAndName("", "foo", null)); - do_check_throws(function () - cps.getCachedByDomainAndName("a.com", "", null)); - do_check_throws(function () - cps.getCachedByDomainAndName("a.com", null, null)); - do_check_throws(function () cps.getCachedGlobal("", null)); - do_check_throws(function () cps.getCachedGlobal(null, null)); + do_check_throws(() => cps.getCachedByDomainAndName(null, "foo", null)); + do_check_throws(() => cps.getCachedByDomainAndName("", "foo", null)); + do_check_throws(() => cps.getCachedByDomainAndName("a.com", "", null)); + do_check_throws(() => cps.getCachedByDomainAndName("a.com", null, null)); + do_check_throws(() => cps.getCachedGlobal("", null)); + do_check_throws(() => cps.getCachedGlobal(null, null)); yield true; }, diff --git a/toolkit/components/contentprefs/tests/unit_cps2/test_getCachedSubdomains.js b/toolkit/components/contentprefs/tests/unit_cps2/test_getCachedSubdomains.js index 239211000a..20cee4eac5 100644 --- a/toolkit/components/contentprefs/tests/unit_cps2/test_getCachedSubdomains.js +++ b/toolkit/components/contentprefs/tests/unit_cps2/test_getCachedSubdomains.js @@ -177,14 +177,10 @@ let tests = [ }, function erroneous() { - do_check_throws(function () - cps.getCachedBySubdomainAndName(null, "foo", null)); - do_check_throws(function () - cps.getCachedBySubdomainAndName("", "foo", null)); - do_check_throws(function () - cps.getCachedBySubdomainAndName("a.com", "", null)); - do_check_throws(function () - cps.getCachedBySubdomainAndName("a.com", null, null)); + do_check_throws(() => cps.getCachedBySubdomainAndName(null, "foo", null)); + do_check_throws(() => cps.getCachedBySubdomainAndName("", "foo", null)); + do_check_throws(() => cps.getCachedBySubdomainAndName("a.com", "", null)); + do_check_throws(() => cps.getCachedBySubdomainAndName("a.com", null, null)); yield true; }, ]; diff --git a/toolkit/components/contentprefs/tests/unit_cps2/test_getSubdomains.js b/toolkit/components/contentprefs/tests/unit_cps2/test_getSubdomains.js index 3d32584ca4..a436c9c928 100644 --- a/toolkit/components/contentprefs/tests/unit_cps2/test_getSubdomains.js +++ b/toolkit/components/contentprefs/tests/unit_cps2/test_getSubdomains.js @@ -58,16 +58,11 @@ let tests = [ }, function erroneous() { - do_check_throws(function () - cps.getBySubdomainAndName(null, "foo", null, {})); - do_check_throws(function () - cps.getBySubdomainAndName("", "foo", null, {})); - do_check_throws(function () - cps.getBySubdomainAndName("a.com", "", null, {})); - do_check_throws(function () - cps.getBySubdomainAndName("a.com", null, null, {})); - do_check_throws(function () - cps.getBySubdomainAndName("a.com", "foo", null, null)); + do_check_throws(() => cps.getBySubdomainAndName(null, "foo", null, {})); + do_check_throws(() => cps.getBySubdomainAndName("", "foo", null, {})); + do_check_throws(() => cps.getBySubdomainAndName("a.com", "", null, {})); + do_check_throws(() => cps.getBySubdomainAndName("a.com", null, null, {})); + do_check_throws(() => cps.getBySubdomainAndName("a.com", "foo", null, null)); yield true; }, ]; diff --git a/toolkit/components/contentprefs/tests/unit_cps2/test_remove.js b/toolkit/components/contentprefs/tests/unit_cps2/test_remove.js index a6a0bbef68..f294290bac 100644 --- a/toolkit/components/contentprefs/tests/unit_cps2/test_remove.js +++ b/toolkit/components/contentprefs/tests/unit_cps2/test_remove.js @@ -177,18 +177,18 @@ let tests = [ }, function erroneous() { - do_check_throws(function () cps.removeByDomainAndName(null, "foo", null)); - do_check_throws(function () cps.removeByDomainAndName("", "foo", null)); - do_check_throws(function () cps.removeByDomainAndName("a.com", "foo", null, - "bogus")); - do_check_throws(function () cps.removeBySubdomainAndName(null, "foo", - null)); - do_check_throws(function () cps.removeBySubdomainAndName("", "foo", null)); - do_check_throws(function () cps.removeBySubdomainAndName("a.com", "foo", - null, "bogus")); - do_check_throws(function () cps.removeGlobal("", null)); - do_check_throws(function () cps.removeGlobal(null, null)); - do_check_throws(function () cps.removeGlobal("foo", null, "bogus")); + do_check_throws(() => cps.removeByDomainAndName(null, "foo", null)); + do_check_throws(() => cps.removeByDomainAndName("", "foo", null)); + do_check_throws(() => cps.removeByDomainAndName("a.com", "foo", null, + "bogus")); + do_check_throws(() => cps.removeBySubdomainAndName(null, "foo", + null)); + do_check_throws(() => cps.removeBySubdomainAndName("", "foo", null)); + do_check_throws(() => cps.removeBySubdomainAndName("a.com", "foo", + null, "bogus")); + do_check_throws(() => cps.removeGlobal("", null)); + do_check_throws(() => cps.removeGlobal(null, null)); + do_check_throws(() => cps.removeGlobal("foo", null, "bogus")); yield true; }, diff --git a/toolkit/components/contentprefs/tests/unit_cps2/test_removeAllDomains.js b/toolkit/components/contentprefs/tests/unit_cps2/test_removeAllDomains.js index 1ef1a3be56..9549439d59 100644 --- a/toolkit/components/contentprefs/tests/unit_cps2/test_removeAllDomains.js +++ b/toolkit/components/contentprefs/tests/unit_cps2/test_removeAllDomains.js @@ -67,7 +67,7 @@ let tests = [ }, function erroneous() { - do_check_throws(function () cps.removeAllDomains(null, "bogus")); + do_check_throws(() => cps.removeAllDomains(null, "bogus")); yield true; }, diff --git a/toolkit/components/contentprefs/tests/unit_cps2/test_removeAllDomainsSince.js b/toolkit/components/contentprefs/tests/unit_cps2/test_removeAllDomainsSince.js index b771419989..f6ee6318ca 100644 --- a/toolkit/components/contentprefs/tests/unit_cps2/test_removeAllDomainsSince.js +++ b/toolkit/components/contentprefs/tests/unit_cps2/test_removeAllDomainsSince.js @@ -84,7 +84,7 @@ let tests = [ }, function erroneous() { - do_check_throws(function () cps.removeAllDomainsSince(null, "bogus")); + do_check_throws(() => cps.removeAllDomainsSince(null, "bogus")); yield true; }, diff --git a/toolkit/components/contentprefs/tests/unit_cps2/test_removeByDomain.js b/toolkit/components/contentprefs/tests/unit_cps2/test_removeByDomain.js index c9405f61e1..3c6282db2b 100644 --- a/toolkit/components/contentprefs/tests/unit_cps2/test_removeByDomain.js +++ b/toolkit/components/contentprefs/tests/unit_cps2/test_removeByDomain.js @@ -150,13 +150,13 @@ let tests = [ }, function erroneous() { - do_check_throws(function () cps.removeByDomain(null, null)); - do_check_throws(function () cps.removeByDomain("", null)); - do_check_throws(function () cps.removeByDomain("a.com", null, "bogus")); - do_check_throws(function () cps.removeBySubdomain(null, null)); - do_check_throws(function () cps.removeBySubdomain("", null)); - do_check_throws(function () cps.removeBySubdomain("a.com", null, "bogus")); - do_check_throws(function () cps.removeAllGlobals(null, "bogus")); + do_check_throws(() => cps.removeByDomain(null, null)); + do_check_throws(() => cps.removeByDomain("", null)); + do_check_throws(() => cps.removeByDomain("a.com", null, "bogus")); + do_check_throws(() => cps.removeBySubdomain(null, null)); + do_check_throws(() => cps.removeBySubdomain("", null)); + do_check_throws(() => cps.removeBySubdomain("a.com", null, "bogus")); + do_check_throws(() => cps.removeAllGlobals(null, "bogus")); yield true; }, diff --git a/toolkit/components/contentprefs/tests/unit_cps2/test_removeByName.js b/toolkit/components/contentprefs/tests/unit_cps2/test_removeByName.js index 5dc4878326..5b523aa7c6 100644 --- a/toolkit/components/contentprefs/tests/unit_cps2/test_removeByName.js +++ b/toolkit/components/contentprefs/tests/unit_cps2/test_removeByName.js @@ -77,9 +77,9 @@ let tests = [ }, function erroneous() { - do_check_throws(function () cps.removeByName("", null)); - do_check_throws(function () cps.removeByName(null, null)); - do_check_throws(function () cps.removeByName("foo", null, "bogus")); + do_check_throws(() => cps.removeByName("", null)); + do_check_throws(() => cps.removeByName(null, null)); + do_check_throws(() => cps.removeByName("foo", null, "bogus")); yield true; }, diff --git a/toolkit/components/contentprefs/tests/unit_cps2/test_setGet.js b/toolkit/components/contentprefs/tests/unit_cps2/test_setGet.js index ff2cd49036..0d035a219f 100644 --- a/toolkit/components/contentprefs/tests/unit_cps2/test_setGet.js +++ b/toolkit/components/contentprefs/tests/unit_cps2/test_setGet.js @@ -109,30 +109,28 @@ let tests = [ }, function set_erroneous() { - do_check_throws(function () cps.set(null, "foo", 1, null)); - do_check_throws(function () cps.set("", "foo", 1, null)); - do_check_throws(function () cps.set("a.com", "", 1, null)); - do_check_throws(function () cps.set("a.com", null, 1, null)); - do_check_throws(function () cps.set("a.com", "foo", undefined, null)); - do_check_throws(function () cps.set("a.com", "foo", 1, null, "bogus")); - do_check_throws(function () cps.setGlobal("", 1, null)); - do_check_throws(function () cps.setGlobal(null, 1, null)); - do_check_throws(function () cps.setGlobal("foo", undefined, null)); - do_check_throws(function () cps.setGlobal("foo", 1, null, "bogus")); + do_check_throws(() => cps.set(null, "foo", 1, null)); + do_check_throws(() => cps.set("", "foo", 1, null)); + do_check_throws(() => cps.set("a.com", "", 1, null)); + do_check_throws(() => cps.set("a.com", null, 1, null)); + do_check_throws(() => cps.set("a.com", "foo", undefined, null)); + do_check_throws(() => cps.set("a.com", "foo", 1, null, "bogus")); + do_check_throws(() => cps.setGlobal("", 1, null)); + do_check_throws(() => cps.setGlobal(null, 1, null)); + do_check_throws(() => cps.setGlobal("foo", undefined, null)); + do_check_throws(() => cps.setGlobal("foo", 1, null, "bogus")); yield true; }, function get_erroneous() { - do_check_throws(function () cps.getByDomainAndName(null, "foo", null, {})); - do_check_throws(function () cps.getByDomainAndName("", "foo", null, {})); - do_check_throws(function () cps.getByDomainAndName("a.com", "", null, {})); - do_check_throws(function () - cps.getByDomainAndName("a.com", null, null, {})); - do_check_throws(function () - cps.getByDomainAndName("a.com", "foo", null, null)); - do_check_throws(function () cps.getGlobal("", null, {})); - do_check_throws(function () cps.getGlobal(null, null, {})); - do_check_throws(function () cps.getGlobal("foo", null, null)); + do_check_throws(() => cps.getByDomainAndName(null, "foo", null, {})); + do_check_throws(() => cps.getByDomainAndName("", "foo", null, {})); + do_check_throws(() => cps.getByDomainAndName("a.com", "", null, {})); + do_check_throws(() => cps.getByDomainAndName("a.com", null, null, {})); + do_check_throws(() => cps.getByDomainAndName("a.com", "foo", null, null)); + do_check_throws(() => cps.getGlobal("", null, {})); + do_check_throws(() => cps.getGlobal(null, null, {})); + do_check_throws(() => cps.getGlobal("foo", null, null)); yield true; }, diff --git a/toolkit/components/downloads/test/browser/browser_download_history.js b/toolkit/components/downloads/test/browser/browser_download_history.js index dd21e2fddb..8733d1da48 100644 --- a/toolkit/components/downloads/test/browser/browser_download_history.js +++ b/toolkit/components/downloads/test/browser/browser_download_history.js @@ -95,7 +95,7 @@ function test() { let win = OpenBrowserWindow({private: aIsPrivate}); win.addEventListener("load", function onLoad() { win.removeEventListener("load", onLoad, false); - executeSoon(function() aCallback(win)); + executeSoon(() => aCallback(win)); }, false); } @@ -103,7 +103,7 @@ function test() { let browser = aWin.gBrowser.selectedBrowser; browser.addEventListener("load", function onLoad() { browser.removeEventListener("load", onLoad, true); - executeSoon(function() aCallback(browser.contentDocument)); + executeSoon(() => aCallback(browser.contentDocument)); }, true); browser.loadURI(aURL); } diff --git a/toolkit/components/osfile/tests/xpcshell/test_path.js b/toolkit/components/osfile/tests/xpcshell/test_path.js index 2c76c86186..76a507ee38 100644 --- a/toolkit/components/osfile/tests/xpcshell/test_path.js +++ b/toolkit/components/osfile/tests/xpcshell/test_path.js @@ -44,7 +44,7 @@ function run_test() do_check_eq(Win.normalize("\\a\\b\\c\\\\\\"), "\\a\\b\\c"); do_check_eq(Win.normalize("\\a\\b\\c\\..\\..\\..\\d\\e\\f"), "\\d\\e\\f"); do_check_eq(Win.normalize("a\\b\\c\\..\\..\\..\\d\\e\\f"), "d\\e\\f"); - do_check_fail(function() Win.normalize("\\a\\b\\c\\..\\..\\..\\..\\d\\e\\f")); + do_check_fail(() => Win.normalize("\\a\\b\\c\\..\\..\\..\\..\\d\\e\\f")); do_check_eq(Win.join("\\tmp", "foo", "bar"), "\\tmp\\foo\\bar", "join \\tmp,foo,bar"); do_check_eq(Win.join("\\tmp", "\\foo", "bar"), "\\foo\\bar", "join \\tmp,\\foo,bar"); @@ -78,7 +78,7 @@ function run_test() do_check_eq(Win.normalize("c:\\a\\b\\c\\\\\\"), "c:\\a\\b\\c"); do_check_eq(Win.normalize("c:\\a\\b\\c\\..\\..\\..\\d\\e\\f"), "c:\\d\\e\\f"); do_check_eq(Win.normalize("c:a\\b\\c\\..\\..\\..\\d\\e\\f"), "c:\\d\\e\\f"); - do_check_fail(function() Win.normalize("c:\\a\\b\\c\\..\\..\\..\\..\\d\\e\\f")); + do_check_fail(() => Win.normalize("c:\\a\\b\\c\\..\\..\\..\\..\\d\\e\\f")); do_check_eq(Win.join("c:\\", "foo"), "c:\\foo", "join c:\,foo"); do_check_eq(Win.join("c:\\tmp", "foo", "bar"), "c:\\tmp\\foo\\bar", "join c:\\tmp,foo,bar"); @@ -120,7 +120,7 @@ function run_test() do_check_eq(Win.normalize("\\\\a\\b\\\\\\\\c"), "\\\\a\\b\\c"); do_check_eq(Win.normalize("\\\\a\\b\\c\\\\\\"), "\\\\a\\b\\c"); do_check_eq(Win.normalize("\\\\a\\b\\c\\..\\..\\d\\e\\f"), "\\\\a\\d\\e\\f"); - do_check_fail(function() Win.normalize("\\\\a\\b\\c\\..\\..\\..\\d\\e\\f")); + do_check_fail(() => Win.normalize("\\\\a\\b\\c\\..\\..\\..\\d\\e\\f")); do_check_eq(Win.join("\\\\a\\tmp", "foo", "bar"), "\\\\a\\tmp\\foo\\bar"); do_check_eq(Win.join("\\\\a\\tmp", "\\foo", "bar"), "\\\\a\\foo\\bar"); @@ -143,7 +143,7 @@ function run_test() do_check_eq(Unix.normalize("/a/b/c///"), "/a/b/c"); do_check_eq(Unix.normalize("/a/b/c/../../../d/e/f"), "/d/e/f"); do_check_eq(Unix.normalize("a/b/c/../../../d/e/f"), "d/e/f"); - do_check_fail(function() Unix.normalize("/a/b/c/../../../../d/e/f")); + do_check_fail(() => Unix.normalize("/a/b/c/../../../../d/e/f")); do_check_eq(Unix.join("/tmp", "foo", "bar"), "/tmp/foo/bar", "join /tmp,foo,bar"); do_check_eq(Unix.join("/tmp", "/foo", "bar"), "/foo/bar", "join /tmp,/foo,bar"); diff --git a/toolkit/components/passwordmgr/test/browser/browser_passwordmgrdlg.js b/toolkit/components/passwordmgr/test/browser/browser_passwordmgrdlg.js index a2d7c4dc0b..c669954850 100644 --- a/toolkit/components/passwordmgr/test/browser/browser_passwordmgrdlg.js +++ b/toolkit/components/passwordmgr/test/browser/browser_passwordmgrdlg.js @@ -36,7 +36,7 @@ function test() { new nsLoginInfo(urls[8], urls[8], null, "my user name", "mozilla", "u9", "p9"), new nsLoginInfo(urls[9], urls[9], null, "my username", "mozilla.com", "u10", "p10"), ]; - logins.forEach(function (login) pwmgr.addLogin(login)); + logins.forEach(login => pwmgr.addLogin(login)); // Open the password manager dialog const PWMGR_DLG = "chrome://passwordmgr/content/passwordManager.xul"; diff --git a/toolkit/components/passwordmgr/test/test_zzz_finish.html b/toolkit/components/passwordmgr/test/test_zzz_finish.html index cfa7dd2203..9224f80c0e 100644 --- a/toolkit/components/passwordmgr/test/test_zzz_finish.html +++ b/toolkit/components/passwordmgr/test/test_zzz_finish.html @@ -39,7 +39,7 @@ is(logins.length, 0, "ensure no remaining logins"); // Remove any disabled hosts var disabledHosts = pwmgr.getAllDisabledHosts(); ok(disabledHosts != null, "getAllDisabledHosts()"); -disabledHosts.forEach(function(host) pwmgr.setLoginSavingEnabled(host, true)); +disabledHosts.forEach(host => pwmgr.setLoginSavingEnabled(host, true)); disabledHosts = pwmgr.getAllDisabledHosts(); ok(disabledHosts != null, "getAllDisabledHosts()"); diff --git a/toolkit/components/places/tests/autocomplete/head_autocomplete.js b/toolkit/components/places/tests/autocomplete/head_autocomplete.js index e6e5741919..93470fa76b 100644 --- a/toolkit/components/places/tests/autocomplete/head_autocomplete.js +++ b/toolkit/components/places/tests/autocomplete/head_autocomplete.js @@ -44,7 +44,7 @@ AutoCompleteInput.prototype = { onSearchComplete: function() {}, setSelectedIndex: function() {}, get searchCount() { return this.searches.length; }, - getSearchAt: function(aIndex) this.searches[aIndex], + getSearchAt: function(aIndex) { return this.searches[aIndex]; }, QueryInterface: XPCOMUtils.generateQI([ Ci.nsIAutoCompleteInput, Ci.nsIAutoCompletePopup, @@ -105,7 +105,7 @@ function ensure_results(aSearch, aExpected) uri = toURI(kURIs[uri]).spec; title = kTitles[title]; if (tags && appendTags) - title += " \u2013 " + tags.map(function(aTag) kTitles[aTag]); + title += " \u2013 " + tags.map(aTag => kTitles[aTag]); print("Checking against expected '" + uri + "', '" + title + "'..."); // Got a match on both uri and title? @@ -235,7 +235,7 @@ function task_addPageBook(aURI, aTitle, aBook, aTags, aKey, aTransitionType, aNo // Add tags if we need to if (aTags != undefined && aTags.length > 0) { // Convert each tag index into the title - let tags = aTags.map(function(aTag) kTitles[aTag]); + let tags = aTags.map(aTag => kTitles[aTag]); tagsvc.tagURI(uri, tags); out.push("\ntags=" + tags); } @@ -280,7 +280,7 @@ function run_test() { // should return reliable resultsets, thus we have to wait. yield PlacesTestUtils.promiseAsyncUpdates(); - }).then(function () ensure_results(search, expected), + }).then(() => ensure_results(search, expected), do_report_unexpected_exception); } diff --git a/toolkit/components/places/tests/autocomplete/test_enabled.js b/toolkit/components/places/tests/autocomplete/test_enabled.js index 093d010031..553671a5a4 100644 --- a/toolkit/components/places/tests/autocomplete/test_enabled.js +++ b/toolkit/components/places/tests/autocomplete/test_enabled.js @@ -23,9 +23,9 @@ let gTests = [ ["1: plain search", "url", [0]], ["2: search disabled", - "url", [], function() setSearch(0)], + "url", [], () => setSearch(0)], ["3: resume normal search", - "url", [0], function() setSearch(1)], + "url", [0], () => setSearch(1)], ]; function setSearch(aSearch) { diff --git a/toolkit/components/places/tests/autocomplete/test_match_beginning.js b/toolkit/components/places/tests/autocomplete/test_match_beginning.js index a443c5706e..4e0ac0f71c 100644 --- a/toolkit/components/places/tests/autocomplete/test_match_beginning.js +++ b/toolkit/components/places/tests/autocomplete/test_match_beginning.js @@ -26,7 +26,7 @@ let gTests = [ // Tests after this one will match at the beginning ["0: Match at the beginning of titles", "a", [0], - function() setBehavior(3)], + () => setBehavior(3)], ["1: Match at the beginning of titles", "b", [1]], ["2: Match at the beginning of urls", @@ -37,7 +37,7 @@ let gTests = [ // Tests after this one will match against word boundaries and anywhere ["4: Sanity check that matching anywhere finds more", "a", [0,1], - function() setBehavior(1)], + () => setBehavior(1)], ]; function setBehavior(aType) { diff --git a/toolkit/components/places/tests/autocomplete/test_special_search.js b/toolkit/components/places/tests/autocomplete/test_special_search.js index de092d4138..390a99a644 100644 --- a/toolkit/components/places/tests/autocomplete/test_special_search.js +++ b/toolkit/components/places/tests/autocomplete/test_special_search.js @@ -78,31 +78,31 @@ let gTests = [ ["6.1: foo ^ -> history", "foo ^", [1,2,3,5,10]], ["6.2: foo | -> history (change pref)", - "foo |", [1,2,3,5,10], function() { changeRestrict("history", "|"); }], + "foo |", [1,2,3,5,10], () => changeRestrict("history", "|")], ["7.1: foo * -> is star", - "foo *", [5,6,7,8,9,10,11], function() resetRestrict("history")], + "foo *", [5,6,7,8,9,10,11], () => resetRestrict("history")], ["7.2: foo | -> is star (change pref)", - "foo |", [5,6,7,8,9,10,11], function() changeRestrict("bookmark", "|")], + "foo |", [5,6,7,8,9,10,11], () => changeRestrict("bookmark", "|")], ["8.1: foo # -> in title", - "foo #", [1,3,5,7,8,9,10,11], function() resetRestrict("bookmark")], + "foo #", [1,3,5,7,8,9,10,11], () => resetRestrict("bookmark")], ["8.2: foo | -> in title (change pref)", - "foo |", [1,3,5,7,8,9,10,11], function() changeRestrict("title", "|")], + "foo |", [1,3,5,7,8,9,10,11], () => changeRestrict("title", "|")], ["9.1: foo @ -> in url", - "foo @", [2,3,6,7,10,11], function() resetRestrict("title")], + "foo @", [2,3,6,7,10,11], () => resetRestrict("title")], ["9.2: foo | -> in url (change pref)", - "foo |", [2,3,6,7,10,11], function() changeRestrict("url", "|")], + "foo |", [2,3,6,7,10,11], () => changeRestrict("url", "|")], ["10: foo + -> is tag", - "foo +", [8,9,10,11], function() resetRestrict("url")], + "foo +", [8,9,10,11], () => resetRestrict("url")], ["10.2: foo | -> is tag (change pref)", - "foo |", [8,9,10,11], function() changeRestrict("tag", "|")], + "foo |", [8,9,10,11], () => changeRestrict("tag", "|")], ["10.3: foo ~ -> is typed", - "foo ~", [3,10], function() resetRestrict("tag")], + "foo ~", [3,10], () => resetRestrict("tag")], ["10.4: foo | -> is typed (change pref)", - "foo |", [3,10], function() changeRestrict("typed", "|")], + "foo |", [3,10], () => changeRestrict("typed", "|")], // Test various pairs of special searches ["11: foo ^ * -> history, is star", - "foo ^ *", [5,10], function() resetRestrict("typed")], + "foo ^ *", [5,10], () => resetRestrict("typed")], ["12: foo ^ # -> history, in title", "foo ^ #", [1,3,5,10]], ["13: foo ^ @ -> history, in url", @@ -136,9 +136,9 @@ let gTests = [ ["21: foo -> default history", "foo", [1,2,3,5,10], function () { setPref({ history: true }); }], ["22: foo -> default history or is star", - "foo", [1,2,3,5,6,7,8,9,10,11], function() setPref({ history: true, bookmark: true })], + "foo", [1,2,3,5,6,7,8,9,10,11], () => setPref({ history: true, bookmark: true })], ["22.1: foo -> default history or is star, is typed", - "foo", [3,10], function() setPref({ history: true, bookmark: true, "history.onlyTyped": true })], + "foo", [3,10], () => setPref({ history: true, bookmark: true, "history.onlyTyped": true })], ]; diff --git a/toolkit/components/places/tests/autocomplete/test_word_boundary_search.js b/toolkit/components/places/tests/autocomplete/test_word_boundary_search.js index 191c5f552f..28a2639944 100644 --- a/toolkit/components/places/tests/autocomplete/test_word_boundary_search.js +++ b/toolkit/components/places/tests/autocomplete/test_word_boundary_search.js @@ -63,7 +63,7 @@ let gTests = [ // Tests after this one will match only on word boundaries ["0: Match 'match' at the beginning or after / or on a CamelCase", "match", [0,2,4,9], - function() setBehavior(2)], + () => setBehavior(2)], ["1: Match 'dont' at the beginning or after /", "dont", [1,3,5]], ["2: Match '2' after the slash and after a word (in tags too)", @@ -97,7 +97,7 @@ let gTests = [ // Tests after this one will match against word boundaries and anywhere ["14: Match on word boundaries as well as anywhere (bug 429531)", "tch", [0,1,2,3,4,5,9], - function() setBehavior(1)], + () => setBehavior(1)], ]; function setBehavior(aType) { diff --git a/toolkit/components/places/tests/bookmarks/test_675416.js b/toolkit/components/places/tests/bookmarks/test_675416.js index 15c872c947..08b1c36205 100644 --- a/toolkit/components/places/tests/bookmarks/test_675416.js +++ b/toolkit/components/places/tests/bookmarks/test_675416.js @@ -12,8 +12,8 @@ function run_test() { } let observer = { - onBeginUpdateBatch: function() forceBookmarkCaching(itemId1), - onEndUpdateBatch: function() forceBookmarkCaching(itemId1), + onBeginUpdateBatch: () => forceBookmarkCaching(itemId1), + onEndUpdateBatch: () => forceBookmarkCaching(itemId1), onItemAdded: forceBookmarkCaching, onItemChanged: forceBookmarkCaching, onItemMoved: forceBookmarkCaching, diff --git a/toolkit/components/places/tests/bookmarks/test_711914.js b/toolkit/components/places/tests/bookmarks/test_711914.js index a8ffed641c..2c78b022fe 100644 --- a/toolkit/components/places/tests/bookmarks/test_711914.js +++ b/toolkit/components/places/tests/bookmarks/test_711914.js @@ -14,8 +14,8 @@ function run_test() { } let observer = { - onBeginUpdateBatch: function () forceBookmarkCaching(itemId1), - onEndUpdateBatch: function () forceBookmarkCaching(itemId1), + onBeginUpdateBatch: () => forceBookmarkCaching(itemId1), + onEndUpdateBatch: () => forceBookmarkCaching(itemId1), onItemAdded: forceBookmarkCaching, onItemChanged: forceBookmarkCaching, onItemMoved: forceBookmarkCaching, diff --git a/toolkit/components/places/tests/bookmarks/test_nsINavBookmarkObserver.js b/toolkit/components/places/tests/bookmarks/test_nsINavBookmarkObserver.js index 420709f4e7..d0e2033648 100644 --- a/toolkit/components/places/tests/bookmarks/test_nsINavBookmarkObserver.js +++ b/toolkit/components/places/tests/bookmarks/test_nsINavBookmarkObserver.js @@ -21,20 +21,27 @@ let gBookmarksObserver = { }, // nsINavBookmarkObserver - onBeginUpdateBatch: function onBeginUpdateBatch() - this.validate(arguments.callee.name, arguments), - onEndUpdateBatch: function onEndUpdateBatch() - this.validate(arguments.callee.name, arguments), - onItemAdded: function onItemAdded() - this.validate(arguments.callee.name, arguments), - onItemRemoved: function onItemRemoved() - this.validate(arguments.callee.name, arguments), - onItemChanged: function onItemChanged() - this.validate(arguments.callee.name, arguments), - onItemVisited: function onItemVisited() - this.validate(arguments.callee.name, arguments), - onItemMoved: function onItemMoved() - this.validate(arguments.callee.name, arguments), + onBeginUpdateBatch() { + return this.validate("onBeginUpdateBatch", arguments); + }, + onEndUpdateBatch() { + return this.validate("onEndUpdateBatch", arguments); + }, + onItemAdded() { + return this.validate("onItemAdded", arguments); + }, + onItemRemoved() { + return this.validate("onItemRemoved", arguments); + }, + onItemChanged() { + return this.validate("onItemChanged", arguments); + }, + onItemVisited() { + return this.validate("onItemVisited", arguments); + }, + onItemMoved() { + return this.validate("onItemMoved", arguments); + }, // nsISupports QueryInterface: XPCOMUtils.generateQI([Ci.nsINavBookmarkObserver]), @@ -60,15 +67,15 @@ add_test(function onItemAdded_bookmark() { gBookmarksObserver.expected = [ { name: "onItemAdded", args: [ - { name: "itemId", check: function (v) typeof(v) == "number" && v > 0 }, - { name: "parentId", check: function (v) v === PlacesUtils.unfiledBookmarksFolderId }, - { name: "index", check: function (v) v === 0 }, - { name: "itemType", check: function (v) v === PlacesUtils.bookmarks.TYPE_BOOKMARK }, - { name: "uri", check: function (v) v instanceof Ci.nsIURI && v.equals(uri) }, - { name: "title", check: function (v) v === TITLE }, - { name: "dateAdded", check: function (v) typeof(v) == "number" && v > 0 }, - { name: "guid", check: function (v) typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, - { name: "parentGuid", check: function (v) typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, + { name: "itemId", check: v => typeof(v) == "number" && v > 0 }, + { name: "parentId", check: v => v === PlacesUtils.unfiledBookmarksFolderId }, + { name: "index", check: v => v === 0 }, + { name: "itemType", check: v => v === PlacesUtils.bookmarks.TYPE_BOOKMARK }, + { name: "uri", check: v => v instanceof Ci.nsIURI && v.equals(uri) }, + { name: "title", check: v => v === TITLE }, + { name: "dateAdded", check: v => typeof(v) == "number" && v > 0 }, + { name: "guid", check: v => typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, + { name: "parentGuid", check: v => typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, ] }, ]; PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId, @@ -80,15 +87,15 @@ add_test(function onItemAdded_separator() { gBookmarksObserver.expected = [ { name: "onItemAdded", args: [ - { name: "itemId", check: function (v) typeof(v) == "number" && v > 0 }, - { name: "parentId", check: function (v) v === PlacesUtils.unfiledBookmarksFolderId }, - { name: "index", check: function (v) v === 1 }, - { name: "itemType", check: function (v) v === PlacesUtils.bookmarks.TYPE_SEPARATOR }, - { name: "uri", check: function (v) v === null }, - { name: "title", check: function (v) v === null }, - { name: "dateAdded", check: function (v) typeof(v) == "number" && v > 0 }, - { name: "guid", check: function (v) typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, - { name: "parentGuid", check: function (v) typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, + { name: "itemId", check: v => typeof(v) == "number" && v > 0 }, + { name: "parentId", check: v => v === PlacesUtils.unfiledBookmarksFolderId }, + { name: "index", check: v => v === 1 }, + { name: "itemType", check: v => v === PlacesUtils.bookmarks.TYPE_SEPARATOR }, + { name: "uri", check: v => v === null }, + { name: "title", check: v => v === null }, + { name: "dateAdded", check: v => typeof(v) == "number" && v > 0 }, + { name: "guid", check: v => typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, + { name: "parentGuid", check: v => typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, ] }, ]; PlacesUtils.bookmarks.insertSeparator(PlacesUtils.unfiledBookmarksFolderId, @@ -100,15 +107,15 @@ add_test(function onItemAdded_folder() { gBookmarksObserver.expected = [ { name: "onItemAdded", args: [ - { name: "itemId", check: function (v) typeof(v) == "number" && v > 0 }, - { name: "parentId", check: function (v) v === PlacesUtils.unfiledBookmarksFolderId }, - { name: "index", check: function (v) v === 2 }, - { name: "itemType", check: function (v) v === PlacesUtils.bookmarks.TYPE_FOLDER }, - { name: "uri", check: function (v) v === null }, - { name: "title", check: function (v) v === TITLE }, - { name: "dateAdded", check: function (v) typeof(v) == "number" && v > 0 }, - { name: "guid", check: function (v) typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, - { name: "parentGuid", check: function (v) typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, + { name: "itemId", check: v => typeof(v) == "number" && v > 0 }, + { name: "parentId", check: v => v === PlacesUtils.unfiledBookmarksFolderId }, + { name: "index", check: v => v === 2 }, + { name: "itemType", check: v => v === PlacesUtils.bookmarks.TYPE_FOLDER }, + { name: "uri", check: v => v === null }, + { name: "title", check: v => v === TITLE }, + { name: "dateAdded", check: v => typeof(v) == "number" && v > 0 }, + { name: "guid", check: v => typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, + { name: "parentGuid", check: v => typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, ] }, ]; PlacesUtils.bookmarks.createFolder(PlacesUtils.unfiledBookmarksFolderId, @@ -123,15 +130,16 @@ add_test(function onItemChanged_title_bookmark() { gBookmarksObserver.expected = [ { name: "onItemChanged", // This is an unfortunate effect of bug 653910. args: [ - { name: "itemId", check: function (v) typeof(v) == "number" && v > 0 }, - { name: "property", check: function (v) v === "title" }, - { name: "isAnno", check: function (v) v === false }, - { name: "newValue", check: function (v) v === TITLE }, - { name: "lastModified", check: function (v) typeof(v) == "number" && v > 0 }, - { name: "itemType", check: function (v) v === PlacesUtils.bookmarks.TYPE_BOOKMARK }, - { name: "parentId", check: function (v) v === PlacesUtils.unfiledBookmarksFolderId }, - { name: "guid", check: function (v) typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, - { name: "parentGuid", check: function (v) typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, + { name: "itemId", check: v => typeof(v) == "number" && v > 0 }, + { name: "property", check: v => v === "title" }, + { name: "isAnno", check: v => v === false }, + { name: "newValue", check: v => v === TITLE }, + { name: "lastModified", check: v => typeof(v) == "number" && v > 0 }, + { name: "itemType", check: v => v === PlacesUtils.bookmarks.TYPE_BOOKMARK }, + { name: "parentId", check: v => v === PlacesUtils.unfiledBookmarksFolderId }, + { name: "guid", check: v => typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, + { name: "parentGuid", check: v => typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, + { name: "oldValue", check: v => typeof(v) == "string" }, ] }, ]; PlacesUtils.bookmarks.setItemTitle(id, TITLE); @@ -145,71 +153,73 @@ add_test(function onItemChanged_tags_bookmark() { gBookmarksObserver.expected = [ { name: "onItemAdded", // This is the tag folder. args: [ - { name: "itemId", check: function (v) typeof(v) == "number" && v > 0 }, - { name: "parentId", check: function (v) v === PlacesUtils.tagsFolderId }, - { name: "index", check: function (v) v === 0 }, - { name: "itemType", check: function (v) v === PlacesUtils.bookmarks.TYPE_FOLDER }, - { name: "uri", check: function (v) v === null }, - { name: "title", check: function (v) v === TAG }, - { name: "dateAdded", check: function (v) typeof(v) == "number" && v > 0 }, - { name: "guid", check: function (v) typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, - { name: "parentGuid", check: function (v) typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, + { name: "itemId", check: v => typeof(v) == "number" && v > 0 }, + { name: "parentId", check: v => v === PlacesUtils.tagsFolderId }, + { name: "index", check: v => v === 0 }, + { name: "itemType", check: v => v === PlacesUtils.bookmarks.TYPE_FOLDER }, + { name: "uri", check: v => v === null }, + { name: "title", check: v => v === TAG }, + { name: "dateAdded", check: v => typeof(v) == "number" && v > 0 }, + { name: "guid", check: v => typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, + { name: "parentGuid", check: v => typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, ] }, { name: "onItemAdded", // This is the tag. args: [ - { name: "itemId", check: function (v) typeof(v) == "number" && v > 0 }, - { name: "parentId", check: function (v) typeof(v) == "number" && v > 0 }, - { name: "index", check: function (v) v === 0 }, - { name: "itemType", check: function (v) v === PlacesUtils.bookmarks.TYPE_BOOKMARK }, - { name: "uri", check: function (v) v instanceof Ci.nsIURI && v.equals(uri) }, - { name: "title", check: function (v) v === null }, - { name: "dateAdded", check: function (v) typeof(v) == "number" && v > 0 }, - { name: "guid", check: function (v) typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, - { name: "parentGuid", check: function (v) typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, + { name: "itemId", check: v => typeof(v) == "number" && v > 0 }, + { name: "parentId", check: v => typeof(v) == "number" && v > 0 }, + { name: "index", check: v => v === 0 }, + { name: "itemType", check: v => v === PlacesUtils.bookmarks.TYPE_BOOKMARK }, + { name: "uri", check: v => v instanceof Ci.nsIURI && v.equals(uri) }, + { name: "title", check: v => v === null }, + { name: "dateAdded", check: v => typeof(v) == "number" && v > 0 }, + { name: "guid", check: v => typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, + { name: "parentGuid", check: v => typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, ] }, { name: "onItemChanged", args: [ - { name: "itemId", check: function (v) typeof(v) == "number" && v > 0 }, - { name: "property", check: function (v) v === "tags" }, - { name: "isAnno", check: function (v) v === false }, - { name: "newValue", check: function (v) v === "" }, - { name: "lastModified", check: function (v) typeof(v) == "number" && v > 0 }, - { name: "itemType", check: function (v) v === PlacesUtils.bookmarks.TYPE_BOOKMARK }, - { name: "parentId", check: function (v) v === PlacesUtils.unfiledBookmarksFolderId }, - { name: "guid", check: function (v) typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, - { name: "parentGuid", check: function (v) typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, + { name: "itemId", check: v => typeof(v) == "number" && v > 0 }, + { name: "property", check: v => v === "tags" }, + { name: "isAnno", check: v => v === false }, + { name: "newValue", check: v => v === "" }, + { name: "lastModified", check: v => typeof(v) == "number" && v > 0 }, + { name: "itemType", check: v => v === PlacesUtils.bookmarks.TYPE_BOOKMARK }, + { name: "parentId", check: v => v === PlacesUtils.unfiledBookmarksFolderId }, + { name: "guid", check: v => typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, + { name: "parentGuid", check: v => typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, + { name: "oldValue", check: v => typeof(v) == "string" }, ] }, { name: "onItemRemoved", // This is the tag. args: [ - { name: "itemId", check: function (v) typeof(v) == "number" && v > 0 }, - { name: "parentId", check: function (v) typeof(v) == "number" && v > 0 }, - { name: "index", check: function (v) v === 0 }, - { name: "itemType", check: function (v) v === PlacesUtils.bookmarks.TYPE_BOOKMARK }, - { name: "uri", check: function (v) v instanceof Ci.nsIURI && v.equals(uri) }, - { name: "guid", check: function (v) typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, - { name: "parentGuid", check: function (v) typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, + { name: "itemId", check: v => typeof(v) == "number" && v > 0 }, + { name: "parentId", check: v => typeof(v) == "number" && v > 0 }, + { name: "index", check: v => v === 0 }, + { name: "itemType", check: v => v === PlacesUtils.bookmarks.TYPE_BOOKMARK }, + { name: "uri", check: v => v instanceof Ci.nsIURI && v.equals(uri) }, + { name: "guid", check: v => typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, + { name: "parentGuid", check: v => typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, ] }, { name: "onItemRemoved", // This is the tag folder. args: [ - { name: "itemId", check: function (v) typeof(v) == "number" && v > 0 }, - { name: "parentId", check: function (v) v === PlacesUtils.tagsFolderId }, - { name: "index", check: function (v) v === 0 }, - { name: "itemType", check: function (v) v === PlacesUtils.bookmarks.TYPE_FOLDER }, - { name: "uri", check: function (v) v === null }, - { name: "guid", check: function (v) typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, - { name: "parentGuid", check: function (v) typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, + { name: "itemId", check: v => typeof(v) == "number" && v > 0 }, + { name: "parentId", check: v => v === PlacesUtils.tagsFolderId }, + { name: "index", check: v => v === 0 }, + { name: "itemType", check: v => v === PlacesUtils.bookmarks.TYPE_FOLDER }, + { name: "uri", check: v => v === null }, + { name: "guid", check: v => typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, + { name: "parentGuid", check: v => typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, ] }, { name: "onItemChanged", args: [ - { name: "itemId", check: function (v) typeof(v) == "number" && v > 0 }, - { name: "property", check: function (v) v === "tags" }, - { name: "isAnno", check: function (v) v === false }, - { name: "newValue", check: function (v) v === "" }, - { name: "lastModified", check: function (v) typeof(v) == "number" && v > 0 }, - { name: "itemType", check: function (v) v === PlacesUtils.bookmarks.TYPE_BOOKMARK }, - { name: "parentId", check: function (v) v === PlacesUtils.unfiledBookmarksFolderId }, - { name: "guid", check: function (v) typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, - { name: "parentGuid", check: function (v) typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, + { name: "itemId", check: v => typeof(v) == "number" && v > 0 }, + { name: "property", check: v => v === "tags" }, + { name: "isAnno", check: v => v === false }, + { name: "newValue", check: v => v === "" }, + { name: "lastModified", check: v => typeof(v) == "number" && v > 0 }, + { name: "itemType", check: v => v === PlacesUtils.bookmarks.TYPE_BOOKMARK }, + { name: "parentId", check: v => v === PlacesUtils.unfiledBookmarksFolderId }, + { name: "guid", check: v => typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, + { name: "parentGuid", check: v => typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, + { name: "oldValue", check: v => typeof(v) == "string" }, ] }, ]; PlacesUtils.tagging.tagURI(uri, [TAG]); @@ -222,27 +232,27 @@ add_test(function onItemMoved_bookmark() { gBookmarksObserver.expected = [ { name: "onItemMoved", args: [ - { name: "itemId", check: function (v) typeof(v) == "number" && v > 0 }, - { name: "oldParentId", check: function (v) v === PlacesUtils.unfiledBookmarksFolderId }, - { name: "oldIndex", check: function (v) v === 0 }, - { name: "newParentId", check: function (v) v === PlacesUtils.toolbarFolderId }, - { name: "newIndex", check: function (v) v === 0 }, - { name: "itemType", check: function (v) v === PlacesUtils.bookmarks.TYPE_BOOKMARK }, - { name: "guid", check: function (v) typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, - { name: "oldParentGuid", check: function (v) typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, - { name: "newParentGuid", check: function (v) typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, + { name: "itemId", check: v => typeof(v) == "number" && v > 0 }, + { name: "oldParentId", check: v => v === PlacesUtils.unfiledBookmarksFolderId }, + { name: "oldIndex", check: v => v === 0 }, + { name: "newParentId", check: v => v === PlacesUtils.toolbarFolderId }, + { name: "newIndex", check: v => v === 0 }, + { name: "itemType", check: v => v === PlacesUtils.bookmarks.TYPE_BOOKMARK }, + { name: "guid", check: v => typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, + { name: "oldParentGuid", check: v => typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, + { name: "newParentGuid", check: v => typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, ] }, { name: "onItemMoved", args: [ - { name: "itemId", check: function (v) typeof(v) == "number" && v > 0 }, - { name: "oldParentId", check: function (v) v === PlacesUtils.toolbarFolderId }, - { name: "oldIndex", check: function (v) v === 0 }, - { name: "newParentId", check: function (v) v === PlacesUtils.unfiledBookmarksFolderId }, - { name: "newIndex", check: function (v) v === 0 }, - { name: "itemType", check: function (v) v === PlacesUtils.bookmarks.TYPE_BOOKMARK }, - { name: "guid", check: function (v) typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, - { name: "oldParentGuid", check: function (v) typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, - { name: "newParentGuid", check: function (v) typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, + { name: "itemId", check: v => typeof(v) == "number" && v > 0 }, + { name: "oldParentId", check: v => v === PlacesUtils.toolbarFolderId }, + { name: "oldIndex", check: v => v === 0 }, + { name: "newParentId", check: v => v === PlacesUtils.unfiledBookmarksFolderId }, + { name: "newIndex", check: v => v === 0 }, + { name: "itemType", check: v => v === PlacesUtils.bookmarks.TYPE_BOOKMARK }, + { name: "guid", check: v => typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, + { name: "oldParentGuid", check: v => typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, + { name: "newParentGuid", check: v => typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, ] }, ]; PlacesUtils.bookmarks.moveItem(id, PlacesUtils.toolbarFolderId, 0); @@ -255,14 +265,14 @@ add_test(function onItemMoved_bookmark() { gBookmarksObserver.expected = [ { name: "onItemVisited", args: [ - { name: "itemId", check: function (v) typeof(v) == "number" && v > 0 }, - { name: "visitId", check: function (v) typeof(v) == "number" && v > 0 }, - { name: "time", check: function (v) typeof(v) == "number" && v > 0 }, - { name: "transitionType", check: function (v) v === PlacesUtils.history.TRANSITION_TYPED }, - { name: "uri", check: function (v) v instanceof Ci.nsIURI && v.equals(uri) }, - { name: "parentId", check: function (v) v === PlacesUtils.unfiledBookmarksFolderId }, - { name: "guid", check: function (v) typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, - { name: "parentGuid", check: function (v) typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, + { name: "itemId", check: v => typeof(v) == "number" && v > 0 }, + { name: "visitId", check: v => typeof(v) == "number" && v > 0 }, + { name: "time", check: v => typeof(v) == "number" && v > 0 }, + { name: "transitionType", check: v => v === PlacesUtils.history.TRANSITION_TYPED }, + { name: "uri", check: v => v instanceof Ci.nsIURI && v.equals(uri) }, + { name: "parentId", check: v => v === PlacesUtils.unfiledBookmarksFolderId }, + { name: "guid", check: v => typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, + { name: "parentGuid", check: v => typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, ] }, ]; PlacesTestUtils.addVisits({ uri: uri, transition: TRANSITION_TYPED }); @@ -274,25 +284,26 @@ add_test(function onItemRemoved_bookmark() { gBookmarksObserver.expected = [ { name: "onItemChanged", // This is an unfortunate effect of bug 653910. args: [ - { name: "itemId", check: function (v) typeof(v) == "number" && v > 0 }, - { name: "property", check: function (v) v === "" }, - { name: "isAnno", check: function (v) v === true }, - { name: "newValue", check: function (v) v === "" }, - { name: "lastModified", check: function (v) typeof(v) == "number" && v > 0 }, - { name: "itemType", check: function (v) v === PlacesUtils.bookmarks.TYPE_BOOKMARK }, - { name: "parentId", check: function (v) v === PlacesUtils.unfiledBookmarksFolderId }, - { name: "guid", check: function (v) typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, - { name: "parentGuid", check: function (v) typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, + { name: "itemId", check: v => typeof(v) == "number" && v > 0 }, + { name: "property", check: v => v === "" }, + { name: "isAnno", check: v => v === true }, + { name: "newValue", check: v => v === "" }, + { name: "lastModified", check: v => typeof(v) == "number" && v > 0 }, + { name: "itemType", check: v => v === PlacesUtils.bookmarks.TYPE_BOOKMARK }, + { name: "parentId", check: v => v === PlacesUtils.unfiledBookmarksFolderId }, + { name: "guid", check: v => typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, + { name: "parentGuid", check: v => typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, + { name: "oldValue", check: v => typeof(v) == "string" }, ] }, { name: "onItemRemoved", args: [ - { name: "itemId", check: function (v) typeof(v) == "number" && v > 0 }, - { name: "parentId", check: function (v) v === PlacesUtils.unfiledBookmarksFolderId }, - { name: "index", check: function (v) v === 0 }, - { name: "itemType", check: function (v) v === PlacesUtils.bookmarks.TYPE_BOOKMARK }, - { name: "uri", check: function (v) v instanceof Ci.nsIURI && v.equals(uri) }, - { name: "guid", check: function (v) typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, - { name: "parentGuid", check: function (v) typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, + { name: "itemId", check: v => typeof(v) == "number" && v > 0 }, + { name: "parentId", check: v => v === PlacesUtils.unfiledBookmarksFolderId }, + { name: "index", check: v => v === 0 }, + { name: "itemType", check: v => v === PlacesUtils.bookmarks.TYPE_BOOKMARK }, + { name: "uri", check: v => v instanceof Ci.nsIURI && v.equals(uri) }, + { name: "guid", check: v => typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, + { name: "parentGuid", check: v => typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, ] }, ]; PlacesUtils.bookmarks.removeItem(id); @@ -303,25 +314,26 @@ add_test(function onItemRemoved_separator() { gBookmarksObserver.expected = [ { name: "onItemChanged", // This is an unfortunate effect of bug 653910. args: [ - { name: "itemId", check: function (v) typeof(v) == "number" && v > 0 }, - { name: "property", check: function (v) v === "" }, - { name: "isAnno", check: function (v) v === true }, - { name: "newValue", check: function (v) v === "" }, - { name: "lastModified", check: function (v) typeof(v) == "number" && v > 0 }, - { name: "itemType", check: function (v) v === PlacesUtils.bookmarks.TYPE_SEPARATOR }, - { name: "parentId", check: function (v) typeof(v) == "number" && v > 0 }, - { name: "guid", check: function (v) typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, - { name: "parentGuid", check: function (v) typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, + { name: "itemId", check: v => typeof(v) == "number" && v > 0 }, + { name: "property", check: v => v === "" }, + { name: "isAnno", check: v => v === true }, + { name: "newValue", check: v => v === "" }, + { name: "lastModified", check: v => typeof(v) == "number" && v > 0 }, + { name: "itemType", check: v => v === PlacesUtils.bookmarks.TYPE_SEPARATOR }, + { name: "parentId", check: v => typeof(v) == "number" && v > 0 }, + { name: "guid", check: v => typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, + { name: "parentGuid", check: v => typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, + { name: "oldValue", check: v => typeof(v) == "string" }, ] }, { name: "onItemRemoved", args: [ - { name: "itemId", check: function (v) typeof(v) == "number" && v > 0 }, - { name: "parentId", check: function (v) typeof(v) == "number" && v > 0 }, - { name: "index", check: function (v) v === 0 }, - { name: "itemType", check: function (v) v === PlacesUtils.bookmarks.TYPE_SEPARATOR }, - { name: "uri", check: function (v) v === null }, - { name: "guid", check: function (v) typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, - { name: "parentGuid", check: function (v) typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, + { name: "itemId", check: v => typeof(v) == "number" && v > 0 }, + { name: "parentId", check: v => typeof(v) == "number" && v > 0 }, + { name: "index", check: v => v === 0 }, + { name: "itemType", check: v => v === PlacesUtils.bookmarks.TYPE_SEPARATOR }, + { name: "uri", check: v => v === null }, + { name: "guid", check: v => typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, + { name: "parentGuid", check: v => typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, ] }, ]; PlacesUtils.bookmarks.removeItem(id); @@ -333,25 +345,26 @@ add_test(function onItemRemoved_folder() { gBookmarksObserver.expected = [ { name: "onItemChanged", // This is an unfortunate effect of bug 653910. args: [ - { name: "itemId", check: function (v) typeof(v) == "number" && v > 0 }, - { name: "property", check: function (v) v === "" }, - { name: "isAnno", check: function (v) v === true }, - { name: "newValue", check: function (v) v === "" }, - { name: "lastModified", check: function (v) typeof(v) == "number" && v > 0 }, - { name: "itemType", check: function (v) v === PlacesUtils.bookmarks.TYPE_FOLDER }, - { name: "parentId", check: function (v) typeof(v) == "number" && v > 0 }, - { name: "guid", check: function (v) typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, - { name: "parentGuid", check: function (v) typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, + { name: "itemId", check: v => typeof(v) == "number" && v > 0 }, + { name: "property", check: v => v === "" }, + { name: "isAnno", check: v => v === true }, + { name: "newValue", check: v => v === "" }, + { name: "lastModified", check: v => typeof(v) == "number" && v > 0 }, + { name: "itemType", check: v => v === PlacesUtils.bookmarks.TYPE_FOLDER }, + { name: "parentId", check: v => typeof(v) == "number" && v > 0 }, + { name: "guid", check: v => typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, + { name: "parentGuid", check: v => typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, + { name: "oldValue", check: v => typeof(v) == "string" }, ] }, { name: "onItemRemoved", args: [ - { name: "itemId", check: function (v) typeof(v) == "number" && v > 0 }, - { name: "parentId", check: function (v) typeof(v) == "number" && v > 0 }, - { name: "index", check: function (v) v === 0 }, - { name: "itemType", check: function (v) v === PlacesUtils.bookmarks.TYPE_FOLDER }, - { name: "uri", check: function (v) v === null }, - { name: "guid", check: function (v) typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, - { name: "parentGuid", check: function (v) typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, + { name: "itemId", check: v => typeof(v) == "number" && v > 0 }, + { name: "parentId", check: v => typeof(v) == "number" && v > 0 }, + { name: "index", check: v => v === 0 }, + { name: "itemType", check: v => v === PlacesUtils.bookmarks.TYPE_FOLDER }, + { name: "uri", check: v => v === null }, + { name: "guid", check: v => typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, + { name: "parentGuid", check: v => typeof(v) == "string" && /^[a-zA-Z0-9\-_]{12}$/.test(v) }, ] }, ]; PlacesUtils.bookmarks.removeItem(id); diff --git a/toolkit/components/places/tests/browser/browser_favicon_privatebrowsing_perwindowpb.js b/toolkit/components/places/tests/browser/browser_favicon_privatebrowsing_perwindowpb.js index f4faba74c9..1dcb7d1856 100644 --- a/toolkit/components/places/tests/browser/browser_favicon_privatebrowsing_perwindowpb.js +++ b/toolkit/components/places/tests/browser/browser_favicon_privatebrowsing_perwindowpb.js @@ -18,7 +18,7 @@ function test() { function testOnWindow(aIsPrivate, aCallback) { whenNewWindowLoaded({private: aIsPrivate}, function(aWin) { windowsToClose.push(aWin); - executeSoon(function() aCallback(aWin)); + executeSoon(() => aCallback(aWin)); }); }; diff --git a/toolkit/components/places/tests/browser/browser_favicon_setAndFetchFaviconForPage.js b/toolkit/components/places/tests/browser/browser_favicon_setAndFetchFaviconForPage.js index 7e5e618338..04dbeff193 100644 --- a/toolkit/components/places/tests/browser/browser_favicon_setAndFetchFaviconForPage.js +++ b/toolkit/components/places/tests/browser/browser_favicon_setAndFetchFaviconForPage.js @@ -18,7 +18,7 @@ function test() { function testOnWindow(aOptions, aCallback) { whenNewWindowLoaded(aOptions, function(aWin) { windowsToClose.push(aWin); - executeSoon(function() aCallback(aWin)); + executeSoon(() => aCallback(aWin)); }); }; diff --git a/toolkit/components/places/tests/browser/browser_favicon_setAndFetchFaviconForPage_failures.js b/toolkit/components/places/tests/browser/browser_favicon_setAndFetchFaviconForPage_failures.js index 979d384a12..d42b60ceb6 100644 --- a/toolkit/components/places/tests/browser/browser_favicon_setAndFetchFaviconForPage_failures.js +++ b/toolkit/components/places/tests/browser/browser_favicon_setAndFetchFaviconForPage_failures.js @@ -27,7 +27,7 @@ function test() { function testOnWindow(aOptions, aCallback) { whenNewWindowLoaded(aOptions, function(aWin) { windowsToClose.push(aWin); - executeSoon(function() aCallback(aWin)); + executeSoon(() => aCallback(aWin)); }); }; diff --git a/toolkit/components/places/tests/browser/browser_visituri_privatebrowsing_perwindowpb.js b/toolkit/components/places/tests/browser/browser_visituri_privatebrowsing_perwindowpb.js index 3f991c3283..8c4998e86e 100644 --- a/toolkit/components/places/tests/browser/browser_visituri_privatebrowsing_perwindowpb.js +++ b/toolkit/components/places/tests/browser/browser_visituri_privatebrowsing_perwindowpb.js @@ -59,7 +59,7 @@ function test() { // execute should only be called when need, like when you are opening // web pages on the test. If calling executeSoon() is not necesary, then // call whenNewWindowLoaded() instead of testOnWindow() on your test. - executeSoon(function() aCallback(aWin)); + executeSoon(() => aCallback(aWin)); }); }; diff --git a/toolkit/components/places/tests/head_common.js b/toolkit/components/places/tests/head_common.js index c8fd1463dc..a96a695f06 100644 --- a/toolkit/components/places/tests/head_common.js +++ b/toolkit/components/places/tests/head_common.js @@ -88,7 +88,9 @@ clearDB(); * @param aSpec * URLString of the uri. */ -function uri(aSpec) NetUtil.newURI(aSpec); +function uri(aSpec) { + return NetUtil.newURI(aSpec); +} /** diff --git a/toolkit/components/places/tests/inline/head_autocomplete.js b/toolkit/components/places/tests/inline/head_autocomplete.js index a0a8706547..48d73f9ed2 100644 --- a/toolkit/components/places/tests/inline/head_autocomplete.js +++ b/toolkit/components/places/tests/inline/head_autocomplete.js @@ -54,8 +54,8 @@ AutoCompleteInput.prototype = { this._selEnd = aEnd; }, - onTextEntered: function() false, - onTextReverted: function() false, + onTextEntered: () => false, + onTextReverted: () => false, get searchCount() { return this.searches.length; diff --git a/toolkit/components/places/tests/queries/test_containersQueries_sorting.js b/toolkit/components/places/tests/queries/test_containersQueries_sorting.js index aad7bcbc63..2e8ac2c14f 100644 --- a/toolkit/components/places/tests/queries/test_containersQueries_sorting.js +++ b/toolkit/components/places/tests/queries/test_containersQueries_sorting.js @@ -95,7 +95,7 @@ function cartProd(aSequences, aCallback) // For each sequence in aSequences, we maintain a pointer (an array index, // really) to the element we're currently enumerating in that sequence - var seqEltPtrs = aSequences.map(function (i) 0); + var seqEltPtrs = aSequences.map(i => 0); var numProds = 0; var done = false; @@ -396,7 +396,7 @@ add_task(function test_containersQueries_sorting() var visitCount = 0; var dayOffset = 0; var visits = []; - pages.forEach(function (aPageUrl) visits.push( + pages.forEach(aPageUrl => visits.push( { isVisit: true, isBookmark: true, transType: Ci.nsINavHistoryService.TRANSITION_TYPED, diff --git a/toolkit/components/places/tests/queries/test_querySerialization.js b/toolkit/components/places/tests/queries/test_querySerialization.js index 8aab959f65..a728a29bd7 100644 --- a/toolkit/components/places/tests/queries/test_querySerialization.js +++ b/toolkit/components/places/tests/queries/test_querySerialization.js @@ -503,7 +503,7 @@ function cartProd(aSequences, aCallback) // For each sequence in aSequences, we maintain a pointer (an array index, // really) to the element we're currently enumerating in that sequence - var seqEltPtrs = aSequences.map(function (i) 0); + var seqEltPtrs = aSequences.map(i => 0); var numProds = 0; var done = false; @@ -574,7 +574,7 @@ function choose(aSet, aHowMany, aCallback) var done = false; while (!done) { numFound++; - aCallback(ptrs.map(function (p) aSet[p])); + aCallback(ptrs.map(p => aSet[p])); // The next subset to be chosen differs from the current one by just a // single element. Determine which element that is. Advance the "rightmost" diff --git a/toolkit/components/places/tests/queries/test_redirects.js b/toolkit/components/places/tests/queries/test_redirects.js index 597de8e4b9..9ba8e5e6ab 100644 --- a/toolkit/components/places/tests/queries/test_redirects.js +++ b/toolkit/components/places/tests/queries/test_redirects.js @@ -133,7 +133,7 @@ function cartProd(aSequences, aCallback) // For each sequence in aSequences, we maintain a pointer (an array index, // really) to the element we're currently enumerating in that sequence - let seqEltPtrs = aSequences.map(function (i) 0); + let seqEltPtrs = aSequences.map(i => 0); let numProds = 0; let done = false; @@ -210,7 +210,7 @@ add_task(function test_add_visits_to_database() ]; // we add a visit for each of the above transition types. - t.forEach(function (transition) visits.push( + t.forEach(transition => visits.push( { isVisit: true, transType: transition, uri: "http://" + transition + ".example.com/", @@ -222,7 +222,7 @@ add_task(function test_add_visits_to_database() isInQuery: true })); // Add a REDIRECT_TEMPORARY layer of visits for each of the above visits. - t.forEach(function (transition) visits.push( + t.forEach(transition => visits.push( { isVisit: true, transType: Ci.nsINavHistoryService.TRANSITION_REDIRECT_TEMPORARY, uri: "http://" + transition + ".redirect.temp.example.com/", @@ -234,7 +234,7 @@ add_task(function test_add_visits_to_database() isInQuery: true })); // Add a REDIRECT_PERMANENT layer of visits for each of the above redirects. - t.forEach(function (transition) visits.push( + t.forEach(transition => visits.push( { isVisit: true, transType: Ci.nsINavHistoryService.TRANSITION_REDIRECT_PERMANENT, uri: "http://" + transition + ".redirect.perm.example.com/", @@ -257,7 +257,7 @@ add_task(function test_add_visits_to_database() do_throw("Unknown uri."); return null; } - t.forEach(function (transition) visits.push( + t.forEach(transition => visits.push( { isVisit: true, transType: Ci.nsINavHistoryService.TRANSITION_REDIRECT_PERMANENT, uri: "http://" + transition + ".example.com/", diff --git a/toolkit/components/places/tests/queries/test_sort-date-site-grouping.js b/toolkit/components/places/tests/queries/test_sort-date-site-grouping.js index 669b0a6e70..8164ac2aaf 100644 --- a/toolkit/components/places/tests/queries/test_sort-date-site-grouping.js +++ b/toolkit/components/places/tests/queries/test_sort-date-site-grouping.js @@ -162,7 +162,7 @@ add_task(function test_sort_date_site_grouping() testData.push(visit); leveledTestData[i][j].push(oldLength); compareArrayToResult(leveledTestData[i][j]. - map(function(x) testData[x]), roots[i][j]); + map(x => testData[x]), roots[i][j]); }); for (let i = 0; i < roots.length; i++) { @@ -219,7 +219,7 @@ function checkSecondLevel(index, secondIndex, child, roots) { // results. root.containerOpen = true; compareArrayToResult(leveledTestData[index][secondIndex]. - map(function(x) testData[x]), root); + map(x => testData[x]), root); // We close |root|'s container later so that we can test live // updates into it. } diff --git a/toolkit/components/places/tests/queries/test_tags.js b/toolkit/components/places/tests/queries/test_tags.js index b3227ee6ec..2871cc405a 100644 --- a/toolkit/components/places/tests/queries/test_tags.js +++ b/toolkit/components/places/tests/queries/test_tags.js @@ -590,7 +590,7 @@ function task_cleanDatabase(aCallback) { * The query's tagsAreNot property will be set to this */ function checkQueryURI(aTags, aTagsAreNot) { - var pairs = (aTags || []).sort().map(function (t) QUERY_KEY_TAG + "=" + encodeTag(t)); + var pairs = (aTags || []).sort().map(t => QUERY_KEY_TAG + "=" + encodeTag(t)); if (aTagsAreNot) pairs.push(QUERY_KEY_NOT_TAGS + "=1"); var expURI = "place:" + pairs.join("&"); @@ -649,7 +649,7 @@ function task_doWithVisit(aTags, aCallback) { function encodeTag(aTag) { return encodeURIComponent(aTag). replace(/[-_.!~*'()]/g, //' - function (s) "%" + s.charCodeAt(0).toString(16)); + s => "%" + s.charCodeAt(0).toString(16)); } /** @@ -757,8 +757,8 @@ function setsAreEqual(aArr1, aArr2, aIsOrdered) { } } else { - aArr1.forEach(function (u) do_check_true(aArr2.indexOf(u) >= 0)); - aArr2.forEach(function (u) do_check_true(aArr1.indexOf(u) >= 0)); + aArr1.forEach(u => do_check_true(aArr2.indexOf(u) >= 0)); + aArr2.forEach(u => do_check_true(aArr1.indexOf(u) >= 0)); } } diff --git a/toolkit/components/places/tests/test_bug_461710_perwindowpb.html b/toolkit/components/places/tests/test_bug_461710_perwindowpb.html index 7075eaf2a6..2fe946d11e 100644 --- a/toolkit/components/places/tests/test_bug_461710_perwindowpb.html +++ b/toolkit/components/places/tests/test_bug_461710_perwindowpb.html @@ -97,7 +97,7 @@ function loadNextTest() { else observer.expectURL(prefix + subtests[0]); - waitForTrue(function() observer.resolved, function() { + waitForTrue(() => observer.resolved, function() { // And the nodes get notified after the "link-visited" topic, so // we need to execute soon... SimpleTest.executeSoon(handleLoad); diff --git a/toolkit/components/places/tests/unifiedcomplete/head_autocomplete.js b/toolkit/components/places/tests/unifiedcomplete/head_autocomplete.js index 562c254211..734a592422 100644 --- a/toolkit/components/places/tests/unifiedcomplete/head_autocomplete.js +++ b/toolkit/components/places/tests/unifiedcomplete/head_autocomplete.js @@ -91,8 +91,8 @@ AutoCompleteInput.prototype = { onSearchBegin: function () {}, onSearchComplete: function () {}, - onTextEntered: function() false, - onTextReverted: function() false, + onTextEntered: () => false, + onTextReverted: () => false, QueryInterface: XPCOMUtils.generateQI([Ci.nsIAutoCompleteInput]) } diff --git a/toolkit/components/places/tests/unit/test_000_frecency.js b/toolkit/components/places/tests/unit/test_000_frecency.js index 5039b71591..a58e9089d9 100644 --- a/toolkit/components/places/tests/unit/test_000_frecency.js +++ b/toolkit/components/places/tests/unit/test_000_frecency.js @@ -209,7 +209,7 @@ add_task(function test_frecency() } // sort results by frecency - results.sort(function(a,b) b[1] - a[1]); + results.sort((a,b) => b[1] - a[1]); // Make sure there's enough results returned prefs.setIntPref("browser.urlbar.maxRichResults", results.length); @@ -258,7 +258,7 @@ add_task(function test_frecency() // frecency just in the wrong "order" (order of same frecency is // undefined), so check if frecency matches. This is okay because we // can still ensure the correct number of expected frecencies. - let getFrecency = function(aURL) aURL.match(/frecency:(-?\d+)$/)[1]; + let getFrecency = aURL => aURL.match(/frecency:(-?\d+)$/)[1]; print("### checking for same frecency between '" + searchURL + "' and '" + expectURL + "'"); do_check_eq(getFrecency(searchURL), getFrecency(expectURL)); diff --git a/toolkit/components/places/tests/unit/test_408221.js b/toolkit/components/places/tests/unit/test_408221.js index 6bcd196761..235268cc22 100644 --- a/toolkit/components/places/tests/unit/test_408221.js +++ b/toolkit/components/places/tests/unit/test_408221.js @@ -98,7 +98,7 @@ function ensure_tag_results(uris, searchTerm) do_check_eq(controller.getStyleAt(i), "tag"); } // Sort the results then check if we have the right items - vals.sort().forEach(function(val, i) do_check_eq(val, uris[i].spec)) + vals.sort().forEach((val, i) => do_check_eq(val, uris[i].spec)) if (current_test < (tests.length - 1)) { current_test++; diff --git a/toolkit/components/places/tests/unit/test_adaptive.js b/toolkit/components/places/tests/unit/test_adaptive.js index 3b7de550c7..3961c5fb74 100644 --- a/toolkit/components/places/tests/unit/test_adaptive.js +++ b/toolkit/components/places/tests/unit/test_adaptive.js @@ -24,22 +24,40 @@ function AutoCompleteInput(aSearches) { AutoCompleteInput.prototype = { constructor: AutoCompleteInput, - get minResultsForPopup() 0, - get timeout() 10, - get searchParam() "", - get textValue() "", - get disableAutoComplete() false, - get completeDefaultIndex() false, + get minResultsForPopup() { + return 0; + }, + get timeout() { + return 10; + }, + get searchParam() { + return ""; + }, + get textValue() { + return ""; + }, + get disableAutoComplete() { + return false; + }, + get completeDefaultIndex() { + return false; + }, - get searchCount() this.searches.length, - getSearchAt: function (aIndex) this.searches[aIndex], + get searchCount() { + return this.searches.length; + }, + getSearchAt: function (aIndex) { + return this.searches[aIndex]; + }, onSearchBegin: function () {}, onSearchComplete: function() {}, - get popupOpen() false, + get popupOpen() { + return false; + }, popup: { - set selectedIndex(aIndex) aIndex, + set selectedIndex(aIndex) {}, invalidate: function () {}, QueryInterface: XPCOMUtils.generateQI([Ci.nsIAutoCompletePopup]) }, @@ -94,11 +112,17 @@ function task_setCountRank(aURI, aCount, aRank, aSearch, aBookmark) QueryInterface: XPCOMUtils.generateQI([Ci.nsIAutoCompleteInput, Ci.nsIAutoCompletePopup, Ci.nsIAutoCompleteController]), - get popup() thing, - get controller() thing, + get popup() { + return thing; + }, + get controller() { + return thing; + }, popupOpen: true, selectedIndex: 0, - getValueAt: function() aURI.spec, + getValueAt: function() { + return aURI.spec; + }, searchString: aSearch }; diff --git a/toolkit/components/places/tests/unit/test_adaptive_bug527311.js b/toolkit/components/places/tests/unit/test_adaptive_bug527311.js index 348add2c7b..dbf3214bbc 100644 --- a/toolkit/components/places/tests/unit/test_adaptive_bug527311.js +++ b/toolkit/components/places/tests/unit/test_adaptive_bug527311.js @@ -116,7 +116,7 @@ function addAdaptiveFeedback(aUrl, aSearch, aCallback) { get controller() { return thing; }, popupOpen: true, selectedIndex: 0, - getValueAt: function() aUrl, + getValueAt: () => aUrl, searchString: aSearch }; diff --git a/toolkit/components/places/tests/unit/test_async_transactions.js b/toolkit/components/places/tests/unit/test_async_transactions.js index 61bddb9a5c..91216ec7db 100644 --- a/toolkit/components/places/tests/unit/test_async_transactions.js +++ b/toolkit/components/places/tests/unit/test_async_transactions.js @@ -1254,7 +1254,9 @@ add_task(function* test_annotate_multiple() { this.expires = Ci.nsIAnnotationService.EXPIRE_NEVER; } - function annos(a = null, b = null) [new AnnoObj("A", a), new AnnoObj("B", b)] + function annos(a = null, b = null) { + return [new AnnoObj("A", a), new AnnoObj("B", b)]; + } function verifyAnnoValues(a = null, b = null) { let currentAnnos = PlacesUtils.getAnnotationsForItem(itemId); diff --git a/toolkit/components/places/tests/unit/test_autocomplete_stopSearch_no_throw.js b/toolkit/components/places/tests/unit/test_autocomplete_stopSearch_no_throw.js index b52e029d69..bca8e5354b 100644 --- a/toolkit/components/places/tests/unit/test_autocomplete_stopSearch_no_throw.js +++ b/toolkit/components/places/tests/unit/test_autocomplete_stopSearch_no_throw.js @@ -38,5 +38,5 @@ let tests = [ ]; function run_test() { - tests.forEach(function(test) test()); + tests.forEach(test => test()); } diff --git a/toolkit/components/places/tests/unit/test_bookmarks_restore_notification.js b/toolkit/components/places/tests/unit/test_bookmarks_restore_notification.js index 11963eae0a..a7553852c0 100644 --- a/toolkit/components/places/tests/unit/test_bookmarks_restore_notification.js +++ b/toolkit/components/places/tests/unit/test_bookmarks_restore_notification.js @@ -288,10 +288,10 @@ var obssvc = Cc["@mozilla.org/observer-service;1"]. * Adds some bookmarks for the URIs in |uris|. */ function addBookmarks() { - uris.forEach(function (u) bmsvc.insertBookmark(bmsvc.bookmarksMenuFolder, - uri(u), - bmsvc.DEFAULT_INDEX, - u)); + uris.forEach(u => bmsvc.insertBookmark(bmsvc.bookmarksMenuFolder, + uri(u), + bmsvc.DEFAULT_INDEX, + u)); checkBookmarksExist(); } diff --git a/toolkit/components/places/tests/unit/test_browserhistory.js b/toolkit/components/places/tests/unit/test_browserhistory.js index 7b60e94567..5a75580731 100644 --- a/toolkit/components/places/tests/unit/test_browserhistory.js +++ b/toolkit/components/places/tests/unit/test_browserhistory.js @@ -23,7 +23,7 @@ add_task(function* test_removePages() { pages.push(NetUtil.newURI(TEST_URI.spec + i)); } - yield PlacesTestUtils.addVisits(pages.map(function (uri) ({ uri: uri }))); + yield PlacesTestUtils.addVisits(pages.map(uri => ({ uri: uri }))); // Bookmarked item should not be removed from moz_places. const ANNO_INDEX = 1; const ANNO_NAME = "testAnno"; diff --git a/toolkit/components/places/tests/unit/test_history_autocomplete_tags.js b/toolkit/components/places/tests/unit/test_history_autocomplete_tags.js index 4765cea257..1d4ecbc992 100644 --- a/toolkit/components/places/tests/unit/test_history_autocomplete_tags.js +++ b/toolkit/components/places/tests/unit/test_history_autocomplete_tags.js @@ -101,7 +101,7 @@ function ensure_tag_results(uris, searchTerm) do_check_eq(controller.getStyleAt(i), "tag"); } // Sort the results then check if we have the right items - vals.sort().forEach(function(val, i) do_check_eq(val, uris[i].spec)) + vals.sort().forEach((val, i) => do_check_eq(val, uris[i].spec)) if (current_test < (tests.length - 1)) { current_test++; @@ -122,30 +122,30 @@ var uri5 = uri("http://site.tld/5/aaa"); var uri6 = uri("http://site.tld/6/bbb"); var tests = [ - function() ensure_tag_results([uri1, uri4, uri6], "foo"), - function() ensure_tag_results([uri1], "foo aaa"), - function() ensure_tag_results([uri4, uri6], "foo bbb"), - function() ensure_tag_results([uri2, uri4, uri5, uri6], "bar"), - function() ensure_tag_results([uri5], "bar aaa"), - function() ensure_tag_results([uri2, uri4, uri6], "bar bbb"), - function() ensure_tag_results([uri3, uri5, uri6], "cheese"), - function() ensure_tag_results([uri3, uri5], "chees aaa"), - function() ensure_tag_results([uri6], "chees bbb"), - function() ensure_tag_results([uri4, uri6], "fo bar"), - function() ensure_tag_results([], "fo bar aaa"), - function() ensure_tag_results([uri4, uri6], "fo bar bbb"), - function() ensure_tag_results([uri4, uri6], "ba foo"), - function() ensure_tag_results([], "ba foo aaa"), - function() ensure_tag_results([uri4, uri6], "ba foo bbb"), - function() ensure_tag_results([uri5, uri6], "ba chee"), - function() ensure_tag_results([uri5], "ba chee aaa"), - function() ensure_tag_results([uri6], "ba chee bbb"), - function() ensure_tag_results([uri5, uri6], "cheese bar"), - function() ensure_tag_results([uri5], "cheese bar aaa"), - function() ensure_tag_results([uri6], "chees bar bbb"), - function() ensure_tag_results([uri6], "cheese bar foo"), - function() ensure_tag_results([], "foo bar cheese aaa"), - function() ensure_tag_results([uri6], "foo bar cheese bbb"), + () => ensure_tag_results([uri1, uri4, uri6], "foo"), + () => ensure_tag_results([uri1], "foo aaa"), + () => ensure_tag_results([uri4, uri6], "foo bbb"), + () => ensure_tag_results([uri2, uri4, uri5, uri6], "bar"), + () => ensure_tag_results([uri5], "bar aaa"), + () => ensure_tag_results([uri2, uri4, uri6], "bar bbb"), + () => ensure_tag_results([uri3, uri5, uri6], "cheese"), + () => ensure_tag_results([uri3, uri5], "chees aaa"), + () => ensure_tag_results([uri6], "chees bbb"), + () => ensure_tag_results([uri4, uri6], "fo bar"), + () => ensure_tag_results([], "fo bar aaa"), + () => ensure_tag_results([uri4, uri6], "fo bar bbb"), + () => ensure_tag_results([uri4, uri6], "ba foo"), + () => ensure_tag_results([], "ba foo aaa"), + () => ensure_tag_results([uri4, uri6], "ba foo bbb"), + () => ensure_tag_results([uri5, uri6], "ba chee"), + () => ensure_tag_results([uri5], "ba chee aaa"), + () => ensure_tag_results([uri6], "ba chee bbb"), + () => ensure_tag_results([uri5, uri6], "cheese bar"), + () => ensure_tag_results([uri5], "cheese bar aaa"), + () => ensure_tag_results([uri6], "chees bar bbb"), + () => ensure_tag_results([uri6], "cheese bar foo"), + () => ensure_tag_results([], "foo bar cheese aaa"), + () => ensure_tag_results([uri6], "foo bar cheese bbb"), ]; /** diff --git a/toolkit/components/places/tests/unit/test_telemetry.js b/toolkit/components/places/tests/unit/test_telemetry.js index a0f18b7a87..1df72f4223 100644 --- a/toolkit/components/places/tests/unit/test_telemetry.js +++ b/toolkit/components/places/tests/unit/test_telemetry.js @@ -97,7 +97,7 @@ add_task(function test_execute() onSearchComplete: function() {}, setSelectedIndex: function() {}, get searchCount() { return this.searches.length; }, - getSearchAt: function(aIndex) this.searches[aIndex], + getSearchAt: function(aIndex) { return this.searches[aIndex]; }, QueryInterface: XPCOMUtils.generateQI([ Ci.nsIAutoCompleteInput, Ci.nsIAutoCompletePopup, @@ -121,7 +121,7 @@ add_task(function test_execute() let validate = histograms[histogramId]; let snapshot = Services.telemetry.getHistogramById(histogramId).snapshot(); validate(snapshot.sum); - do_check_true(snapshot.counts.reduce(function(a, b) a + b) > 0); + do_check_true(snapshot.counts.reduce((a, b) => a + b) > 0); } }); diff --git a/toolkit/components/satchel/test/browser/browser_privbrowsing_perwindowpb.js b/toolkit/components/satchel/test/browser/browser_privbrowsing_perwindowpb.js index 5a7629774d..06cc971ad0 100644 --- a/toolkit/components/satchel/test/browser/browser_privbrowsing_perwindowpb.js +++ b/toolkit/components/satchel/test/browser/browser_privbrowsing_perwindowpb.js @@ -57,7 +57,7 @@ function test() { function testOnWindow(aOptions, aCallback) { whenNewWindowLoaded(aOptions, function(aWin) { windowsToClose.push(aWin); - executeSoon(function() aCallback(aWin)); + executeSoon(() => aCallback(aWin)); }); }; diff --git a/toolkit/components/satchel/test/test_bug_787624.html b/toolkit/components/satchel/test/test_bug_787624.html index 45378c7994..96b9508897 100644 --- a/toolkit/components/satchel/test/test_bug_787624.html +++ b/toolkit/components/satchel/test/test_bug_787624.html @@ -70,7 +70,7 @@ function setupFormHistory() { { op : "remove" }, { op : "add", fieldname : "field1", value : "value1" }, { op : "add", fieldname : "field1", value : "value2" }, - ], function() runTest(1)); + ], () => runTest(1)); } function checkForm(expectedValue) { diff --git a/toolkit/components/satchel/test/unit/head_satchel.js b/toolkit/components/satchel/test/unit/head_satchel.js index b81edaff4a..79e454ae86 100644 --- a/toolkit/components/satchel/test/unit/head_satchel.js +++ b/toolkit/components/satchel/test/unit/head_satchel.js @@ -39,7 +39,7 @@ const isGUID = /[A-Za-z0-9\+\/]{16}/; // Find form history entries. function searchEntries(terms, params, iter) { let results = []; - FormHistory.search(terms, params, { handleResult: function (result) results.push(result), + FormHistory.search(terms, params, { handleResult: result => results.push(result), handleError: function (error) { do_throw("Error occurred searching form history: " + error); }, @@ -57,7 +57,7 @@ function countEntries(name, value, then) { obj.value = value; let count = 0; - FormHistory.count(obj, { handleResult: function (result) count = result, + FormHistory.count(obj, { handleResult: result => count = result, handleError: function (error) { do_throw("Error occurred searching form history: " + error); }, diff --git a/toolkit/components/satchel/test/unit/test_history_api.js b/toolkit/components/satchel/test/unit/test_history_api.js index b71adb9616..9eaded4095 100644 --- a/toolkit/components/satchel/test/unit/test_history_api.js +++ b/toolkit/components/satchel/test/unit/test_history_api.js @@ -76,7 +76,7 @@ function promiseSearchEntries(terms, params) let deferred = Promise.defer(); let results = []; FormHistory.search(terms, params, - { handleResult: function(result) results.push(result), + { handleResult: result => results.push(result), handleError: function (error) { do_throw("Error occurred searching form history: " + error); deferred.reject(error); @@ -165,7 +165,7 @@ add_task(function () // and here a search should be done explicity for null. deferred = Promise.defer(); yield FormHistory.count({ fieldname: null, value: null }, - { handleResult: function(result) checkNotExists(result), + { handleResult: result => checkNotExists(result), handleError: function (error) { do_throw("Error occurred searching form history: " + error); }, @@ -269,7 +269,7 @@ add_task(function () do_check_eq(1, timesUsed); do_check_true(firstUsed > 0); do_check_true(lastUsed > 0); - yield promiseCountEntries(null, null, function(num) do_check_eq(num, 1)); + yield promiseCountEntries(null, null, num => do_check_eq(num, 1)); // ===== 11 ===== // Add another single entry @@ -277,7 +277,7 @@ add_task(function () yield promiseUpdateEntry("add", "field1", "value1b"); yield promiseCountEntries("field1", "value1", checkExists); yield promiseCountEntries("field1", "value1b", checkExists); - yield promiseCountEntries(null, null, function(num) do_check_eq(num, 2)); + yield promiseCountEntries(null, null, num => do_check_eq(num, 2)); // ===== 12 ===== // Update a single entry @@ -290,7 +290,7 @@ add_task(function () yield promiseCountEntries("field1", "modifiedValue", checkExists); yield promiseCountEntries("field1", "value1", checkNotExists); yield promiseCountEntries("field1", "value1b", checkExists); - yield promiseCountEntries(null, null, function(num) do_check_eq(num, 2)); + yield promiseCountEntries(null, null, num => do_check_eq(num, 2)); // ===== 13 ===== // Add a single entry with times @@ -305,7 +305,7 @@ add_task(function () do_check_eq(20, timesUsed); do_check_eq(100, firstUsed); do_check_eq(500, lastUsed); - yield promiseCountEntries(null, null, function(num) do_check_eq(num, 3)); + yield promiseCountEntries(null, null, num => do_check_eq(num, 3)); // ===== 14 ===== // Bump an entry, which updates its lastUsed field @@ -318,7 +318,7 @@ add_task(function () do_check_eq(21, timesUsed); do_check_eq(100, firstUsed); do_check_true(lastUsed > 500); - yield promiseCountEntries(null, null, function(num) do_check_eq(num, 3)); + yield promiseCountEntries(null, null, num => do_check_eq(num, 3)); // ===== 15 ===== // Bump an entry that does not exist @@ -331,7 +331,7 @@ add_task(function () do_check_eq(10, timesUsed); do_check_eq(50, firstUsed); do_check_eq(400, lastUsed); - yield promiseCountEntries(null, null, function(num) do_check_eq(num, 4)); + yield promiseCountEntries(null, null, num => do_check_eq(num, 4)); // ===== 16 ===== // Bump an entry with a guid @@ -345,7 +345,7 @@ add_task(function () do_check_eq(11, timesUsed); do_check_eq(50, firstUsed); do_check_true(lastUsed > 400); - yield promiseCountEntries(null, null, function(num) do_check_eq(num, 4)); + yield promiseCountEntries(null, null, num => do_check_eq(num, 4)); // ===== 17 ===== // Remove an entry @@ -358,17 +358,17 @@ add_task(function () yield promiseUpdate({ op : "remove", guid: guid}); yield promiseCountEntries("field1", "modifiedValue", checkExists); yield promiseCountEntries("field1", "value1b", checkNotExists); - yield promiseCountEntries(null, null, function(num) do_check_eq(num, 3)); + yield promiseCountEntries(null, null, num => do_check_eq(num, 3)); yield countDeletedEntries(8); - yield checkTimeDeleted(guid, function (timeDeleted) do_check_true(timeDeleted > 10000)); + yield checkTimeDeleted(guid, timeDeleted => do_check_true(timeDeleted > 10000)); // ===== 18 ===== // Add yet another single entry testnum++; yield promiseUpdate({ op : "add", fieldname: "field4", value: "value4", timesUsed: 5, firstUsed: 230, lastUsed: 600 }); - yield promiseCountEntries(null, null, function(num) do_check_eq(num, 4)); + yield promiseCountEntries(null, null, num => do_check_eq(num, 4)); // ===== 19 ===== // Remove an entry by time @@ -378,7 +378,7 @@ add_task(function () yield promiseCountEntries("field2", "value2", checkNotExists); yield promiseCountEntries("field3", "value3", checkExists); yield promiseCountEntries("field4", "value4", checkNotExists); - yield promiseCountEntries(null, null, function(num) do_check_eq(num, 2)); + yield promiseCountEntries(null, null, num => do_check_eq(num, 2)); yield countDeletedEntries(10); // ===== 20 ===== @@ -389,7 +389,7 @@ add_task(function () timesUsed: 5, firstUsed: 230, lastUsed: 600 }, { op : "add", fieldname: "field6", value: "value6", timesUsed: 12, firstUsed: 430, lastUsed: 700 }]); - yield promiseCountEntries(null, null, function(num) do_check_eq(num, 4)); + yield promiseCountEntries(null, null, num => do_check_eq(num, 4)); yield promiseUpdate([ { op : "bump", fieldname: "field5", value: "value5" }, @@ -403,7 +403,7 @@ add_task(function () do_check_true(results[2].lastUsed > 600); do_check_true(results[3].lastUsed > 700); - yield promiseCountEntries(null, null, function(num) do_check_eq(num, 4)); + yield promiseCountEntries(null, null, num => do_check_eq(num, 4)); } catch (e) { throw "FAILED in test #" + testnum + " -- " + e; @@ -414,4 +414,6 @@ add_task(function () } }); -function run_test() run_next_test(); +function run_test() { + return run_next_test(); +} diff --git a/toolkit/components/social/test/xpcshell/head.js b/toolkit/components/social/test/xpcshell/head.js index cdb3a624f3..b93e891321 100644 --- a/toolkit/components/social/test/xpcshell/head.js +++ b/toolkit/components/social/test/xpcshell/head.js @@ -76,7 +76,7 @@ function initApp() { function AsyncRunner() { do_test_pending(); - do_register_cleanup((function () this.destroy()).bind(this)); + do_register_cleanup(() => this.destroy()); this._callbacks = { done: do_test_finished, diff --git a/toolkit/components/social/test/xpcshell/test_SocialService.js b/toolkit/components/social/test/xpcshell/test_SocialService.js index 979853b764..2cb4d14074 100644 --- a/toolkit/components/social/test/xpcshell/test_SocialService.js +++ b/toolkit/components/social/test/xpcshell/test_SocialService.js @@ -74,7 +74,7 @@ function testGetProviderList(manifests, next) { let providers = yield SocialService.getProviderList(next); do_check_true(providers.length >= manifests.length); for (let i = 0; i < manifests.length; i++) { - let providerIdx = providers.map(function (p) p.origin).indexOf(manifests[i].origin); + let providerIdx = providers.map(p => p.origin).indexOf(manifests[i].origin); let provider = providers[providerIdx]; do_check_true(!!provider); do_check_false(provider.enabled); diff --git a/toolkit/components/telemetry/Histograms.json b/toolkit/components/telemetry/Histograms.json index a6d7d88d58..2995e33802 100644 --- a/toolkit/components/telemetry/Histograms.json +++ b/toolkit/components/telemetry/Histograms.json @@ -25,7 +25,6 @@ "kind": "exponential", "high": "10000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "time spent updating accessibility (ms)" }, "ADDON_SHIM_USAGE": { @@ -450,7 +449,6 @@ "low": "32 * 1024", "high": "16 * 1024 * 1024", "n_buckets": 100, - "extended_statistics_ok": true, "description": "Virtual memory size (KB)" }, "MEMORY_VSIZE_MAX_CONTIGUOUS": { @@ -460,7 +458,6 @@ "low": "32 * 1024", "high": "16 * 1024 * 1024", "n_buckets": 100, - "extended_statistics_ok": true, "description": "Maximum-sized block of contiguous virtual memory (KB)" }, "MEMORY_JS_COMPARTMENTS_SYSTEM": { @@ -469,7 +466,6 @@ "kind": "exponential", "high": "1000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "Total JavaScript compartments used for add-ons and internals." }, "MEMORY_JS_COMPARTMENTS_USER": { @@ -478,7 +474,6 @@ "kind": "exponential", "high": "1000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "Total JavaScript compartments used for web pages" }, "MEMORY_JS_MAIN_RUNTIME_TEMPORARY_PEAK": { @@ -488,7 +483,6 @@ "low": 1024, "high": "16 * 1024 * 1024", "n_buckets": 200, - "extended_statistics_ok": true, "description": "Peak memory used by the main JSRuntime to store transient data (KB)" }, "MEMORY_JS_GC_HEAP": { @@ -498,7 +492,6 @@ "low": 1024, "high": "16 * 1024 * 1024", "n_buckets": 200, - "extended_statistics_ok": true, "description": "Memory used by the garbage-collected JavaScript heap (KB)" }, "MEMORY_STORAGE_SQLITE": { @@ -508,7 +501,6 @@ "low": 1024, "high": "512 * 1024", "n_buckets": 50, - "extended_statistics_ok": true, "description": "Memory used by SQLite (KB)" }, "MEMORY_IMAGES_CONTENT_USED_UNCOMPRESSED": { @@ -518,7 +510,6 @@ "low": 1024, "high": "1024 * 1024", "n_buckets": 50, - "extended_statistics_ok": true, "description": "Memory used for uncompressed, in-use content images (KB)" }, "MEMORY_HEAP_ALLOCATED": { @@ -528,7 +519,6 @@ "low": 1024, "high": "16 * 1024 * 1024", "n_buckets": 200, - "extended_statistics_ok": true, "description": "Heap memory allocated (KB)" }, "MEMORY_HEAP_COMMITTED_UNUSED": { @@ -538,7 +528,6 @@ "low": 1024, "high": "512 * 1024", "n_buckets": 50, - "extended_statistics_ok": true, "description": "Committed, unused heap memory (KB)" }, "MEMORY_HEAP_COMMITTED_UNUSED_RATIO": { @@ -555,7 +544,6 @@ "kind": "exponential", "high": "128", "n_buckets": 32, - "extended_statistics_ok": true, "description": "Number of ghost windows" }, "MEMORY_FREE_PURGED_PAGES_MS": { @@ -564,7 +552,6 @@ "kind": "exponential", "high": "1024", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Time(ms) to purge dirty heap pages." }, "LOW_MEMORY_EVENTS_VIRTUAL": { @@ -573,7 +560,6 @@ "kind": "exponential", "high": "1024", "n_buckets": 21, - "extended_statistics_ok": true, "description": "Number of low-virtual-memory events fired since last ping", "cpp_guard": "XP_WIN" }, @@ -583,7 +569,6 @@ "kind": "exponential", "high": "1024", "n_buckets": 21, - "extended_statistics_ok": true, "description": "Number of low-physical-memory events fired since last ping", "cpp_guard": "XP_WIN" }, @@ -593,7 +578,6 @@ "kind": "exponential", "high": "1024", "n_buckets": 21, - "extended_statistics_ok": true, "description": "Number of low-commit-space events fired since last ping", "cpp_guard": "XP_WIN" }, @@ -612,7 +596,6 @@ "kind": "exponential", "high": "50 * 1024", "n_buckets": 12, - "extended_statistics_ok": true, "description": "ProcessIoCounters.ReadTransferCount before glue startup (KB)", "cpp_guard": "XP_WIN" }, @@ -631,7 +614,6 @@ "kind": "exponential", "high": "50 * 1024", "n_buckets": 12, - "extended_statistics_ok": true, "description": "ProcessIoCounters.ReadTransferCount after glue startup (KB)", "cpp_guard": "XP_WIN" }, @@ -650,7 +632,6 @@ "kind": "exponential", "high": "500", "n_buckets": 12, - "extended_statistics_ok": true, "description": "Hard faults count after glue startup", "cpp_guard": "XP_UNIX" }, @@ -660,7 +641,6 @@ "low": 8, "high": "64 * 1024", "n_buckets": 13, - "extended_statistics_ok": true, "description": "Hard page faults (since last telemetry ping)", "cpp_guard": "XP_UNIX" }, @@ -669,7 +649,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "Time(ms) spent on reading other family names from all fonts" }, "FONTLIST_INITFACENAMELISTS": { @@ -677,7 +656,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "Time(ms) spent on reading family names from all fonts" }, "DWRITEFONT_DELAYEDINITFONTLIST_TOTAL": { @@ -685,7 +663,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "gfxDWriteFontList::DelayedInitFontList Total (ms)", "cpp_guard": "XP_WIN" }, @@ -694,7 +671,6 @@ "kind": "exponential", "high": "10000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "gfxDWriteFontList::DelayedInitFontList Font Family Count", "cpp_guard": "XP_WIN" }, @@ -703,7 +679,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "gfxDWriteFontList::DelayedInitFontList GetSystemFontCollection (ms)", "cpp_guard": "XP_WIN" }, @@ -719,7 +694,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "gfxGDIFontList::InitFontList Total (ms)", "cpp_guard": "XP_WIN" }, @@ -728,7 +702,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "gfxMacPlatformFontList::InitFontList Total (ms)", "cpp_guard": "XP_MACOSX" }, @@ -737,7 +710,6 @@ "kind": "exponential", "high": "100000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "System font fallback (us)" }, "SYSTEM_FONT_FALLBACK_FIRST": { @@ -745,7 +717,6 @@ "kind": "exponential", "high": "40000", "n_buckets": 20, - "extended_statistics_ok": true, "description": "System font fallback, first call (ms)" }, "SYSTEM_FONT_FALLBACK_SCRIPT": { @@ -773,7 +744,6 @@ "kind": "exponential", "high": "3000", "n_buckets": 20, - "extended_statistics_ok": true, "description": "Startup cache age (hours)" }, "STARTUP_CACHE_INVALID": { @@ -911,7 +881,6 @@ "low": 100, "high": "30000", "n_buckets": 100, - "extended_statistics_ok": true, "description": "HTTP: Total page load time (ms)" }, "HTTP_SUBITEM_OPEN_LATENCY_TIME": { @@ -919,7 +888,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "HTTP subitem: Page start -> subitem open() (ms)" }, "HTTP_SUBITEM_FIRST_BYTE_LATENCY_TIME": { @@ -927,7 +895,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "HTTP subitem: Page start -> first byte received for subitem reply (ms)" }, "HTTP_REQUEST_PER_PAGE": { @@ -935,7 +902,6 @@ "kind": "exponential", "high": "1000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "HTTP: Requests per page (count)" }, "HTTP_REQUEST_PER_PAGE_FROM_CACHE": { @@ -949,7 +915,6 @@ "kind": "exponential", "high": "1000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "HTTP: requests per connection" }, "HTTP_KBREAD_PER_CONN": { @@ -957,7 +922,6 @@ "kind": "exponential", "high": "3000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "HTTP: KB read per connection" }, "HTTP_PAGE_DNS_ISSUE_TIME": { @@ -965,7 +929,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "HTTP page: open() -> DNS request issued (ms)" }, "HTTP_PAGE_DNS_LOOKUP_TIME": { @@ -973,7 +936,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "HTTP page: DNS lookup time (ms)" }, "HTTP_PAGE_TCP_CONNECTION": { @@ -981,7 +943,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "HTTP page: TCP connection setup (ms)" }, "HTTP_PAGE_OPEN_TO_FIRST_SENT": { @@ -989,7 +950,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "HTTP page: Open -> first byte of request sent (ms)" }, "HTTP_PAGE_FIRST_SENT_TO_LAST_RECEIVED": { @@ -997,7 +957,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "HTTP page: First byte of request sent -> last byte of response received (ms)" }, "HTTP_PAGE_OPEN_TO_FIRST_RECEIVED": { @@ -1005,7 +964,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "HTTP page: Open -> first byte of reply received (ms)" }, "HTTP_PAGE_OPEN_TO_FIRST_FROM_CACHE": { @@ -1013,7 +971,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "HTTP page: Open -> cache read start (ms)" }, "HTTP_PAGE_OPEN_TO_FIRST_FROM_CACHE_V2": { @@ -1021,7 +978,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "HTTP page: Open -> cache read start (ms), [cache2]" }, "HTTP_PAGE_CACHE_READ_TIME": { @@ -1029,7 +985,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "HTTP page: Cache read time (ms)" }, "HTTP_PAGE_CACHE_READ_TIME_V2": { @@ -1037,7 +992,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "HTTP page: Cache read time (ms) [cache2]" }, "HTTP_PAGE_REVALIDATION": { @@ -1045,7 +999,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "HTTP page: Positive cache validation time (ms)" }, "HTTP_PAGE_COMPLETE_LOAD": { @@ -1053,7 +1006,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "HTTP page: Overall load time - all (ms)" }, "HTTP_PAGE_COMPLETE_LOAD_V2": { @@ -1061,7 +1013,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "HTTP page: Overall load time - all (ms) [cache2]" }, "HTTP_PAGE_COMPLETE_LOAD_CACHED": { @@ -1069,7 +1020,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "HTTP page: Overall load time - cache hits (ms)" }, "HTTP_PAGE_COMPLETE_LOAD_CACHED_V2": { @@ -1077,7 +1027,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "HTTP page: Overall load time - cache hits (ms) [cache2]" }, "HTTP_PAGE_COMPLETE_LOAD_NET": { @@ -1085,7 +1034,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "HTTP page: Overall load time - network (ms)" }, "HTTP_PAGE_COMPLETE_LOAD_NET_V2": { @@ -1093,7 +1041,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "HTTP page: Overall load time - network (ms) [cache2]" }, "HTTP_SUB_DNS_ISSUE_TIME": { @@ -1101,7 +1048,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "HTTP subitem: open() -> DNS request issued (ms)" }, "HTTP_SUB_DNS_LOOKUP_TIME": { @@ -1109,7 +1055,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "HTTP subitem: DNS lookup time (ms)" }, "HTTP_SUB_TCP_CONNECTION": { @@ -1117,7 +1062,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "HTTP subitem: TCP connection setup (ms)" }, "HTTP_SUB_OPEN_TO_FIRST_SENT": { @@ -1125,7 +1069,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "HTTP subitem: Open -> first byte of request sent (ms)" }, "HTTP_SUB_FIRST_SENT_TO_LAST_RECEIVED": { @@ -1133,7 +1076,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "HTTP subitem: First byte of request sent -> last byte of response received (ms)" }, "HTTP_SUB_OPEN_TO_FIRST_RECEIVED": { @@ -1141,7 +1083,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "HTTP subitem: Open -> first byte of reply received (ms)" }, "HTTP_SUB_OPEN_TO_FIRST_FROM_CACHE": { @@ -1149,7 +1090,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "HTTP subitem: Open -> cache read start (ms)" }, "HTTP_SUB_OPEN_TO_FIRST_FROM_CACHE_V2": { @@ -1157,7 +1097,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "HTTP subitem: Open -> cache read start (ms) [cache2]" }, "HTTP_SUB_CACHE_READ_TIME": { @@ -1165,7 +1104,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "HTTP subitem: Cache read time (ms)" }, "HTTP_SUB_CACHE_READ_TIME_V2": { @@ -1173,7 +1111,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "HTTP subitem: Cache read time (ms) [cache2]" }, "HTTP_SUB_REVALIDATION": { @@ -1181,7 +1118,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "HTTP subitem: Positive cache validation time (ms)" }, "HTTP_SUB_COMPLETE_LOAD": { @@ -1189,7 +1125,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "HTTP subitem: Overall load time - all (ms)" }, "HTTP_SUB_COMPLETE_LOAD_V2": { @@ -1197,7 +1132,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "HTTP subitem: Overall load time - all (ms) [cache2]" }, "HTTP_SUB_COMPLETE_LOAD_CACHED": { @@ -1205,7 +1139,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "HTTP subitem: Overall load time - cache hits (ms)" }, "HTTP_SUB_COMPLETE_LOAD_CACHED_V2": { @@ -1213,7 +1146,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "HTTP subitem: Overall load time - cache hits (ms) [cache2]" }, "HTTP_SUB_COMPLETE_LOAD_NET": { @@ -1221,7 +1153,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "HTTP subitem: Overall load time - network (ms)" }, "HTTP_SUB_COMPLETE_LOAD_NET_V2": { @@ -1229,7 +1160,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "HTTP subitem: Overall load time - network (ms) [cache2]" }, "HTTP_PROXY_TYPE": { @@ -1286,7 +1216,6 @@ "kind": "exponential", "high": "60000", "n_buckets": 200, - "extended_statistics_ok": true, "description": "ms of SSL wait time including TCP and proxy tunneling" }, "SSL_TIME_UNTIL_HANDSHAKE_FINISHED": { @@ -1301,7 +1230,6 @@ "kind": "exponential", "high": "32000", "n_buckets": 64, - "extended_statistics_ok": true, "description": "plaintext bytes read before a server certificate authenticated" }, "SSL_NPN_TYPE": { @@ -1326,7 +1254,6 @@ "kind": "exponential", "high": "60000", "n_buckets": 200, - "extended_statistics_ok": true, "description": "ms elapsed time of OCSP etc.. that was canceled" }, "CERT_VALIDATION_HTTP_REQUEST_SUCCEEDED_TIME": { @@ -1334,7 +1261,6 @@ "kind": "exponential", "high": "60000", "n_buckets": 200, - "extended_statistics_ok": true, "description": "ms elapsed time of OCSP etc.. that succeeded" }, "CERT_VALIDATION_HTTP_REQUEST_FAILED_TIME": { @@ -1342,7 +1268,6 @@ "kind": "exponential", "high": "60000", "n_buckets": 200, - "extended_statistics_ok": true, "description": "ms elapsed time of OCSP etc.. that failed" }, "SSL_KEY_EXCHANGE_ALGORITHM_FULL": { @@ -1396,7 +1321,6 @@ "kind": "exponential", "high": "1000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "SPDY: Streams concurrent active per connection" }, "SPDY_REQUEST_PER_CONN": { @@ -1404,7 +1328,6 @@ "kind": "exponential", "high": "1000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "SPDY: Streams created per connection" }, "SPDY_SERVER_INITIATED_STREAMS": { @@ -1412,7 +1335,6 @@ "kind": "exponential", "high": "100000", "n_buckets": 250, - "extended_statistics_ok": true, "description": "SPDY: Streams recevied per connection" }, "SPDY_CHUNK_RECVD": { @@ -1420,7 +1342,6 @@ "kind": "exponential", "high": "1000", "n_buckets": 100, - "extended_statistics_ok": true, "description": "SPDY: Recvd Chunk Size (rounded to KB)" }, "SPDY_SYN_SIZE": { @@ -1429,7 +1350,6 @@ "low": 20, "high": "20000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "SPDY: SYN Frame Header Size" }, "SPDY_SYN_RATIO": { @@ -1445,7 +1365,6 @@ "low": 16, "high": "20000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "SPDY: SYN Reply Header Size" }, "SPDY_SYN_REPLY_RATIO": { @@ -1470,7 +1389,6 @@ "kind": "exponential", "high": "3000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "SPDY: KB read per connection" }, "SPDY_SETTINGS_UL_BW": { @@ -1478,7 +1396,6 @@ "kind": "exponential", "high": "10000", "n_buckets": 100, - "extended_statistics_ok": true, "description": "SPDY: Settings Upload Bandwidth" }, "SPDY_SETTINGS_DL_BW": { @@ -1486,7 +1403,6 @@ "kind": "exponential", "high": "10000", "n_buckets": 100, - "extended_statistics_ok": true, "description": "SPDY: Settings Download Bandwidth" }, "SPDY_SETTINGS_RTT": { @@ -1494,7 +1410,6 @@ "kind": "exponential", "high": "1000", "n_buckets": 100, - "extended_statistics_ok": true, "description": "SPDY: Settings RTT" }, "SPDY_SETTINGS_MAX_STREAMS": { @@ -1502,7 +1417,6 @@ "kind": "exponential", "high": "5000", "n_buckets": 100, - "extended_statistics_ok": true, "description": "H2: Settings Max Streams parameter" }, "SPDY_SETTINGS_CWND": { @@ -1510,7 +1424,6 @@ "kind": "exponential", "high": "500", "n_buckets": 50, - "extended_statistics_ok": true, "description": "SPDY: Settings CWND (packets)" }, "SPDY_SETTINGS_RETRANS": { @@ -1518,7 +1431,6 @@ "kind": "exponential", "high": "100", "n_buckets": 50, - "extended_statistics_ok": true, "description": "SPDY: Retransmission Rate" }, "SPDY_SETTINGS_IW": { @@ -1526,7 +1438,6 @@ "kind": "exponential", "high": "1000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "H2: Settings Initial Window (rounded to KB)" }, "SPDY_GOAWAY_LOCAL": { @@ -1602,7 +1513,6 @@ "kind": "exponential", "high": "900000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "Time before we reload an HTTP cache entry again to memory" }, "HTTP_CACHE_ENTRY_ALIVE_TIME": { @@ -1610,7 +1520,6 @@ "kind": "exponential", "high": "7200000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "Time for which an HTTP cache entry is kept warmed in memory" }, "HTTP_CACHE_ENTRY_REUSE_COUNT": { @@ -1642,7 +1551,6 @@ "kind": "exponential", "high": "10000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "Time to search cache (ms)" }, "CACHE_MEMORY_SEARCH_2": { @@ -1650,7 +1558,6 @@ "kind": "exponential", "high": "10000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "Time to search memory cache (ms)" }, "CACHE_DISK_SEARCH_2": { @@ -1658,7 +1565,6 @@ "kind": "exponential", "high": "10000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "Time to search disk cache (ms)" }, "CACHE_OFFLINE_SEARCH_2": { @@ -1666,7 +1572,6 @@ "kind": "exponential", "high": "10000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "Time to search offline cache (ms)" }, "TRANSACTION_WAIT_TIME_HTTP": { @@ -1674,7 +1579,6 @@ "kind": "exponential", "high": "5000", "n_buckets": 100, - "extended_statistics_ok": true, "description": "Time from submission to dispatch of HTTP transaction (ms)" }, "TRANSACTION_WAIT_TIME_HTTP_PIPELINES": { @@ -1682,7 +1586,6 @@ "kind": "exponential", "high": "5000", "n_buckets": 100, - "extended_statistics_ok": true, "description": "Time from submission to dispatch of HTTP with pipelines transaction (ms)" }, "TRANSACTION_WAIT_TIME_SPDY": { @@ -1690,7 +1593,6 @@ "kind": "exponential", "high": "5000", "n_buckets": 100, - "extended_statistics_ok": true, "description": "Time from submission to dispatch of SPDY transaction (ms)" }, "HTTP_SAW_QUIC_ALT_PROTOCOL": { @@ -1703,7 +1605,6 @@ "kind": "exponential", "high": "32000000", "n_buckets": 100, - "extended_statistics_ok": true, "description": "HTTP Disk cache memory overhead (bytes)" }, "CACHE_LM_INCONSISTENT": { @@ -2230,7 +2131,6 @@ "kind": "exponential", "high": "1440", "n_buckets": 50, - "extended_statistics_ok": true, "description": "DNS Cache Entry Age at Removal Time (minutes)" }, "DNS_LOOKUP_TIME": { @@ -2238,7 +2138,6 @@ "kind": "exponential", "high": "60000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "Time for a successful DNS OS resolution (msec)" }, "DNS_RENEWAL_TIME": { @@ -2246,7 +2145,6 @@ "kind": "exponential", "high": "60000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "Time for a renewed DNS OS resolution (msec)" }, "DNS_RENEWAL_TIME_FOR_TTL": { @@ -2254,7 +2152,6 @@ "kind": "exponential", "high": "60000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "Time for a DNS OS resolution (msec) used to get TTL" }, "DNS_FAILED_LOOKUP_TIME": { @@ -2262,7 +2159,6 @@ "kind": "exponential", "high": "60000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "Time for an unsuccessful DNS OS resolution (msec)" }, "DNS_BLACKLIST_COUNT": { @@ -2298,7 +2194,6 @@ "kind": "exponential", "high": "1000 * 1000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "Number of times nsINetworkPredictor::Predict is called and attempts to predict" }, "PREDICTOR_LEARN_ATTEMPTS": { @@ -2306,7 +2201,6 @@ "kind": "exponential", "high": "1000 * 1000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "Number of times nsINetworkPredictor::Learn is called and attempts to learn" }, "PREDICTOR_PREDICT_FULL_QUEUE": { @@ -2314,7 +2208,6 @@ "kind": "exponential", "high": "60000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "Number of times nsINetworkPredictor::Predict doesn't continue because the queue is full" }, "PREDICTOR_LEARN_FULL_QUEUE": { @@ -2322,7 +2215,6 @@ "kind": "exponential", "high": "60000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "Number of times nsINetworkPredictor::Learn doesn't continue because the queue is full" }, "PREDICTOR_WAIT_TIME": { @@ -2330,7 +2222,6 @@ "kind": "exponential", "high": "3000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Amount of time a predictor event waits in the queue (ms)" }, "PREDICTOR_PREDICT_WORK_TIME": { @@ -2338,7 +2229,6 @@ "kind": "exponential", "high": "3000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Amount of time spent doing the work for predict (ms)" }, "PREDICTOR_LEARN_WORK_TIME": { @@ -2346,7 +2236,6 @@ "kind": "exponential", "high": "3000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Amount of time spent doing the work for learn (ms)" }, "PREDICTOR_TOTAL_PREDICTIONS": { @@ -2354,7 +2243,6 @@ "kind": "exponential", "high": "1000 * 1000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "How many actual predictions (preresolves, preconnects, ...) happen" }, "PREDICTOR_TOTAL_PRECONNECTS": { @@ -2362,7 +2250,6 @@ "kind": "exponential", "high": "1000 * 1000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "How many actual preconnects happen" }, "PREDICTOR_TOTAL_PRECONNECTS_CREATED": { @@ -2370,7 +2257,6 @@ "kind": "exponential", "high": "1000 * 1000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "How many preconnects actually created a speculative socket" }, "PREDICTOR_TOTAL_PRECONNECTS_USED": { @@ -2378,7 +2264,6 @@ "kind": "exponential", "high": "1000 * 1000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "How many preconnects actually created a used speculative socket" }, "PREDICTOR_TOTAL_PRECONNECTS_UNUSED": { @@ -2386,7 +2271,6 @@ "kind": "exponential", "high": "1000 * 1000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "How many preconnects needlessly created a speculative socket" }, "PREDICTOR_TOTAL_PRERESOLVES": { @@ -2394,7 +2278,6 @@ "kind": "exponential", "high": "1000 * 1000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "How many actual preresolves happen" }, "PREDICTOR_PREDICTIONS_CALCULATED": { @@ -2402,7 +2285,6 @@ "kind": "exponential", "high": "1000 * 1000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "How many prediction calculations are performed" }, "PREDICTOR_GLOBAL_DEGRADATION": { @@ -2504,7 +2386,6 @@ "kind": "exponential", "high": "1000 * 1000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "How many speculative http connections are created" }, "HTTPCONNMGR_USED_SPECULATIVE_CONN": { @@ -2512,7 +2393,6 @@ "kind": "exponential", "high": "1000 * 1000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "How many speculative http connections are actually used" }, "HTTPCONNMGR_UNUSED_SPECULATIVE_CONN": { @@ -2520,7 +2400,6 @@ "kind": "exponential", "high": "1000 * 1000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "How many speculative connections are made needlessly" }, "STS_POLL_AND_EVENTS_CYCLE": { @@ -2739,7 +2618,6 @@ "kind": "exponential", "high": "3000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Time spent scanning filesystem for plugins (ms)" }, "CHECK_JAVA_ENABLED": { @@ -2747,7 +2625,6 @@ "kind": "exponential", "high": "3000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Time spent checking if Java is enabled (ms)" }, "PLUGIN_HANG_UI_USER_RESPONSE": { @@ -2787,7 +2664,6 @@ "kind": "exponential", "high": "5000", "n_buckets": 20, - "extended_statistics_ok": true, "description": "Time spent starting up plugins (ms)" }, "PLUGIN_SHUTDOWN_MS": { @@ -2795,7 +2671,6 @@ "kind": "exponential", "high": "5000", "n_buckets": 20, - "extended_statistics_ok": true, "description": "Time spent shutting down plugins (ms)" }, "PLUGIN_CALLED_DIRECTLY": { @@ -2844,7 +2719,6 @@ "kind": "exponential", "high": "3000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Time spent on SQLite open() (ms)" }, "MOZ_SQLITE_OPEN_MAIN_THREAD_MS": { @@ -2852,7 +2726,6 @@ "kind": "exponential", "high": "3000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Time spent on SQLite open() (ms) *** No longer needed (bug 1156565). Delete histogram and accumulation code! ***" }, "MOZ_SQLITE_TRUNCATE_MS": { @@ -2860,7 +2733,6 @@ "kind": "exponential", "high": "3000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Time spent on SQLite truncate() (ms) *** No longer needed (bug 1156565). Delete histogram and accumulation code! ***" }, "MOZ_SQLITE_TRUNCATE_MAIN_THREAD_MS": { @@ -2868,7 +2740,6 @@ "kind": "exponential", "high": "3000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Time spent on SQLite truncate() (ms) *** No longer needed (bug 1156565). Delete histogram and accumulation code! ***" }, "MOZ_SQLITE_OTHER_READ_MS": { @@ -2876,7 +2747,6 @@ "kind": "exponential", "high": "3000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Time spent on SQLite read() (ms) *** No longer needed (bug 1156565). Delete histogram and accumulation code! ***" }, "MOZ_SQLITE_OTHER_READ_MAIN_THREAD_MS": { @@ -2884,7 +2754,6 @@ "kind": "exponential", "high": "3000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Time spent on SQLite read() (ms) *** No longer needed (bug 1156565). Delete histogram and accumulation code! ***" }, "MOZ_SQLITE_PLACES_READ_MS": { @@ -2892,7 +2761,6 @@ "kind": "exponential", "high": "3000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Time spent on SQLite read() (ms) *** No longer needed (bug 1156565). Delete histogram and accumulation code! ***" }, "MOZ_SQLITE_PLACES_READ_MAIN_THREAD_MS": { @@ -2900,7 +2768,6 @@ "kind": "exponential", "high": "3000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Time spent on SQLite read() (ms) *** No longer needed (bug 1156565). Delete histogram and accumulation code! ***" }, "MOZ_SQLITE_COOKIES_OPEN_READAHEAD_MS": { @@ -2908,7 +2775,6 @@ "kind": "exponential", "high": "3000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Time spent on cookie DB open with readahead (ms)" }, "MOZ_SQLITE_COOKIES_READ_MS": { @@ -2916,7 +2782,6 @@ "kind": "exponential", "high": "3000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Time spent on SQLite read() (ms) *** No longer needed (bug 1156565). Delete histogram and accumulation code! ***" }, "MOZ_SQLITE_COOKIES_READ_MAIN_THREAD_MS": { @@ -2924,7 +2789,6 @@ "kind": "exponential", "high": "3000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Time spent on SQLite read() (ms) *** No longer needed (bug 1156565). Delete histogram and accumulation code! ***" }, "MOZ_SQLITE_WEBAPPS_READ_MS": { @@ -2932,7 +2796,6 @@ "kind": "exponential", "high": "3000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Time spent on SQLite read() (ms) *** No longer needed (bug 1156565). Delete histogram and accumulation code! ***" }, "MOZ_SQLITE_WEBAPPS_READ_MAIN_THREAD_MS": { @@ -2940,7 +2803,6 @@ "kind": "exponential", "high": "3000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Time spent on SQLite read() (ms) *** No longer needed (bug 1156565). Delete histogram and accumulation code! ***" }, "MOZ_SQLITE_OTHER_WRITE_MS": { @@ -2948,7 +2810,6 @@ "kind": "exponential", "high": "3000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Time spent on SQLite write() (ms)" }, "MOZ_SQLITE_OTHER_WRITE_MAIN_THREAD_MS": { @@ -2956,7 +2817,6 @@ "kind": "exponential", "high": "3000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Time spent on SQLite write() (ms)" }, "MOZ_SQLITE_PLACES_WRITE_MS": { @@ -2964,7 +2824,6 @@ "kind": "exponential", "high": "3000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Time spent on SQLite write() (ms)" }, "MOZ_SQLITE_PLACES_WRITE_MAIN_THREAD_MS": { @@ -2972,7 +2831,6 @@ "kind": "exponential", "high": "3000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Time spent on SQLite write() (ms) *** No longer needed (bug 1156565). Delete histogram and accumulation code! ***" }, "MOZ_SQLITE_COOKIES_WRITE_MS": { @@ -2980,7 +2838,6 @@ "kind": "exponential", "high": "3000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Time spent on SQLite write() (ms) *** No longer needed (bug 1156565). Delete histogram and accumulation code! ***" }, "MOZ_SQLITE_COOKIES_WRITE_MAIN_THREAD_MS": { @@ -2988,7 +2845,6 @@ "kind": "exponential", "high": "3000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Time spent on SQLite write() (ms) *** No longer needed (bug 1156565). Delete histogram and accumulation code! ***" }, "MOZ_SQLITE_WEBAPPS_WRITE_MS": { @@ -2996,7 +2852,6 @@ "kind": "exponential", "high": "3000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Time spent on SQLite write() (ms) *** No longer needed (bug 1156565). Delete histogram and accumulation code! ***" }, "MOZ_SQLITE_WEBAPPS_WRITE_MAIN_THREAD_MS": { @@ -3004,7 +2859,6 @@ "kind": "exponential", "high": "3000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Time spent on SQLite write() (ms) *** No longer needed (bug 1156565). Delete histogram and accumulation code! ***" }, "MOZ_SQLITE_OTHER_SYNC_MS": { @@ -3012,7 +2866,6 @@ "kind": "exponential", "high": "3000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Time spent on SQLite fsync() (ms)" }, "MOZ_SQLITE_OTHER_SYNC_MAIN_THREAD_MS": { @@ -3020,7 +2873,6 @@ "kind": "exponential", "high": "3000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Time spent on SQLite fsync() (ms)" }, "MOZ_SQLITE_PLACES_SYNC_MS": { @@ -3028,7 +2880,6 @@ "kind": "exponential", "high": "3000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Time spent on SQLite fsync() (ms)" }, "MOZ_SQLITE_PLACES_SYNC_MAIN_THREAD_MS": { @@ -3036,7 +2887,6 @@ "kind": "exponential", "high": "3000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Time spent on SQLite fsync() (ms)" }, "MOZ_SQLITE_COOKIES_SYNC_MS": { @@ -3044,7 +2894,6 @@ "kind": "exponential", "high": "3000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Time spent on SQLite fsync() (ms)" }, "MOZ_SQLITE_COOKIES_SYNC_MAIN_THREAD_MS": { @@ -3052,7 +2901,6 @@ "kind": "exponential", "high": "3000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Time spent on SQLite fsync() (ms)" }, "MOZ_SQLITE_WEBAPPS_SYNC_MS": { @@ -3060,7 +2908,6 @@ "kind": "exponential", "high": "3000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Time spent on SQLite fsync() (ms)" }, "MOZ_SQLITE_WEBAPPS_SYNC_MAIN_THREAD_MS": { @@ -3068,7 +2915,6 @@ "kind": "exponential", "high": "3000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Time spent on SQLite fsync() (ms)" }, "MOZ_SQLITE_OTHER_READ_B": { @@ -3133,7 +2979,6 @@ "kind": "exponential", "high": "32768", "n_buckets": 20, - "extended_statistics_ok": true, "description": "mozStorage async requests completion (ms)" }, "MOZ_STORAGE_ASYNC_REQUESTS_SUCCESS": { @@ -3153,7 +2998,6 @@ "kind": "exponential", "high": "10000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Time spent opening disk cache (ms)" }, "NETWORK_DISK_CACHE_TRASHRENAME": { @@ -3161,7 +3005,6 @@ "kind": "exponential", "high": "10000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Time spent renaming bad Cache to Cache.Trash (ms)" }, "NETWORK_DISK_CACHE_DELETEDIR": { @@ -3169,7 +3012,6 @@ "kind": "exponential", "high": "10000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Time spent deleting disk cache (ms)" }, "NETWORK_DISK_CACHE_DELETEDIR_SHUTDOWN": { @@ -3177,7 +3019,6 @@ "kind": "exponential", "high": "10000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Time spent during showdown stopping thread deleting old disk cache (ms)" }, "NETWORK_DISK_CACHE_SHUTDOWN": { @@ -3185,7 +3026,6 @@ "kind": "exponential", "high": "10000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Total Time spent (ms) during disk cache showdown" }, "NETWORK_DISK_CACHE_SHUTDOWN_V2": { @@ -3193,7 +3033,6 @@ "kind": "exponential", "high": "10000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Total Time spent (ms) during disk cache showdown [cache2]" }, "NETWORK_DISK_CACHE_SHUTDOWN_CLEAR_PRIVATE": { @@ -3201,7 +3040,6 @@ "kind": "exponential", "high": "10000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Time spent (ms) during showdown deleting disk cache for 'clear private data' option" }, "NETWORK_DISK_CACHE2_SHUTDOWN_CLEAR_PRIVATE": { @@ -3209,7 +3047,6 @@ "kind": "exponential", "high": "10000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Time spent (ms) during showdown deleting disk cache v2 for 'clear private data' option" }, "NETWORK_DISK_CACHE_REVALIDATION": { @@ -3217,7 +3054,6 @@ "kind": "exponential", "high": "10000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Total Time spent (ms) during disk cache revalidation" }, "NETWORK_DISK_CACHE_STREAMIO_CLOSE": { @@ -3225,7 +3061,6 @@ "kind": "exponential", "high": "10000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Time spent in nsDiskCacheStreamIO::Close() on non-main thread (ms)" }, "NETWORK_DISK_CACHE_STREAMIO_CLOSE_MAIN_THREAD": { @@ -3233,7 +3068,6 @@ "kind": "exponential", "high": "10000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Time spent in nsDiskCacheStreamIO::Close() on the main thread (ms)" }, "IDLE_NOTIFY_BACK_MS": { @@ -3241,7 +3075,6 @@ "kind": "exponential", "high": "5000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Time spent checking for and notifying listeners that the user is back (ms)" }, "IDLE_NOTIFY_BACK_LISTENERS": { @@ -3256,7 +3089,6 @@ "kind": "exponential", "high": "5000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Time spent checking for and notifying listeners that the user is idle (ms)" }, "IDLE_NOTIFY_IDLE_LISTENERS": { @@ -3271,7 +3103,6 @@ "kind": "exponential", "high": "500", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Time spent per dbservice lookup (ms)" }, "URLCLASSIFIER_CL_CHECK_TIME": { @@ -3279,7 +3110,6 @@ "kind": "exponential", "high": "500", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Time spent per classifier lookup (ms)" }, "URLCLASSIFIER_CL_UPDATE_TIME": { @@ -3288,7 +3118,6 @@ "low": 20, "high": "15000", "n_buckets": 15, - "extended_statistics_ok": true, "description": "Time spent per classifier update (ms)" }, "URLCLASSIFIER_PS_FILELOAD_TIME": { @@ -3296,7 +3125,6 @@ "kind": "exponential", "high": "1000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Time spent loading PrefixSet from file (ms)" }, "URLCLASSIFIER_PS_FALLOCATE_TIME": { @@ -3304,7 +3132,6 @@ "kind": "exponential", "high": "1000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Time spent fallocating PrefixSet (ms)" }, "URLCLASSIFIER_PS_CONSTRUCT_TIME": { @@ -3312,7 +3139,6 @@ "kind": "exponential", "high": "5000", "n_buckets": 15, - "extended_statistics_ok": true, "description": "Time spent constructing PrefixSet from DB (ms)" }, "URLCLASSIFIER_LC_PREFIXES": { @@ -3327,7 +3153,6 @@ "kind": "exponential", "high": "200", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Size of the completion cache in entries" }, "URLCLASSIFIER_PS_FAILURE": { @@ -3341,7 +3166,6 @@ "low": 1000, "high": "150000", "n_buckets": 20, - "extended_statistics_ok": true, "description": "PLACES: Number of unique pages" }, "PLACES_BOOKMARKS_COUNT": { @@ -3350,7 +3174,6 @@ "low": 100, "high": "8000", "n_buckets": 15, - "extended_statistics_ok": true, "description": "PLACES: Number of bookmarks" }, "PLACES_TAGS_COUNT": { @@ -3358,7 +3181,6 @@ "kind": "exponential", "high": "200", "n_buckets": 10, - "extended_statistics_ok": true, "description": "PLACES: Number of tags" }, "PLACES_KEYWORDS_COUNT": { @@ -3366,7 +3188,6 @@ "kind": "exponential", "high": "200", "n_buckets": 10, - "extended_statistics_ok": true, "description": "PLACES: Number of keywords" }, "PLACES_BACKUPS_DAYSFROMLAST": { @@ -3381,7 +3202,6 @@ "low": 50, "high": 2000, "n_buckets": 10, - "extended_statistics_ok": true, "description": "PLACES: Time to build the bookmarks tree" }, "PLACES_BACKUPS_TOJSON_MS": { @@ -3390,7 +3210,6 @@ "low": 50, "high": 2000, "n_buckets": 10, - "extended_statistics_ok": true, "description": "PLACES: Time to convert and write the backup" }, "PLACES_EXPORT_TOHTML_MS": { @@ -3399,7 +3218,6 @@ "low": 50, "high": 2000, "n_buckets": 10, - "extended_statistics_ok": true, "description": "PLACES: Time to convert and write bookmarks.html" }, "PLACES_FAVICON_ICO_SIZES": { @@ -3498,7 +3316,6 @@ "low": 50, "high": 2000, "n_buckets": 10, - "extended_statistics_ok": true, "description": "PLACES: Time to build the bookmarks tree" }, "PLACES_BACKUPS_TOJSON_MS": { @@ -3507,7 +3324,6 @@ "low": 50, "high": 2000, "n_buckets": 10, - "extended_statistics_ok": true, "description": "PLACES: Time to convert and write the backup" }, "FENNEC_FAVICONS_COUNT": { @@ -3516,7 +3332,6 @@ "high": "2000", "n_buckets": 10, "cpp_guard": "ANDROID", - "extended_statistics_ok": true, "description": "Number of favicons stored in the browser DB" }, "FENNEC_THUMBNAILS_COUNT": { @@ -3525,7 +3340,6 @@ "high": "2000", "n_buckets": 10, "cpp_guard": "ANDROID", - "extended_statistics_ok": true, "description": "Number of thumbnails stored in the browser DB" }, "FENNEC_READING_LIST_COUNT": { @@ -3534,7 +3348,6 @@ "high": "1000", "n_buckets": 10, "cpp_guard": "ANDROID", - "extended_statistics_ok": true, "description": "Number of reading list items stored in the browser DB" }, "PLACES_SORTED_BOOKMARKS_PERC": { @@ -3557,7 +3370,6 @@ "low": 5, "high": "200", "n_buckets": 10, - "extended_statistics_ok": true, "description": "PLACES: Database filesize (MB)" }, "PLACES_DATABASE_PAGESIZE_B": { @@ -3566,7 +3378,6 @@ "low": 1024, "high": "32768", "n_buckets": 10, - "extended_statistics_ok": true, "description": "PLACES: Database page size (bytes)" }, "PLACES_DATABASE_SIZE_PER_PAGE_B": { @@ -3575,7 +3386,6 @@ "low": 500, "high": "10240", "n_buckets": 20, - "extended_statistics_ok": true, "description": "PLACES: Average size of a place in the database (bytes)" }, "PLACES_EXPIRATION_STEPS_TO_CLEAN2": { @@ -3590,7 +3400,6 @@ "low": 50, "high": "500", "n_buckets": 10, - "extended_statistics_ok": true, "description": "PLACES: Time for first autocomplete result if > 50ms (ms)" }, "PLACES_AUTOCOMPLETE_6_FIRST_RESULTS_TIME_MS": { @@ -3599,7 +3408,6 @@ "low": 50, "high": "1000", "n_buckets": 30, - "extended_statistics_ok": true, "description": "PLACES: Time for the 6 first autocomplete results (ms)" }, "HISTORY_LASTVISITED_TREE_QUERY_TIME_MS": { @@ -3608,7 +3416,6 @@ "low": 50, "high": "2000", "n_buckets": 30, - "extended_statistics_ok": true, "description": "PLACES: Time to load the sidebar history tree sorted by last visit (ms)" }, "PLACES_HISTORY_LIBRARY_SEARCH_TIME_MS": { @@ -3617,7 +3424,6 @@ "low": 50, "high": "1000", "n_buckets": 30, - "extended_statistics_ok": true, "description": "PLACES: Time to search the history library (ms)" }, "PLACES_AUTOCOMPLETE_URLINLINE_DOMAIN_QUERY_TIME_MS": { @@ -3626,7 +3432,6 @@ "low": 50, "high": 2000, "n_buckets": 10, - "extended_statistics_ok": true, "description": "PLACES: Duration of the domain query for the url inline autocompletion (ms)" }, "PLACES_IDLE_FRECENCY_DECAY_TIME_MS": { @@ -3635,7 +3440,6 @@ "low": 50, "high": "10000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "PLACES: Time to decay all frecencies values on idle (ms)" }, "PLACES_IDLE_MAINTENANCE_TIME_MS": { @@ -3644,7 +3448,6 @@ "low": 1000, "high": "30000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "PLACES: Time to execute maintenance tasks on idle (ms)" }, "PLACES_ANNOS_BOOKMARKS_COUNT": { @@ -3653,7 +3456,6 @@ "low": 50, "high": "5000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "PLACES: Number of bookmarks annotations" }, "PLACES_ANNOS_PAGES_COUNT": { @@ -3662,7 +3464,6 @@ "low": 50, "high": "5000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "PLACES: Number of pages annotations" }, "PLACES_MAINTENANCE_DAYSFROMLAST": { @@ -3959,7 +3760,6 @@ "kind": "exponential", "high": "10000", "n_buckets": 30, - "extended_statistics_ok": true, "description": "Conversations: time between the moment we click and the second gloda query returns (ms)" }, "THUNDERBIRD_INDEXING_RATE_MSG_PER_S": { @@ -4055,6 +3855,15 @@ "bug_numbers": [1221674], "description": "Delay in ms between the target and the actual handling time of the frame at refresh driver in the content process." }, + "FX_REFRESH_DRIVER_SYNC_SCROLL_FRAME_DELAY_MS": { + "alert_emails": ["perf-telemetry-alerts@mozilla.com"], + "expires_in_version": "never", + "kind": "exponential", + "high": "10000", + "n_buckets": 50, + "bug_numbers": [1228147], + "description": "Delay in ms between the target and the actual handling time of the frame at refresh driver while scrolling synchronously." + }, "FX_TAB_SWITCH_UPDATE_MS": { "alert_emails": ["perf-telemetry-alerts@mozilla.com"], "expires_in_version": "40", @@ -4096,7 +3905,6 @@ "kind": "exponential", "high": "1000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Firefox: Time taken by the identity popup to open in milliseconds" }, "FX_BOOKMARKS_TOOLBAR_INIT_MS": { @@ -4105,7 +3913,6 @@ "low": 50, "high": "5000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Firefox: Time to initialize the bookmarks toolbar view (ms)" }, "FX_BROWSER_FULLSCREEN_USED": { @@ -4118,7 +3925,6 @@ "kind": "exponential", "high": "10000", "n_buckets": 20, - "extended_statistics_ok": true, "description": "Firefox: Time taken to open a new browser window (ms)" }, "FX_PAGE_LOAD_MS": { @@ -4126,7 +3932,6 @@ "kind": "exponential", "high": "10000", "n_buckets": 20, - "extended_statistics_ok": true, "description": "Firefox: Time taken to load a page (ms)" }, "FX_TOTAL_TOP_VISITS": { @@ -4139,7 +3944,6 @@ "kind": "exponential", "high": "500", "n_buckets": 15, - "extended_statistics_ok": true, "description": "THUMBNAILS: Time (ms) it takes to capture a thumbnail" }, "FX_THUMBNAILS_STORE_TIME_MS": { @@ -4147,7 +3951,6 @@ "kind": "exponential", "high": "500", "n_buckets": 15, - "extended_statistics_ok": true, "description": "THUMBNAILS: Time (ms) it takes to store a thumbnail in the cache" }, "FX_THUMBNAILS_HIT_OR_MISS": { @@ -4162,7 +3965,6 @@ "low": 50, "high": "60000", "n_buckets": 20, - "extended_statistics_ok": true, "description": "Widget: Time it takes for the message before a UI message (ms)" }, "FX_SESSION_RESTORE_STARTUP_INIT_SESSION_MS": { @@ -4170,7 +3972,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 20, - "extended_statistics_ok": true, "description": "Session restore: Time it takes to prepare the data structures for restoring a session (ms)" }, "FX_SESSION_RESTORE_STARTUP_ONLOAD_INITIAL_WINDOW_MS": { @@ -4178,7 +3979,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 20, - "extended_statistics_ok": true, "description": "Session restore: Time it takes to finish restoration once we have first opened a window (ms)" }, "FX_SESSION_RESTORE_COLLECT_ALL_WINDOWS_DATA_MS": { @@ -4186,7 +3986,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Session restore: Time to collect all window data (ms)" }, "FX_SESSION_RESTORE_COLLECT_COOKIES_MS": { @@ -4194,7 +3993,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Session restore: Time to collect cookies (ms)" }, "FX_SESSION_RESTORE_COLLECT_DATA_MS": { @@ -4202,7 +4000,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Session restore: Time to collect all window and tab data (ms)" }, "FX_SESSION_RESTORE_COLLECT_DATA_LONGEST_OP_MS": { @@ -4210,7 +4007,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Session restore: Duration of the longest uninterruptible operation while collecting all window and tab data (ms)" }, "FX_SESSION_RESTORE_CONTENT_COLLECT_DATA_LONGEST_OP_MS": { @@ -4218,7 +4014,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Session restore: Duration of the longest uninterruptible operation while collecting data in the content process (ms)" }, "FX_SESSION_RESTORE_SERIALIZE_DATA_MS": { @@ -4227,7 +4022,6 @@ "kind": "exponential", "high": "1000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Session restore: Time to JSON serialize session data (ms)" }, "FX_SESSION_RESTORE_READ_FILE_MS": { @@ -4235,7 +4029,6 @@ "kind": "exponential", "high": "3000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Session restore: Time to read the session data from the file on disk (ms)" }, "FX_SESSION_RESTORE_SEND_SERIALIZED_STATE_LONGEST_OP_MS": { @@ -4243,7 +4036,6 @@ "kind": "exponential", "high": "3000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Session restore: Time spent on the main thread sending the session data off the main thread for writing (ms)" }, "FX_SESSION_RESTORE_WRITE_FILE_MS": { @@ -4251,7 +4043,6 @@ "kind": "exponential", "high": "3000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Session restore: Time to write the session data to the file on disk (ms)" }, "FX_SESSION_RESTORE_FILE_SIZE_BYTES": { @@ -4259,7 +4050,6 @@ "kind": "exponential", "high": 50000000, "n_buckets": 30, - "extended_statistics_ok": true, "description": "Session restore: The size of file sessionstore.js (bytes)" }, "FX_SESSION_RESTORE_CORRUPT_FILE": { @@ -4277,7 +4067,6 @@ "kind": "exponential", "high": "3000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Session restore: Time spent blocking the main thread while restoring a window state (ms)" }, "FX_SESSION_RESTORE_SEND_UPDATE_CAUSED_OOM": { @@ -4291,7 +4080,6 @@ "kind": "exponential", "high": "30000000", "n_buckets": 20, - "extended_statistics_ok": true, "description": "Session restore: Number of characters in DOM Storage for a tab. Pages without DOM Storage or with an empty DOM Storage are ignored." }, "FX_TABLETMODE_PAGE_LOAD": { @@ -4470,7 +4258,6 @@ "kind": "exponential", "high": "3000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "DOM: Timer handlers called per native timer expiration" }, "DOM_TIMERS_RECENTLY_SET": { @@ -4478,7 +4265,6 @@ "kind": "exponential", "high": "3000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "DOM: setTimeout/setInterval calls recently (last 30s or more)" }, "DOM_RANGE_DETACHED": { @@ -4496,7 +4282,6 @@ "kind": "exponential", "high": "3000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Time to open the localStorage database (ms)" }, "LOCALDOMSTORAGE_SHUTDOWN_DATABASE_MS": { @@ -4504,7 +4289,6 @@ "kind": "exponential", "high": "3000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Time to flush and close the localStorage database (ms)" }, "LOCALDOMSTORAGE_PRELOAD_PENDING_ON_FIRST_ACCESS": { @@ -4517,7 +4301,6 @@ "kind": "exponential", "high": "3000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Time to block before we return a list of all keys in domain's LocalStorage (ms)" }, "LOCALDOMSTORAGE_GETKEY_BLOCKING_MS": { @@ -4525,7 +4308,6 @@ "kind": "exponential", "high": "3000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Time to block before we return a key name in domain's LocalStorage (ms)" }, "LOCALDOMSTORAGE_GETLENGTH_BLOCKING_MS": { @@ -4533,7 +4315,6 @@ "kind": "exponential", "high": "3000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Time to block before we return number of keys in domain's LocalStorage (ms)" }, "LOCALDOMSTORAGE_GETVALUE_BLOCKING_MS": { @@ -4541,7 +4322,6 @@ "kind": "exponential", "high": "3000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Time to block before we return a value for a key in LocalStorage (ms)" }, "LOCALDOMSTORAGE_SETVALUE_BLOCKING_MS": { @@ -4549,7 +4329,6 @@ "kind": "exponential", "high": "3000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Time to block before we set a single key's value in LocalStorage (ms)" }, "LOCALDOMSTORAGE_REMOVEKEY_BLOCKING_MS": { @@ -4557,7 +4336,6 @@ "kind": "exponential", "high": "3000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Time to block before we remove a single key from LocalStorage (ms)" }, "LOCALDOMSTORAGE_CLEAR_BLOCKING_MS": { @@ -4565,7 +4343,6 @@ "kind": "exponential", "high": "3000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Time to block before we clear LocalStorage for all domains (ms)" }, "LOCALDOMSTORAGE_UNLOAD_BLOCKING_MS": { @@ -4573,7 +4350,6 @@ "kind": "exponential", "high": "3000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Time to fetch LocalStorage data before we can clean the cache (ms)" }, "LOCALDOMSTORAGE_SESSIONONLY_PRELOAD_BLOCKING_MS": { @@ -4581,7 +4357,6 @@ "kind": "exponential", "high": "3000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Time to fetch LocalStorage data before we can expose them as session only data (ms)" }, "LOCALDOMSTORAGE_KEY_SIZE_BYTES": { @@ -4590,7 +4365,6 @@ "low": 1024, "high": "32768", "n_buckets": 10, - "extended_statistics_ok": true, "description": "DOM storage: size of keys stored in localStorage" }, "LOCALDOMSTORAGE_VALUE_SIZE_BYTES": { @@ -4599,7 +4373,6 @@ "low": 1024, "high": "32768", "n_buckets": 10, - "extended_statistics_ok": true, "description": "DOM storage: size of values stored in localStorage" }, "SESSIONDOMSTORAGE_KEY_SIZE_BYTES": { @@ -4608,7 +4381,6 @@ "low": 1024, "high": "32768", "n_buckets": 10, - "extended_statistics_ok": true, "description": "DOM storage: size of keys stored in sessionStorage" }, "SESSIONDOMSTORAGE_VALUE_SIZE_BYTES": { @@ -4617,7 +4389,6 @@ "low": 1024, "high": "32768", "n_buckets": 10, - "extended_statistics_ok": true, "description": "DOM storage: size of values stored in sessionStorage" }, "RANGE_CHECKSUM_ERRORS": { @@ -4626,7 +4397,6 @@ "kind": "exponential", "high": "3000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Number of histograms with range checksum errors" }, "BUCKET_ORDER_ERRORS": { @@ -4635,7 +4405,6 @@ "kind": "exponential", "high": "3000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Number of histograms with bucket order errors" }, "TOTAL_COUNT_HIGH_ERRORS": { @@ -4644,7 +4413,6 @@ "kind": "exponential", "high": "3000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Number of histograms with total count high errors" }, "TOTAL_COUNT_LOW_ERRORS": { @@ -4653,7 +4421,6 @@ "kind": "exponential", "high": "3000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Number of histograms with total count low errors" }, "TELEMETRY_ARCHIVE_DIRECTORIES_COUNT": { @@ -4849,7 +4616,6 @@ "kind": "exponential", "high": "3000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Time taken to compress telemetry object (ms)" }, "TELEMETRY_PING": { @@ -4857,7 +4623,6 @@ "kind": "exponential", "high": "3000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Time taken to submit telemetry info (ms)" }, "TELEMETRY_SEND" : { @@ -4865,7 +4630,6 @@ "kind": "exponential", "high": "3000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Time to send the compressed string to the Telemetry servers and get a reply back (ms)" }, "TELEMETRY_STRINGIFY" : { @@ -4873,7 +4637,6 @@ "kind": "exponential", "high": "3000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Time to stringify telemetry object (ms)" }, "TELEMETRY_SUCCESS": { @@ -4928,6 +4691,17 @@ "kind": "count", "description": "a testing histogram; not meant to be touched" }, + "TELEMETRY_TEST_COUNT_INIT_NO_RECORD": { + "expires_in_version": "never", + "kind": "count", + "description": "a testing histogram; not meant to be touched - initially not recording" + }, + "TELEMETRY_TEST_KEYED_COUNT_INIT_NO_RECORD": { + "expires_in_version": "never", + "kind": "count", + "keyed": true, + "description": "a testing histogram; not meant to be touched - initially not recording" + }, "TELEMETRY_TEST_KEYED_FLAG": { "expires_in_version": "never", "kind": "flag", @@ -5012,7 +4786,6 @@ "kind": "exponential", "high": "100", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Number of sites blocked from the new tab page." }, "NEWTAB_PAGE_SHOWN": { @@ -5031,7 +4804,6 @@ "kind": "exponential", "high": "10000", "n_buckets": 15, - "extended_statistics_ok": true, "description": "Time it takes to initialize Panorama (ms)" }, "PANORAMA_GROUPS_COUNT": { @@ -5039,7 +4811,6 @@ "kind": "exponential", "high": "25", "n_buckets": 15, - "extended_statistics_ok": true, "description": "Number of groups in Panorama" }, "PANORAMA_STACKED_GROUPS_COUNT": { @@ -5047,7 +4818,6 @@ "kind": "exponential", "high": "25", "n_buckets": 15, - "extended_statistics_ok": true, "description": "Number of stacked groups in Panorama" }, "PANORAMA_MEDIAN_TABS_IN_GROUPS_COUNT": { @@ -5055,7 +4825,6 @@ "kind": "exponential", "high": "100", "n_buckets": 15, - "extended_statistics_ok": true, "description": "Median of tabs in groups in Panorama" }, "BROWSERPROVIDER_XUL_IMPORT_TIME": { @@ -5064,7 +4833,6 @@ "low": 20, "high": "600000", "n_buckets": 20, - "extended_statistics_ok": true, "description": "Time for the initial conversion of a XUL places database (ms)", "cpp_guard": "ANDROID" }, @@ -5073,7 +4841,6 @@ "kind": "exponential", "high": "50000", "n_buckets": 20, - "extended_statistics_ok": true, "description": "Number of bookmarks in the original XUL places database", "cpp_guard": "ANDROID" }, @@ -5082,7 +4849,6 @@ "kind": "exponential", "high": "1000000", "n_buckets": 20, - "extended_statistics_ok": true, "description": "Number of history entries in the original XUL places database", "cpp_guard": "ANDROID" }, @@ -5227,7 +4993,6 @@ "kind": "exponential", "high": "1000", "n_buckets": 15, - "extended_statistics_ok": true, "description": "Time (ms) it takes to initialize the search service" }, "SEARCH_SERVICE_INIT_SYNC": { @@ -5241,7 +5006,6 @@ "kind": "exponential", "high": "1000", "n_buckets": 15, - "extended_statistics_ok": true, "description": "Time (ms) it takes to build the cache of the search service" }, "SEARCH_SERVICE_COUNTRY_FETCH_TIME_MS": { @@ -5333,7 +5097,6 @@ "kind": "exponential", "high": "5000", "n_buckets": 15, - "extended_statistics_ok": true, "description": "Time (ms) it takes to figure out extension last modified time" }, "TELEMETRY_MEMORY_REPORTER_MS": { @@ -5342,7 +5105,6 @@ "kind": "exponential", "high": "5000", "n_buckets": 10, - "extended_statistics_ok": true, "description": "Time (ms) it takes to run memory reporters when sending a telemetry ping" }, "SSL_SUCCESFUL_CERT_VALIDATION_TIME_MOZILLAPKIX" : { @@ -5350,7 +5112,6 @@ "kind": "exponential", "high": "60000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "Time spent on a successful cert verification in mozilla::pkix mode (ms)" }, "SSL_INITIAL_FAILED_CERT_VALIDATION_TIME_MOZILLAPKIX" : { @@ -5358,7 +5119,6 @@ "kind": "exponential", "high": "60000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "Time spent on an initially failed cert verification in mozilla::pkix mode (ms)" }, "HEALTHREPORT_DB_OPEN_FIRSTRUN_MS": { @@ -5387,7 +5147,6 @@ "kind": "exponential", "high": "20000", "n_buckets": 15, - "extended_statistics_ok": true, "description": "Time (ms) spent to initialize Firefox Health Report service." }, "HEALTHREPORT_GENERATE_JSON_PAYLOAD_MS": { @@ -5395,7 +5154,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 20, - "extended_statistics_ok": true, "description": "Time (ms) it takes to obtain and format a Health Report JSON payload." }, "HEALTHREPORT_JSON_PAYLOAD_SERIALIZE_MS": { @@ -5424,7 +5182,6 @@ "kind": "exponential", "high": "60000", "n_buckets": 20, - "extended_statistics_ok": true, "description": "Time (ms) it takes to upload the Health Report payload." }, "HEALTHREPORT_COLLECT_CONSTANT_DATA_MS": { @@ -7382,7 +7139,6 @@ "kind": "exponential", "high": 100, "n_buckets": 15, - "extended_statistics_ok": true, "description": "BACKGROUND THUMBNAILS: Size of capture queue when a capture request is received" }, "FX_THUMBNAILS_BG_CAPTURE_QUEUE_TIME_MS": { @@ -7390,7 +7146,6 @@ "kind": "exponential", "high": 300000, "n_buckets": 20, - "extended_statistics_ok": true, "description": "BACKGROUND THUMBNAILS: Time the capture request spent in the queue before being serviced (ms)" }, "FX_THUMBNAILS_BG_CAPTURE_SERVICE_TIME_MS": { @@ -7398,7 +7153,6 @@ "kind": "exponential", "high": 30000, "n_buckets": 20, - "extended_statistics_ok": true, "description": "BACKGROUND THUMBNAILS: Time the capture took once it started and successfully completed (ms)" }, "FX_THUMBNAILS_BG_CAPTURE_DONE_REASON_2": { @@ -7412,7 +7166,6 @@ "kind": "exponential", "high": 60000, "n_buckets": 20, - "extended_statistics_ok": true, "description": "BACKGROUND THUMBNAILS: Time the capture's page load took (ms)" }, "FX_THUMBNAILS_BG_CAPTURE_CANVAS_DRAW_TIME_MS": { @@ -7420,7 +7173,6 @@ "kind": "exponential", "high": 500, "n_buckets": 15, - "extended_statistics_ok": true, "description": "BACKGROUND THUMBNAILS: Time it took to draw the capture's window to canvas (ms)" }, "NETWORK_CACHE_V2_MISS_TIME_MS": { @@ -7428,7 +7180,6 @@ "kind": "exponential", "high": "10000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "Time spent to find out a cache entry file is missing" }, "NETWORK_CACHE_V2_HIT_TIME_MS": { @@ -7436,7 +7187,6 @@ "kind": "exponential", "high": "10000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "Time spent to open an existing file" }, "NETWORK_CACHE_V1_TRUNCATE_TIME_MS": { @@ -7444,7 +7194,6 @@ "kind": "exponential", "high": "10000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "Time spent to reopen an entry with OPEN_TRUNCATE" }, "NETWORK_CACHE_V1_MISS_TIME_MS": { @@ -7452,7 +7201,6 @@ "kind": "exponential", "high": "10000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "Time spent to find out a cache entry is missing" }, "NETWORK_CACHE_V1_HIT_TIME_MS": { @@ -7460,7 +7208,6 @@ "kind": "exponential", "high": "10000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "Time spent to open an existing cache entry" }, "NETWORK_CACHE_V2_OUTPUT_STREAM_STATUS": { @@ -7505,7 +7252,6 @@ "kind": "exponential", "high": "10000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "Time spent to read the first part of the metadata from the cache entry file." }, "NETWORK_CACHE_METADATA_SECOND_READ_TIME_MS": { @@ -7513,7 +7259,6 @@ "kind": "exponential", "high": "10000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "Time spent to read the missing part of the metadata from the cache entry file." }, "NETWORK_CACHE_METADATA_FIRST_READ_SIZE": { @@ -7775,24 +7520,21 @@ "kind": "exponential", "description": "The duration between the instant the first message is sent to OS.File and the moment the OS.File worker starts executing JavaScript, in milliseconds", "high": "5000", - "n_buckets": 10, - "extended_statistics_ok": true + "n_buckets": 10 }, "OSFILE_WORKER_READY_MS": { "expires_in_version": "default", "kind": "exponential", "description": "The duration between the instant the first message is sent to OS.File and the moment the OS.File worker has finished executing its startup JavaScript and is ready to receive requests, in milliseconds", "high": "5000", - "n_buckets": 10, - "extended_statistics_ok": true + "n_buckets": 10 }, "OSFILE_WRITEATOMIC_JANK_MS": { "expires_in_version": "default", "kind": "exponential", "description": "The duration during which the main thread is blocked during a call to OS.File.writeAtomic, in milliseconds", "high": "5000", - "n_buckets": 10, - "extended_statistics_ok": true + "n_buckets": 10 }, "CERT_VALIDATION_SUCCESS_BY_CA": { "expires_in_version": "never", @@ -8111,7 +7853,6 @@ "kind": "exponential", "high": "10000", "n_buckets": 20, - "extended_statistics_ok": true, "keyed": true, "description": "Time (ms) that the main thread has been blocked on LoadModule and NP_Initialize in PluginModuleParent" }, @@ -8120,7 +7861,6 @@ "kind": "exponential", "high": "10000", "n_buckets": 20, - "extended_statistics_ok": true, "keyed": true, "description": "Time (ms) that the main thread has been blocked on NPP_New in an IPC plugin" }, @@ -8129,7 +7869,6 @@ "kind": "exponential", "high": "10000", "n_buckets": 20, - "extended_statistics_ok": true, "keyed": true, "description": "Time (ms) that the main thread has been blocked on NPP_NewStream in an IPC plugin" }, @@ -8138,7 +7877,6 @@ "kind": "exponential", "high": "10000", "n_buckets": 20, - "extended_statistics_ok": true, "keyed": true, "description": "Time (ms) that the main thread has been blocked on PluginAsyncSurrogate::WaitForInit in an IPC plugin" }, @@ -8147,7 +7885,6 @@ "kind": "exponential", "high": "10000", "n_buckets": 20, - "extended_statistics_ok": true, "keyed": true, "description": "Time (ms) that the main thread has been blocked on NPP_Destroy in an IPC plugin" }, @@ -8294,7 +8031,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 20, - "extended_statistics_ok": true, "description": "Sanitize: Total time it takes to sanitize (ms)" }, "FX_SANITIZE_CACHE": { @@ -8303,7 +8039,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 20, - "extended_statistics_ok": true, "description": "Sanitize: Time it takes to sanitize the cache (ms)" }, "FX_SANITIZE_COOKIES": { @@ -8312,7 +8047,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 20, - "extended_statistics_ok": true, "description": "Sanitize: Time it takes to sanitize cookies (ms)" }, "FX_SANITIZE_OFFLINEAPPS": { @@ -8321,7 +8055,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 20, - "extended_statistics_ok": true, "description": "Sanitize: Time it takes to sanitize stored offline app data (ms)" }, "FX_SANITIZE_HISTORY": { @@ -8330,7 +8063,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 20, - "extended_statistics_ok": true, "description": "Sanitize: Time it takes to sanitize history (ms)" }, "FX_SANITIZE_FORMDATA": { @@ -8339,7 +8071,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 20, - "extended_statistics_ok": true, "description": "Sanitize: Time it takes to sanitize stored form data (ms)" }, "FX_SANITIZE_DOWNLOADS": { @@ -8348,7 +8079,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 20, - "extended_statistics_ok": true, "description": "Sanitize: Time it takes to sanitize recent downloads (ms)" }, "FX_SANITIZE_SESSIONS": { @@ -8357,7 +8087,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 20, - "extended_statistics_ok": true, "description": "Sanitize: Time it takes to sanitize saved sessions (ms)" }, "FX_SANITIZE_SITESETTINGS": { @@ -8366,7 +8095,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 20, - "extended_statistics_ok": true, "description": "Sanitize: Time it takes to sanitize site-specific settings (ms)" }, "FX_SANITIZE_OPENWINDOWS": { @@ -8375,7 +8103,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 20, - "extended_statistics_ok": true, "description": "Sanitize: Time it takes to sanitize the open windows list (ms)" }, "MEDIA_CODEC_USED": { @@ -8391,7 +8118,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 20, - "extended_statistics_ok": true, "description": "Sanitize: Total time it takes to sanitize (ms)" }, "FX_SANITIZE_CACHE": { @@ -8400,7 +8126,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 20, - "extended_statistics_ok": true, "description": "Sanitize: Time it takes to sanitize the cache (ms)" }, "FX_SANITIZE_COOKIES": { @@ -8409,7 +8134,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 20, - "extended_statistics_ok": true, "description": "Sanitize: Time it takes to sanitize cookies (ms)" }, "FX_SANITIZE_COOKIES_2": { @@ -8418,7 +8142,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 20, - "extended_statistics_ok": true, "description": "Sanitize: Time it takes to sanitize firefox cookies (ms). A subset of FX_SANITIZE_COOKIES." }, "FX_SANITIZE_PLUGINS": { @@ -8427,7 +8150,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 20, - "extended_statistics_ok": true, "description": "Sanitize: Time it takes to sanitize plugin cookies (ms). A subset of FX_SANITIZE_COOKIES." }, "FX_SANITIZE_OFFLINEAPPS": { @@ -8436,7 +8158,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 20, - "extended_statistics_ok": true, "description": "Sanitize: Time it takes to sanitize stored offline app data (ms)" }, "FX_SANITIZE_HISTORY": { @@ -8445,7 +8166,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 20, - "extended_statistics_ok": true, "description": "Sanitize: Time it takes to sanitize history (ms)" }, "FX_SANITIZE_FORMDATA": { @@ -8454,7 +8174,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 20, - "extended_statistics_ok": true, "description": "Sanitize: Time it takes to sanitize stored form data (ms)" }, "FX_SANITIZE_DOWNLOADS": { @@ -8463,7 +8182,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 20, - "extended_statistics_ok": true, "description": "Sanitize: Time it takes to sanitize recent downloads (ms)" }, "FX_SANITIZE_SESSIONS": { @@ -8472,7 +8190,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 20, - "extended_statistics_ok": true, "description": "Sanitize: Time it takes to sanitize saved sessions (ms)" }, "FX_SANITIZE_SITESETTINGS": { @@ -8481,7 +8198,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 20, - "extended_statistics_ok": true, "description": "Sanitize: Time it takes to sanitize site-specific settings (ms)" }, "FX_SANITIZE_OPENWINDOWS": { @@ -8490,7 +8206,6 @@ "kind": "exponential", "high": "30000", "n_buckets": 20, - "extended_statistics_ok": true, "description": "Sanitize: Time it takes to sanitize the open windows list (ms)" }, "PWMGR_BLOCKLIST_NUM_SITES": { @@ -8498,7 +8213,6 @@ "kind": "exponential", "high": 100, "n_buckets" : 10, - "extended_statistics_ok": true, "description": "The number of sites for which the user has explicitly rejected saving logins" }, "PWMGR_FORM_ACTION_EFFECT": { @@ -8570,7 +8284,6 @@ "kind": "exponential", "high": 750, "n_buckets" : 50, - "extended_statistics_ok": true, "description": "Total number of saved logins, including those that cannot be decrypted" }, "PWMGR_NUM_HTTPAUTH_PASSWORDS": { @@ -9420,7 +9133,6 @@ "kind": "exponential", "high": "60000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "Time to download a webfont (ms)" }, "WEBFONT_DOWNLOAD_TIME_AFTER_START": { @@ -9429,7 +9141,6 @@ "kind": "exponential", "high": "60000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "Time after navigationStart webfont download completed (ms)" }, "WEBFONT_FONTTYPE": { @@ -9458,7 +9169,6 @@ "kind": "exponential", "high": "5000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "Size of all fonts loaded at page load (kb)" }, "WEBFONT_SIZE": { @@ -9467,7 +9177,6 @@ "kind": "exponential", "high": "5000", "n_buckets": 50, - "extended_statistics_ok": true, "description": "Size of font loaded (kb)" }, "WEBFONT_COMPRESSION_WOFF": { diff --git a/toolkit/components/telemetry/Telemetry.cpp b/toolkit/components/telemetry/Telemetry.cpp index 9d1689a334..908faf32e0 100644 --- a/toolkit/components/telemetry/Telemetry.cpp +++ b/toolkit/components/telemetry/Telemetry.cpp @@ -11,6 +11,7 @@ #include #include "mozilla/dom/ToJSValue.h" +#include "mozilla/Atomics.h" #include "mozilla/Attributes.h" #include "mozilla/DebugOnly.h" #include "mozilla/Likely.h" @@ -840,6 +841,9 @@ public: nsresult GetJSSnapshot(JSContext* cx, JS::Handle obj, bool subsession, bool clearSubsession); + void SetRecordingEnabled(bool aEnabled) { mRecordingEnabled = aEnabled; }; + bool IsRecordingEnabled() const { return mRecordingEnabled; }; + nsresult Add(const nsCString& key, uint32_t aSample); void Clear(bool subsession); @@ -862,6 +866,7 @@ private: const uint32_t mMax; const uint32_t mBucketCount; const uint32_t mDataset; + mozilla::Atomic mRecordingEnabled; }; // Hardcoded probes @@ -873,7 +878,6 @@ struct TelemetryHistogram { uint32_t id_offset; uint32_t expiration_offset; uint32_t dataset; - bool extendedStatisticsOK; bool keyed; const char *id() const; @@ -895,6 +899,31 @@ TelemetryHistogram::expiration() const return &gHistogramStringTable[this->expiration_offset]; } +bool +IsHistogramEnumId(Telemetry::ID aID) +{ + static_assert(((Telemetry::ID)-1 > 0), "ID should be unsigned."); + return aID < Telemetry::HistogramCount; +} + +// List of histogram IDs which should have recording disabled initially. +const Telemetry::ID kRecordingInitiallyDisabledIDs[] = { + Telemetry::FX_REFRESH_DRIVER_SYNC_SCROLL_FRAME_DELAY_MS, + + // The array must not be empty. Leave these item here. + Telemetry::TELEMETRY_TEST_COUNT_INIT_NO_RECORD, + Telemetry::TELEMETRY_TEST_KEYED_COUNT_INIT_NO_RECORD +}; + +void +InitHistogramRecordingEnabled() +{ + const size_t length = mozilla::ArrayLength(kRecordingInitiallyDisabledIDs); + for (size_t i = 0; i < length; i++) { + SetHistogramRecordingEnabled(kRecordingInitiallyDisabledIDs[i], false); + } +} + bool IsExpired(const char *expiration){ static Version current_version = Version(MOZ_APP_VERSION); @@ -1057,9 +1086,6 @@ GetHistogramByEnumId(Telemetry::ID id, Histogram **ret) } #endif - if (p.extendedStatisticsOK) { - h->SetFlags(Histogram::kExtendedStatisticsFlag); - } *ret = knownHistograms[id] = h; return NS_OK; } @@ -1142,7 +1168,7 @@ nsresult HistogramAdd(Histogram& histogram, int32_t value, uint32_t dataset) { // Check if we are allowed to record the data. - if (!CanRecordDataset(dataset)) { + if (!CanRecordDataset(dataset) || !histogram.IsRecordingEnabled()) { return NS_OK; } @@ -1207,12 +1233,7 @@ ReflectHistogramAndSamples(JSContext *cx, JS::Handle obj, Histogram * return REFLECT_FAILURE; } - if (h->histogram_type() == Histogram::HISTOGRAM) { - if (!(JS_DefineProperty(cx, obj, "log_sum", ss.log_sum(), JSPROP_ENUMERATE) - && JS_DefineProperty(cx, obj, "log_sum_squares", ss.log_sum_squares(), JSPROP_ENUMERATE))) { - return REFLECT_FAILURE; - } - } else { + if (h->histogram_type() != Histogram::HISTOGRAM) { // Export |sum_squares| as two separate 32-bit properties so that we // can accurately reconstruct it on the analysis side. uint64_t sum_squares = ss.sum_squares(); @@ -1925,6 +1946,11 @@ mFailedLockCount(0) mKeyedHistograms.Put(id, new KeyedHistogram(id, expiration, h.histogramType, h.min, h.max, h.bucketCount, h.dataset)); } + + // Setup of the initial recording-enabled state (for not-recording-by-default + // histograms) using InitHistogramRecordingEnabled() will happen after instantiating + // sTelemetry since it depends on the static GetKeyedHistogramById(...) - which + // uses the singleton instance at sTelemetry. } TelemetryImpl::~TelemetryImpl() { @@ -1951,7 +1977,6 @@ TelemetryImpl::NewHistogram(const nsACString &name, const nsACString &expiration if (NS_FAILED(rv)) return rv; h->ClearFlags(Histogram::kUmaTargetedHistogramFlag); - h->SetFlags(Histogram::kExtendedStatisticsFlag); return WrapAndReturnHistogram(h, cx, ret); } @@ -2266,6 +2291,25 @@ TelemetryImpl::UnregisterAddonHistograms(const nsACString &id) return NS_OK; } +NS_IMETHODIMP +TelemetryImpl::SetHistogramRecordingEnabled(const nsACString &id, bool aEnabled) +{ + Histogram *h; + nsresult rv = GetHistogramByName(id, &h); + if (NS_SUCCEEDED(rv)) { + h->SetRecordingEnabled(aEnabled); + return NS_OK; + } + + KeyedHistogram* keyed = GetKeyedHistogramById(id); + if (keyed) { + keyed->SetRecordingEnabled(aEnabled); + return NS_OK; + } + + return NS_ERROR_FAILURE; +} + nsresult TelemetryImpl::CreateHistogramSnapshots(JSContext *cx, JS::MutableHandle ret, @@ -2873,10 +2917,8 @@ CreateJSTimeHistogram(JSContext* cx, const Telemetry::TimeHistogram& time) JSPROP_ENUMERATE)) { return nullptr; } - // TODO: calculate "sum", "log_sum", and "log_sum_squares" - if (!JS_DefineProperty(cx, ret, "sum", 0, JSPROP_ENUMERATE) || - !JS_DefineProperty(cx, ret, "log_sum", 0.0, JSPROP_ENUMERATE) || - !JS_DefineProperty(cx, ret, "log_sum_squares", 0.0, JSPROP_ENUMERATE)) { + // TODO: calculate "sum" + if (!JS_DefineProperty(cx, ret, "sum", 0, JSPROP_ENUMERATE)) { return nullptr; } @@ -3306,6 +3348,7 @@ TelemetryImpl::CreateTelemetryInstance() nsCOMPtr ret = sTelemetry; sTelemetry->InitMemoryReporter(); + InitHistogramRecordingEnabled(); // requires sTelemetry to exist return ret.forget(); } @@ -3796,6 +3839,34 @@ RecordShutdownEndTimeStamp() { namespace Telemetry { +// The external API for controlling recording state +void +SetHistogramRecordingEnabled(ID aID, bool aEnabled) +{ + if (!IsHistogramEnumId(aID)) { + MOZ_ASSERT(false, "Telemetry::SetHistogramRecordingEnabled(...) must be used with an enum id"); + return; + } + + if (gHistograms[aID].keyed) { + const nsDependentCString id(gHistograms[aID].id()); + KeyedHistogram* keyed = TelemetryImpl::GetKeyedHistogramById(id); + if (keyed) { + keyed->SetRecordingEnabled(aEnabled); + return; + } + } else { + Histogram *h; + nsresult rv = GetHistogramByEnumId(aID, &h); + if (NS_SUCCEEDED(rv)) { + h->SetRecordingEnabled(aEnabled); + return; + } + } + + MOZ_ASSERT(false, "Telemetry::SetHistogramRecordingEnabled(...) id not found"); +} + void Accumulate(ID aHistogram, uint32_t aSample) { @@ -4282,6 +4353,7 @@ KeyedHistogram::KeyedHistogram(const nsACString &name, const nsACString &expirat , mMax(max) , mBucketCount(bucketCount) , mDataset(dataset) + , mRecordingEnabled(true) { } @@ -4319,7 +4391,6 @@ KeyedHistogram::GetHistogram(const nsCString& key, Histogram** histogram, } h->ClearFlags(Histogram::kUmaTargetedHistogramFlag); - h->SetFlags(Histogram::kExtendedStatisticsFlag); *histogram = h; entry = map.PutEntry(key); @@ -4369,6 +4440,10 @@ KeyedHistogram::Add(const nsCString& key, uint32_t sample) } #endif + if (!IsRecordingEnabled()) { + return NS_OK; + } + histogram->Add(sample); #if !defined(MOZ_WIDGET_GONK) && !defined(MOZ_WIDGET_ANDROID) subsession->Add(sample); diff --git a/toolkit/components/telemetry/Telemetry.h b/toolkit/components/telemetry/Telemetry.h index 9c7bc3b8c6..1b16d0ed74 100644 --- a/toolkit/components/telemetry/Telemetry.h +++ b/toolkit/components/telemetry/Telemetry.h @@ -83,6 +83,16 @@ void Accumulate(const char *name, const nsCString& key, uint32_t sample = 1); */ void AccumulateTimeDelta(ID id, TimeStamp start, TimeStamp end = TimeStamp::Now()); +/** + * Enable/disable recording for this histogram at runtime. + * Recording is enabled by default, unless listed at kRecordingInitiallyDisabledIDs[]. + * id must be a valid telemetry enum, otherwise an assertion is triggered. + * + * @param id - histogram id + * @param enabled - whether or not to enable recording from now on. + */ +void SetHistogramRecordingEnabled(ID id, bool enabled); + /** * Return a raw Histogram for direct manipulation for users who can not use Accumulate(). */ diff --git a/toolkit/components/telemetry/TelemetrySession.jsm b/toolkit/components/telemetry/TelemetrySession.jsm index 3bfe9b6def..25148d2ceb 100644 --- a/toolkit/components/telemetry/TelemetrySession.jsm +++ b/toolkit/components/telemetry/TelemetrySession.jsm @@ -585,7 +585,6 @@ var Impl = { * with the following properties: * * - min, max, histogram_type, sum, sum_squares_{lo,hi}: simple integers; - * - log_sum, log_sum_squares: doubles; * - counts: array of counts for histogram buckets; * - ranges: array of calculated bucket sizes. * @@ -598,7 +597,6 @@ var Impl = { * histogram_type: , sum: , * sum_squares_lo: , * sum_squares_hi: , - * log_sum: , log_sum_squares: , * values: { bucket1: count1, bucket2: count2, ... } } */ packHistogram: function packHistogram(hgram) { @@ -612,10 +610,7 @@ var Impl = { sum: hgram.sum }; - if (hgram.histogram_type == Telemetry.HISTOGRAM_EXPONENTIAL) { - retgram.log_sum = hgram.log_sum; - retgram.log_sum_squares = hgram.log_sum_squares; - } else { + if (hgram.histogram_type != Telemetry.HISTOGRAM_EXPONENTIAL) { retgram.sum_squares_lo = hgram.sum_squares_lo; retgram.sum_squares_hi = hgram.sum_squares_hi; } diff --git a/toolkit/components/telemetry/gen-histogram-data.py b/toolkit/components/telemetry/gen-histogram-data.py index cdaf481222..f160501d4d 100644 --- a/toolkit/components/telemetry/gen-histogram-data.py +++ b/toolkit/components/telemetry/gen-histogram-data.py @@ -60,11 +60,10 @@ def print_array_entry(histogram, name_index, exp_index): cpp_guard = histogram.cpp_guard() if cpp_guard: print "#if defined(%s)" % cpp_guard - print " { %s, %s, %s, %s, %d, %d, %s, %s, %s }," \ + print " { %s, %s, %s, %s, %d, %d, %s, %s }," \ % (histogram.low(), histogram.high(), histogram.n_buckets(), histogram.nsITelemetry_kind(), name_index, exp_index, histogram.dataset(), - "true" if histogram.extended_statistics_ok() else "false", "true" if histogram.keyed() else "false") if cpp_guard: print "#endif" diff --git a/toolkit/components/telemetry/histogram_tools.py b/toolkit/components/telemetry/histogram_tools.py index 21d3b300e7..4df7c513f9 100644 --- a/toolkit/components/telemetry/histogram_tools.py +++ b/toolkit/components/telemetry/histogram_tools.py @@ -109,7 +109,6 @@ symbol that should guard C/C++ definitions associated with the histogram.""" self._kind = definition['kind'] self._cpp_guard = definition.get('cpp_guard') self._keyed = definition.get('keyed', False) - self._extended_statistics_ok = definition.get('extended_statistics_ok', False) self._expiration = definition.get('expires_in_version') self.compute_bucket_parameters(definition) table = { 'boolean': 'BOOLEAN', @@ -177,11 +176,6 @@ associated with the histogram. Returns None if no guarding is necessary.""" """Returns the dataset this histogram belongs into.""" return self._dataset - def extended_statistics_ok(self): - """Return True if gathering extended statistics for this histogram -is enabled.""" - return self._extended_statistics_ok - def ranges(self): """Return an array of lower bounds for each bucket in the histogram.""" table = { 'boolean': linear_buckets, @@ -215,7 +209,7 @@ is enabled.""" 'count': always_allowed_keys, 'enumerated': always_allowed_keys + ['n_values'], 'linear': general_keys, - 'exponential': general_keys + ['extended_statistics_ok'] + 'exponential': general_keys } table_dispatch(definition['kind'], table, lambda allowed_keys: Histogram.check_keys(name, definition, allowed_keys)) diff --git a/toolkit/components/telemetry/nsITelemetry.idl b/toolkit/components/telemetry/nsITelemetry.idl index 0c0a4db5ef..e2b58b82a7 100644 --- a/toolkit/components/telemetry/nsITelemetry.idl +++ b/toolkit/components/telemetry/nsITelemetry.idl @@ -12,7 +12,7 @@ interface nsIFetchTelemetryDataCallback : nsISupports void complete(); }; -[scriptable, uuid(fabde631-c128-41c3-b7cb-9eb96f1276ff)] +[scriptable, uuid(273d2dd0-6c63-475a-b864-cb65160a1909)] interface nsITelemetry : nsISupports { /** @@ -327,6 +327,16 @@ interface nsITelemetry : nsISupports */ void unregisterAddonHistograms(in ACString addon_id); + /** + * Enable/disable recording for this histogram at runtime. + * Recording is enabled by default, unless listed at kRecordingInitiallyDisabledIDs[]. + * Name must be a valid Histogram identifier, otherwise an assertion will be triggered. + * + * @param id - unique identifier from histograms.json + * @param enabled - whether or not to enable recording from now on. + */ + void setHistogramRecordingEnabled(in ACString id, in boolean enabled); + /** * An object containing a snapshot from all of the currently * registered addon histograms. diff --git a/toolkit/components/telemetry/tests/unit/test_TelemetryStopwatch.js b/toolkit/components/telemetry/tests/unit/test_TelemetryStopwatch.js index 5b6e810ef1..65e860be06 100644 --- a/toolkit/components/telemetry/tests/unit/test_TelemetryStopwatch.js +++ b/toolkit/components/telemetry/tests/unit/test_TelemetryStopwatch.js @@ -24,11 +24,11 @@ let originalCount1, originalCount2; function run_test() { let histogram = Telemetry.getHistogramById(HIST_NAME); let snapshot = histogram.snapshot(); - originalCount1 = snapshot.counts.reduce(function (a,b) a += b); + originalCount1 = snapshot.counts.reduce((a,b) => a += b); histogram = Telemetry.getHistogramById(HIST_NAME2); snapshot = histogram.snapshot(); - originalCount2 = snapshot.counts.reduce(function (a,b) a += b); + originalCount2 = snapshot.counts.reduce((a,b) => a += b); do_check_false(TelemetryStopwatch.start(3)); do_check_false(TelemetryStopwatch.start({})); @@ -110,13 +110,13 @@ function run_test() { function finishTest() { let histogram = Telemetry.getHistogramById(HIST_NAME); let snapshot = histogram.snapshot(); - let newCount = snapshot.counts.reduce(function (a,b) a += b); + let newCount = snapshot.counts.reduce((a,b) => a += b); do_check_eq(newCount - originalCount1, 5, "The correct number of histograms were added for histogram 1."); histogram = Telemetry.getHistogramById(HIST_NAME2); snapshot = histogram.snapshot(); - newCount = snapshot.counts.reduce(function (a,b) a += b); + newCount = snapshot.counts.reduce((a,b) => a += b); do_check_eq(newCount - originalCount2, 3, "The correct number of histograms were added for histogram 2."); } diff --git a/toolkit/components/telemetry/tests/unit/test_nsITelemetry.js b/toolkit/components/telemetry/tests/unit/test_nsITelemetry.js index b12834cf78..373194cf2b 100644 --- a/toolkit/components/telemetry/tests/unit/test_nsITelemetry.js +++ b/toolkit/components/telemetry/tests/unit/test_nsITelemetry.js @@ -32,35 +32,21 @@ function test_histogram(histogram_type, name, min, max, bucket_count) { var h = Telemetry.newHistogram(name, "never", histogram_type, min, max, bucket_count); var r = h.snapshot().ranges; var sum = 0; - var log_sum = 0; - var log_sum_squares = 0; for(var i=0;i register(addon_id, name1, Telemetry.HISTOGRAM_LINEAR, 1, 5, 6)); // Can't register the same histogram multiple times. - expect_fail(function () - register(addon_id, name1, Telemetry.HISTOGRAM_LINEAR, 1, 5, 6)); + expect_fail(() => + register(addon_id, name1, Telemetry.HISTOGRAM_LINEAR, 1, 5, 6)); // Make sure we can't get at it with another name. - expect_fail(function () Telemetry.getAddonHistogram(fake_addon_id, name1)); + expect_fail(() => Telemetry.getAddonHistogram(fake_addon_id, name1)); // Check for reflection capabilities. var h1 = Telemetry.getAddonHistogram(addon_id, name1); @@ -298,7 +278,7 @@ function test_addons() { do_check_eq(s1.counts[3], 1); var name2 = "testing-histogram2"; - expect_success(function () + expect_success(() => register(addon_id, name2, Telemetry.HISTOGRAM_LINEAR, 2, 4, 4)); var h2 = Telemetry.getAddonHistogram(addon_id, name2); @@ -314,16 +294,16 @@ function test_addons() { // Check that we can register histograms for a different addon with // identical names. var extra_addon = "testing-extra-addon"; - expect_success(function () - register(extra_addon, name1, Telemetry.HISTOGRAM_BOOLEAN)); + expect_success(() => + register(extra_addon, name1, Telemetry.HISTOGRAM_BOOLEAN)); // Check that we can register flag histograms. var flag_addon = "testing-flag-addon"; var flag_histogram = "flag-histogram"; - expect_success(function() - register(flag_addon, flag_histogram, Telemetry.HISTOGRAM_FLAG)) - expect_success(function() - register(flag_addon, name2, Telemetry.HISTOGRAM_LINEAR, 2, 4, 4)); + expect_success(() => + register(flag_addon, flag_histogram, Telemetry.HISTOGRAM_FLAG)); + expect_success(() => + register(flag_addon, name2, Telemetry.HISTOGRAM_LINEAR, 2, 4, 4)); // Check that we reflect registered addons and histograms. snapshots = Telemetry.addonHistogramSnapshots; @@ -370,19 +350,58 @@ function test_privateMode() { do_check_neq(uneval(orig), uneval(h.snapshot())); } -// Check that histograms that aren't flagged as needing extended stats -// don't record extended stats. -function test_extended_stats() { - var h = Telemetry.getHistogramById("GRADIENT_DURATION"); - var s = h.snapshot(); - do_check_eq(s.sum, 0); - do_check_eq(s.log_sum, 0); - do_check_eq(s.log_sum_squares, 0); +// Check that telemetry records only when it is suppose to. +function test_histogramRecording() { + // Check that no histogram is recorded if both base and extended recording are off. + Telemetry.canRecordBase = false; + Telemetry.canRecordExtended = false; + + let h = Telemetry.getHistogramById("TELEMETRY_TEST_RELEASE_OPTOUT"); + h.clear(); + let orig = h.snapshot(); h.add(1); - s = h.snapshot(); - do_check_eq(s.sum, 1); - do_check_eq(s.log_sum, 0); - do_check_eq(s.log_sum_squares, 0); + Assert.equal(orig.sum, h.snapshot().sum); + + // Check that only base histograms are recorded. + Telemetry.canRecordBase = true; + h.add(1); + Assert.equal(orig.sum + 1, h.snapshot().sum, + "Histogram value should have incremented by 1 due to recording."); + + // Extended histograms should not be recorded. + h = Telemetry.getHistogramById("TELEMETRY_TEST_RELEASE_OPTIN"); + orig = h.snapshot(); + h.add(1); + Assert.equal(orig.sum, h.snapshot().sum, + "Histograms should be equal after recording."); + + // Runtime created histograms should not be recorded. + h = Telemetry.newHistogram("test::runtime_created_boolean", "never", Telemetry.HISTOGRAM_BOOLEAN); + orig = h.snapshot(); + h.add(1); + Assert.equal(orig.sum, h.snapshot().sum, + "Histograms should be equal after recording."); + + // Check that extended histograms are recorded when required. + Telemetry.canRecordExtended = true; + + h.add(1); + Assert.equal(orig.sum + 1, h.snapshot().sum, + "Runtime histogram value should have incremented by 1 due to recording."); + + h = Telemetry.getHistogramById("TELEMETRY_TEST_RELEASE_OPTIN"); + orig = h.snapshot(); + h.add(1); + Assert.equal(orig.sum + 1, h.snapshot().sum, + "Histogram value should have incremented by 1 due to recording."); + + // Check that base histograms are still being recorded. + h = Telemetry.getHistogramById("TELEMETRY_TEST_RELEASE_OPTOUT"); + h.clear(); + orig = h.snapshot(); + h.add(1); + Assert.equal(orig.sum + 1, h.snapshot().sum, + "Histogram value should have incremented by 1 due to recording."); } // Return an array of numbers from lower up to, excluding, upper @@ -538,6 +557,145 @@ function test_keyed_flag_histogram() Assert.deepEqual(h.snapshot(), {}); } +function test_keyed_histogram_recording() { + // Check that no histogram is recorded if both base and extended recording are off. + Telemetry.canRecordBase = false; + Telemetry.canRecordExtended = false; + + const TEST_KEY = "record_foo"; + let h = Telemetry.getKeyedHistogramById("TELEMETRY_TEST_KEYED_RELEASE_OPTOUT"); + h.clear(); + h.add(TEST_KEY, 1); + Assert.equal(h.snapshot(TEST_KEY).sum, 0); + + // Check that only base histograms are recorded. + Telemetry.canRecordBase = true; + h.add(TEST_KEY, 1); + Assert.equal(h.snapshot(TEST_KEY).sum, 1, + "The keyed histogram should record the correct value."); + + // Extended set keyed histograms should not be recorded. + h = Telemetry.getKeyedHistogramById("TELEMETRY_TEST_KEYED_RELEASE_OPTIN"); + h.clear(); + h.add(TEST_KEY, 1); + Assert.equal(h.snapshot(TEST_KEY).sum, 0, + "The keyed histograms should not record any data."); + + // Runtime created histograms should not be recorded. + h = Telemetry.newKeyedHistogram("test::runtime_keyed_boolean", "never", Telemetry.HISTOGRAM_BOOLEAN); + h.add(TEST_KEY, 1); + Assert.equal(h.snapshot(TEST_KEY).sum, 0, + "The keyed histogram should not record any data."); + + // Check that extended histograms are recorded when required. + Telemetry.canRecordExtended = true; + + h.add(TEST_KEY, 1); + Assert.equal(h.snapshot(TEST_KEY).sum, 1, + "The runtime keyed histogram should record the correct value."); + + h = Telemetry.getKeyedHistogramById("TELEMETRY_TEST_KEYED_RELEASE_OPTIN"); + h.clear(); + h.add(TEST_KEY, 1); + Assert.equal(h.snapshot(TEST_KEY).sum, 1, + "The keyed histogram should record the correct value."); + + // Check that base histograms are still being recorded. + h = Telemetry.getKeyedHistogramById("TELEMETRY_TEST_KEYED_RELEASE_OPTOUT"); + h.clear(); + h.add(TEST_KEY, 1); + Assert.equal(h.snapshot(TEST_KEY).sum, 1); +} + +function test_histogram_recording_enabled() { + Telemetry.canRecordBase = true; + Telemetry.canRecordExtended = true; + + // Check that a "normal" histogram respects recording-enabled on/off + var h = Telemetry.getHistogramById("TELEMETRY_TEST_COUNT"); + var orig = h.snapshot(); + + h.add(1); + Assert.equal(orig.sum + 1, h.snapshot().sum, + "add should record by default."); + + // Check that when recording is disabled - add is ignored + Telemetry.setHistogramRecordingEnabled("TELEMETRY_TEST_COUNT", false); + h.add(1); + Assert.equal(orig.sum + 1, h.snapshot().sum, + "When recording is disabled add should not record."); + + // Check that we're back to normal after recording is enabled + Telemetry.setHistogramRecordingEnabled("TELEMETRY_TEST_COUNT", true); + h.add(1); + Assert.equal(orig.sum + 2, h.snapshot().sum, + "When recording is re-enabled add should record."); + + // Check that a histogram with recording disabled by default behaves correctly + h = Telemetry.getHistogramById("TELEMETRY_TEST_COUNT_INIT_NO_RECORD"); + orig = h.snapshot(); + + h.add(1); + Assert.equal(orig.sum, h.snapshot().sum, + "When recording is disabled by default, add should not record by default."); + + Telemetry.setHistogramRecordingEnabled("TELEMETRY_TEST_COUNT_INIT_NO_RECORD", true); + h.add(1); + Assert.equal(orig.sum + 1, h.snapshot().sum, + "When recording is enabled add should record."); + + // Restore to disabled + Telemetry.setHistogramRecordingEnabled("TELEMETRY_TEST_COUNT_INIT_NO_RECORD", false); + h.add(1); + Assert.equal(orig.sum + 1, h.snapshot().sum, + "When recording is disabled add should not record."); + +} + +function test_keyed_histogram_recording_enabled() { + Telemetry.canRecordBase = true; + Telemetry.canRecordExtended = true; + + // Check RecordingEnabled for keyed histograms which are recording by default + const TEST_KEY = "record_foo"; + h = Telemetry.getKeyedHistogramById("TELEMETRY_TEST_KEYED_RELEASE_OPTOUT"); + + h.clear(); + h.add(TEST_KEY, 1); + Assert.equal(h.snapshot(TEST_KEY).sum, 1, + "Keyed histogram add should record by default"); + + Telemetry.setHistogramRecordingEnabled("TELEMETRY_TEST_KEYED_RELEASE_OPTOUT", false); + h.add(TEST_KEY, 1); + Assert.equal(h.snapshot(TEST_KEY).sum, 1, + "Keyed histogram add should not record when recording is disabled"); + + Telemetry.setHistogramRecordingEnabled("TELEMETRY_TEST_KEYED_RELEASE_OPTOUT", true); + h.clear(); + h.add(TEST_KEY, 1); + Assert.equal(h.snapshot(TEST_KEY).sum, 1, + "Keyed histogram add should record when recording is re-enabled"); + + // Check that a histogram with recording disabled by default behaves correctly + h = Telemetry.getKeyedHistogramById("TELEMETRY_TEST_KEYED_COUNT_INIT_NO_RECORD"); + h.clear(); + + h.add(TEST_KEY, 1); + Assert.equal(h.snapshot(TEST_KEY).sum, 0, + "Keyed histogram add should not record by default for histograms which don't record by default"); + + Telemetry.setHistogramRecordingEnabled("TELEMETRY_TEST_KEYED_COUNT_INIT_NO_RECORD", true); + h.add(TEST_KEY, 1); + Assert.equal(h.snapshot(TEST_KEY).sum, 1, + "Keyed histogram add should record when recording is enabled"); + + // Restore to disabled + Telemetry.setHistogramRecordingEnabled("TELEMETRY_TEST_KEYED_COUNT_INIT_NO_RECORD", false); + h.add(TEST_KEY, 1); + Assert.equal(h.snapshot(TEST_KEY).sum, 1, + "Keyed histogram add should not record when recording is disabled"); +} + function test_keyed_histogram() { // Check that invalid names get rejected. @@ -564,6 +722,7 @@ function test_keyed_histogram() { test_keyed_boolean_histogram(); test_keyed_count_histogram(); test_keyed_flag_histogram(); + test_keyed_histogram_recording(); } function test_datasets() @@ -778,8 +937,8 @@ function run_test() test_histogram(histogram_type, "test::"+histogram_type, min, max, bucket_count); const nh = Telemetry.newHistogram; - expect_fail(function () nh("test::min", "never", histogram_type, 0, max, bucket_count)); - expect_fail(function () nh("test::bucket_count", "never", histogram_type, min, max, 1)); + expect_fail(() => nh("test::min", "never", histogram_type, 0, max, bucket_count)); + expect_fail(() => nh("test::bucket_count", "never", histogram_type, min, max, 1)); } // Instantiate the storage for this histogram and make sure it doesn't @@ -795,11 +954,13 @@ function run_test() test_getSlowSQL(); test_getWebrtc(); test_privateMode(); + test_histogramRecording(); test_addons(); - test_extended_stats(); test_expired_histogram(); test_keyed_histogram(); test_datasets(); test_subsession(); test_keyed_subsession(); + test_histogram_recording_enabled(); + test_keyed_histogram_recording_enabled(); } diff --git a/toolkit/components/thumbnails/test/head.js b/toolkit/components/thumbnails/test/head.js index e4bbcddd5b..79618f37f8 100644 --- a/toolkit/components/thumbnails/test/head.js +++ b/toolkit/components/thumbnails/test/head.js @@ -222,7 +222,7 @@ function addVisitsAndRepopulateNewTabLinks(aPlaceInfo, aCallback) { function whenFileExists(aURL, aCallback = next) { let callback = aCallback; if (!thumbnailExists(aURL)) { - callback = function () whenFileExists(aURL, aCallback); + callback = () => whenFileExists(aURL, aCallback); } executeSoon(callback); @@ -239,7 +239,7 @@ function whenFileExists(aURL, aCallback = next) { function whenFileRemoved(aFile, aCallback) { let callback = aCallback; if (aFile.exists()) { - callback = function () whenFileRemoved(aFile, aCallback); + callback = () => whenFileRemoved(aFile, aCallback); } executeSoon(callback || next); @@ -313,7 +313,9 @@ function bgAddCrashObserver() { } }, 'ipc:content-shutdown', false); return { - get crashed() crashed + get crashed() { + return crashed; + } }; } diff --git a/widget/cocoa/nsDeviceContextSpecX.h b/widget/cocoa/nsDeviceContextSpecX.h index c1b860e1aa..054c634e98 100644 --- a/widget/cocoa/nsDeviceContextSpecX.h +++ b/widget/cocoa/nsDeviceContextSpecX.h @@ -20,7 +20,7 @@ public: NS_IMETHOD Init(nsIWidget *aWidget, nsIPrintSettings* aPS, bool aIsPrintPreview) override; NS_IMETHOD GetSurfaceForPrinter(gfxASurface **surface) override; NS_IMETHOD BeginDocument(const nsAString& aTitle, - char16_t* aPrintToFileName, + const nsAString& aPrintToFileName, int32_t aStartPage, int32_t aEndPage) override; NS_IMETHOD EndDocument() override; diff --git a/widget/cocoa/nsDeviceContextSpecX.mm b/widget/cocoa/nsDeviceContextSpecX.mm index 0c30a6d419..6ac66060c1 100644 --- a/widget/cocoa/nsDeviceContextSpecX.mm +++ b/widget/cocoa/nsDeviceContextSpecX.mm @@ -59,7 +59,7 @@ NS_IMETHODIMP nsDeviceContextSpecX::Init(nsIWidget *aWidget, } NS_IMETHODIMP nsDeviceContextSpecX::BeginDocument(const nsAString& aTitle, - char16_t* aPrintToFileName, + const nsAString& aPrintToFileName, int32_t aStartPage, int32_t aEndPage) { diff --git a/widget/gonk/GeckoTouchDispatcher.cpp b/widget/gonk/GeckoTouchDispatcher.cpp index 7c0592b94d..60244c25fa 100644 --- a/widget/gonk/GeckoTouchDispatcher.cpp +++ b/widget/gonk/GeckoTouchDispatcher.cpp @@ -38,6 +38,7 @@ #include #include +#undef LOG #define LOG(args...) \ __android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args) @@ -76,10 +77,9 @@ GeckoTouchDispatcher::GeckoTouchDispatcher() gfxPrefs::GetSingleton(); mEnabledUniformityInfo = gfxPrefs::UniformityInfo(); - mResamplingEnabled = gfxPrefs::TouchResampling() && - gfxPrefs::HardwareVsyncEnabled(); mVsyncAdjust = TimeDuration::FromMilliseconds(gfxPrefs::TouchVsyncSampleAdjust()); mMaxPredict = TimeDuration::FromMilliseconds(gfxPrefs::TouchResampleMaxPredict()); + mMinDelta = TimeDuration::FromMilliseconds(gfxPrefs::TouchResampleMinDelta()); mOldTouchThreshold = TimeDuration::FromMilliseconds(gfxPrefs::TouchResampleOldTouchThreshold()); mDelayedVsyncThreshold = TimeDuration::FromMilliseconds(gfxPrefs::TouchResampleVsyncDelayThreshold()); } @@ -90,15 +90,12 @@ GeckoTouchDispatcher::SetCompositorVsyncScheduler(mozilla::layers::CompositorVsy MOZ_ASSERT(NS_IsMainThread()); // We assume on b2g that there is only 1 CompositorParent MOZ_ASSERT(mCompositorVsyncScheduler == nullptr); - if (mResamplingEnabled) { - mCompositorVsyncScheduler = aObserver; - } + mCompositorVsyncScheduler = aObserver; } void GeckoTouchDispatcher::NotifyVsync(TimeStamp aVsyncTimestamp) { - MOZ_ASSERT(mResamplingEnabled); layers::APZThreadUtils::AssertOnControllerThread(); DispatchTouchMoveEvents(aVsyncTimestamp); } @@ -125,12 +122,6 @@ GeckoTouchDispatcher::NotifyTouch(MultiTouchInput& aTouch, TimeStamp aEventTime) mTouchMoveEvents.push_back(aTouch); mHavePendingTouchMoves = true; - if (mResamplingEnabled) { - return; - } - - layers::APZThreadUtils::RunOnControllerThread(NewRunnableMethod( - this, &GeckoTouchDispatcher::DispatchTouchMoveEvents, TimeStamp::Now())); } else { { // scope lock MutexAutoLock lock(mTouchQueueLock); @@ -146,12 +137,10 @@ GeckoTouchDispatcher::DispatchTouchNonMoveEvent(MultiTouchInput aInput) { layers::APZThreadUtils::AssertOnControllerThread(); - if (mResamplingEnabled) { - // Flush pending touch move events, if there are any - // (DispatchTouchMoveEvents will check the mHavePendingTouchMoves flag and - // bail out if there's nothing to be done). - NotifyVsync(TimeStamp::Now()); - } + // Flush pending touch move events, if there are any + // (DispatchTouchMoveEvents will check the mHavePendingTouchMoves flag and + // bail out if there's nothing to be done). + NotifyVsync(TimeStamp::Now()); DispatchTouchEvent(aInput); { // scope lock @@ -173,27 +162,22 @@ GeckoTouchDispatcher::DispatchTouchMoveEvents(TimeStamp aVsyncTime) } mHavePendingTouchMoves = false; - if (mResamplingEnabled) { - int touchCount = mTouchMoveEvents.size(); - TimeDuration vsyncTouchDiff = aVsyncTime - mTouchMoveEvents.back().mTimeStamp; - // The delay threshold is a positive pref, but we're testing to see if the - // vsync time is delayed from the touch, so add a negative sign. - bool isDelayedVsyncEvent = vsyncTouchDiff < -mDelayedVsyncThreshold; - bool isOldTouch = vsyncTouchDiff > mOldTouchThreshold; - bool resample = (touchCount > 1) && !isDelayedVsyncEvent && !isOldTouch; + int touchCount = mTouchMoveEvents.size(); + TimeDuration vsyncTouchDiff = aVsyncTime - mTouchMoveEvents.back().mTimeStamp; + // The delay threshold is a positive pref, but we're testing to see if the + // vsync time is delayed from the touch, so add a negative sign. + bool isDelayedVsyncEvent = vsyncTouchDiff < -mDelayedVsyncThreshold; + bool isOldTouch = vsyncTouchDiff > mOldTouchThreshold; + bool resample = (touchCount > 1) && !isDelayedVsyncEvent && !isOldTouch; - if (!resample) { - touchMove = mTouchMoveEvents.back(); - mTouchMoveEvents.clear(); - if (!isDelayedVsyncEvent && !isOldTouch) { - mTouchMoveEvents.push_back(touchMove); - } - } else { - ResampleTouchMoves(touchMove, aVsyncTime); - } - } else { + if (!resample) { touchMove = mTouchMoveEvents.back(); mTouchMoveEvents.clear(); + if (!isDelayedVsyncEvent && !isOldTouch) { + mTouchMoveEvents.push_back(touchMove); + } + } else { + ResampleTouchMoves(touchMove, aVsyncTime); } } @@ -293,6 +277,14 @@ GeckoTouchDispatcher::ResampleTouchMoves(MultiTouchInput& aOutTouch, TimeStamp a TimeStamp sampleTime = aVsyncTime - mVsyncAdjust; TimeDuration touchDiff = currentTouch.mTimeStamp - baseTouch.mTimeStamp; + if (touchDiff < mMinDelta) { + aOutTouch = currentTouch; + #ifdef LOG_RESAMPLE_DATA + LOG("The touches are too close, skip resampling\n"); + #endif + return; + } + if (currentTouch.mTimeStamp < sampleTime) { TimeDuration maxResampleTime = std::min(touchDiff / int64_t(2), mMaxPredict); TimeStamp maxTimestamp = currentTouch.mTimeStamp + maxResampleTime; diff --git a/widget/gonk/GeckoTouchDispatcher.h b/widget/gonk/GeckoTouchDispatcher.h index 5cbe414260..3c7acd0e31 100644 --- a/widget/gonk/GeckoTouchDispatcher.h +++ b/widget/gonk/GeckoTouchDispatcher.h @@ -79,6 +79,7 @@ private: // All times below are in nanoseconds TimeDuration mVsyncAdjust; // Time from vsync we create sample times from TimeDuration mMaxPredict; // How far into the future we're allowed to extrapolate + TimeDuration mMinDelta; // Minimal time difference between touches for resampling // Amount of time between vsync and the last event that is required before we // resample diff --git a/widget/gonk/GonkMemoryPressureMonitoring.cpp b/widget/gonk/GonkMemoryPressureMonitoring.cpp index 551b26a11f..808b1590f6 100644 --- a/widget/gonk/GonkMemoryPressureMonitoring.cpp +++ b/widget/gonk/GonkMemoryPressureMonitoring.cpp @@ -121,8 +121,6 @@ public: #ifdef MOZ_NUWA_PROCESS if (IsNuwaProcess()) { - NS_ASSERTION(NuwaMarkCurrentThread != nullptr, - "NuwaMarkCurrentThread is undefined!"); NuwaMarkCurrentThread(nullptr, nullptr); } #endif diff --git a/widget/gonk/GonkPermission.cpp b/widget/gonk/GonkPermission.cpp index 876354a783..ae8f231c50 100644 --- a/widget/gonk/GonkPermission.cpp +++ b/widget/gonk/GonkPermission.cpp @@ -30,6 +30,7 @@ #undef LOG #include +#undef ALOGE #define ALOGE(args...) __android_log_print(ANDROID_LOG_ERROR, "gonkperm" , ## args) using namespace android; diff --git a/widget/gonk/OrientationObserver.cpp b/widget/gonk/OrientationObserver.cpp index 1e55404d90..9096404cfb 100644 --- a/widget/gonk/OrientationObserver.cpp +++ b/widget/gonk/OrientationObserver.cpp @@ -43,8 +43,8 @@ static OrientationMapping sOrientationMappings[] = { {nsIScreen::ROTATION_270_DEG, eScreenOrientation_LandscapeSecondary}, }; -const static int sDefaultLandscape = 2; -const static int sDefaultPortrait = 0; +const static uint32_t sDefaultLandscape = 2; +const static uint32_t sDefaultPortrait = 0; static uint32_t sOrientationOffset = 0; @@ -108,7 +108,7 @@ DetectDefaultOrientation() static nsresult ConvertToScreenRotation(ScreenOrientationInternal aOrientation, uint32_t *aResult) { - for (int i = 0; i < ArrayLength(sOrientationMappings); i++) { + for (uint32_t i = 0; i < ArrayLength(sOrientationMappings); i++) { if (aOrientation & sOrientationMappings[i].mDomOrientation) { // Shift the mappings in sOrientationMappings so devices with default // landscape orientation map landscape-primary to 0 degree and so forth. @@ -134,7 +134,7 @@ ConvertToScreenRotation(ScreenOrientationInternal aOrientation, uint32_t *aResul nsresult ConvertToDomOrientation(uint32_t aRotation, ScreenOrientationInternal *aResult) { - for (int i = 0; i < ArrayLength(sOrientationMappings); i++) { + for (uint32_t i = 0; i < ArrayLength(sOrientationMappings); i++) { if (aRotation == sOrientationMappings[i].mScreenRotation) { // Shift the mappings in sOrientationMappings so devices with default // landscape orientation map 0 degree to landscape-primary and so forth. @@ -213,7 +213,7 @@ OrientationObserver::Notify(const hal::SensorData& aSensorData) } int rotation = mOrientation->OnSensorChanged(aSensorData, static_cast(currRotation)); - if (rotation < 0 || rotation == currRotation) { + if (rotation < 0 || uint32_t(rotation) == currRotation) { return; } diff --git a/widget/gonk/libui/InputDispatcher.cpp b/widget/gonk/libui/InputDispatcher.cpp index 09d47c7376..7adaa19989 100644 --- a/widget/gonk/libui/InputDispatcher.cpp +++ b/widget/gonk/libui/InputDispatcher.cpp @@ -1112,8 +1112,6 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, INJECTION_PERMISSION_DENIED }; - nsecs_t startTime = now(); - // For security reasons, we defer updating the touch state until we are sure that // event injection will be allowed. // @@ -2241,7 +2239,6 @@ InputDispatcher::MotionEntry* InputDispatcher::splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet32 pointerIds) { ALOG_ASSERT(pointerIds.value != 0); - uint32_t splitPointerIndexMap[MAX_POINTERS]; PointerProperties splitPointerProperties[MAX_POINTERS]; PointerCoords splitPointerCoords[MAX_POINTERS]; @@ -2254,7 +2251,6 @@ InputDispatcher::splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet originalMotionEntry->pointerProperties[originalPointerIndex]; uint32_t pointerId = uint32_t(pointerProperties.id); if (pointerIds.hasBit(pointerId)) { - splitPointerIndexMap[splitPointerCount] = originalPointerIndex; splitPointerProperties[splitPointerCount].copyFrom(pointerProperties); splitPointerCoords[splitPointerCount].copyFrom( originalMotionEntry->pointerCoords[originalPointerIndex]); diff --git a/widget/gonk/libui/InputReader.cpp b/widget/gonk/libui/InputReader.cpp index c8bd213537..3699569aa7 100644 --- a/widget/gonk/libui/InputReader.cpp +++ b/widget/gonk/libui/InputReader.cpp @@ -1592,11 +1592,15 @@ void MultiTouchMotionAccumulator::clearSlots(int32_t initialSlot) { void MultiTouchMotionAccumulator::process(const RawEvent* rawEvent) { if (rawEvent->type == EV_ABS) { +#if DEBUG_POINTERS bool newSlot = false; +#endif if (mUsingSlotsProtocol) { if (rawEvent->code == ABS_MT_SLOT) { mCurrentSlot = rawEvent->value; +#if DEBUG_POINTERS newSlot = true; +#endif } } else if (mCurrentSlot < 0) { mCurrentSlot = 0; @@ -4650,18 +4654,15 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, // Otherwise choose an arbitrary remaining pointer. // This guarantees we always have an active touch id when there is at least one pointer. // We keep the same active touch id for as long as possible. - bool activeTouchChanged = false; int32_t lastActiveTouchId = mPointerGesture.activeTouchId; int32_t activeTouchId = lastActiveTouchId; if (activeTouchId < 0) { if (!mCurrentFingerIdBits.isEmpty()) { - activeTouchChanged = true; activeTouchId = mPointerGesture.activeTouchId = mCurrentFingerIdBits.firstMarkedBit(); mPointerGesture.firstTouchTime = when; } } else if (!mCurrentFingerIdBits.hasBit(activeTouchId)) { - activeTouchChanged = true; if (!mCurrentFingerIdBits.isEmpty()) { activeTouchId = mPointerGesture.activeTouchId = mCurrentFingerIdBits.firstMarkedBit(); @@ -4757,7 +4758,6 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, } if (bestId >= 0 && bestId != activeTouchId) { mPointerGesture.activeTouchId = activeTouchId = bestId; - activeTouchChanged = true; #if DEBUG_GESTURES ALOGD("Gestures: BUTTON_CLICK_OR_DRAG switched pointers, " "bestId=%d, bestSpeed=%0.3f", bestId, bestSpeed); diff --git a/widget/gonk/libui/Keyboard.cpp b/widget/gonk/libui/Keyboard.cpp index 09143595da..f775025792 100644 --- a/widget/gonk/libui/Keyboard.cpp +++ b/widget/gonk/libui/Keyboard.cpp @@ -240,7 +240,6 @@ static int32_t toggleLockedMetaState(int32_t mask, bool down, int32_t oldMetaSta } int32_t updateMetaState(int32_t keyCode, bool down, int32_t oldMetaState) { - int32_t mask; switch (keyCode) { case AKEYCODE_ALT_LEFT: return setEphemeralMetaState(AMETA_ALT_LEFT_ON, down, oldMetaState); diff --git a/widget/gonk/libui/SpriteController.cpp b/widget/gonk/libui/SpriteController.cpp index 38f198cbf3..8677476b1b 100644 --- a/widget/gonk/libui/SpriteController.cpp +++ b/widget/gonk/libui/SpriteController.cpp @@ -141,10 +141,9 @@ void SpriteController::doUpdateSprites() { // Create missing surfaces. bool surfaceChanged = false; +#ifdef HAVE_ANDROID_OS for (size_t i = 0; i < numSprites; i++) { SpriteUpdate& update = updates.editItemAt(i); - -#ifdef HAVE_ANDROID_OS if (update.state.surfaceControl == NULL && update.state.wantSurfaceVisible()) { update.state.surfaceWidth = update.state.icon.bitmap.width(); update.state.surfaceHeight = update.state.icon.bitmap.height(); @@ -156,15 +155,14 @@ void SpriteController::doUpdateSprites() { update.surfaceChanged = surfaceChanged = true; } } -#endif } +#endif // Resize sprites if needed, inside a global transaction. +#ifdef HAVE_ANDROID_OS bool haveGlobalTransaction = false; for (size_t i = 0; i < numSprites; i++) { SpriteUpdate& update = updates.editItemAt(i); - -#ifdef HAVE_ANDROID_OS if (update.state.surfaceControl != NULL && update.state.wantSurfaceVisible()) { int32_t desiredWidth = update.state.icon.bitmap.width(); int32_t desiredHeight = update.state.icon.bitmap.height(); @@ -197,8 +195,8 @@ void SpriteController::doUpdateSprites() { } } } -#endif } +#endif #ifdef HAVE_ANDROID_OS if (haveGlobalTransaction) { SurfaceComposerClient::closeGlobalTransaction(); @@ -258,16 +256,15 @@ void SpriteController::doUpdateSprites() { #endif } +#ifdef HAVE_ANDROID_OS // Set sprite surface properties and make them visible. bool haveTransaction = false; for (size_t i = 0; i < numSprites; i++) { SpriteUpdate& update = updates.editItemAt(i); - bool wantSurfaceVisibleAndDrawn = update.state.wantSurfaceVisible() && update.state.surfaceDrawn; bool becomingVisible = wantSurfaceVisibleAndDrawn && !update.state.surfaceVisible; bool becomingHidden = !wantSurfaceVisibleAndDrawn && update.state.surfaceVisible; -#ifdef HAVE_ANDROID_OS if (update.state.surfaceControl != NULL && (becomingVisible || becomingHidden || (wantSurfaceVisibleAndDrawn && (update.state.dirty & (DIRTY_ALPHA | DIRTY_POSITION | DIRTY_TRANSFORMATION_MATRIX | DIRTY_LAYER @@ -337,8 +334,8 @@ void SpriteController::doUpdateSprites() { } } } -#endif } +#endif #ifdef HAVE_ANDROID_OS if (haveTransaction) { @@ -346,6 +343,7 @@ void SpriteController::doUpdateSprites() { } #endif +#ifdef HAVE_ANDROID_OS // If any surfaces were changed, write back the new surface properties to the sprites. if (surfaceChanged) { // acquire lock AutoMutex _l(mLock); @@ -353,15 +351,14 @@ void SpriteController::doUpdateSprites() { for (size_t i = 0; i < numSprites; i++) { const SpriteUpdate& update = updates.itemAt(i); -#ifdef HAVE_ANDROID_OS if (update.surfaceChanged) { update.sprite->setSurfaceLocked(update.state.surfaceControl, update.state.surfaceWidth, update.state.surfaceHeight, update.state.surfaceDrawn, update.state.surfaceVisible); } -#endif } } // release lock +#endif // Clear the sprite update vector outside the lock. It is very important that // we do not clear sprite references inside the lock since we could be releasing diff --git a/widget/gonk/nsAppShell.cpp b/widget/gonk/nsAppShell.cpp index 7dd3528c54..25ea3b89f2 100644 --- a/widget/gonk/nsAppShell.cpp +++ b/widget/gonk/nsAppShell.cpp @@ -75,6 +75,7 @@ #include "mozilla/layers/CompositorParent.h" #include "GeckoTouchDispatcher.h" +#undef LOG #define LOG(args...) \ __android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args) #ifdef VERBOSE_LOG_ENABLED diff --git a/widget/gtk/nsDeviceContextSpecG.cpp b/widget/gtk/nsDeviceContextSpecG.cpp index 3f2dc9ce19..2a8abf9b3e 100644 --- a/widget/gtk/nsDeviceContextSpecG.cpp +++ b/widget/gtk/nsDeviceContextSpecG.cpp @@ -277,8 +277,10 @@ ns_release_macro(gpointer aData) { NS_RELEASE(spoolFile); } -NS_IMETHODIMP nsDeviceContextSpecGTK::BeginDocument(const nsAString& aTitle, char16_t * aPrintToFileName, - int32_t aStartPage, int32_t aEndPage) +NS_IMETHODIMP +nsDeviceContextSpecGTK::BeginDocument(const nsAString& aTitle, + const nsAString& aPrintToFileName, + int32_t aStartPage, int32_t aEndPage) { if (mToPrinter) { if (!GTK_IS_PRINTER(mGtkPrinter)) diff --git a/widget/gtk/nsDeviceContextSpecG.h b/widget/gtk/nsDeviceContextSpecG.h index 2585a72299..b1fa40fc41 100644 --- a/widget/gtk/nsDeviceContextSpecG.h +++ b/widget/gtk/nsDeviceContextSpecG.h @@ -38,7 +38,8 @@ public: NS_IMETHOD Init(nsIWidget *aWidget, nsIPrintSettings* aPS, bool aIsPrintPreview) override; - NS_IMETHOD BeginDocument(const nsAString& aTitle, char16_t * aPrintToFileName, + NS_IMETHOD BeginDocument(const nsAString& aTitle, + const nsAString& aPrintToFileName, int32_t aStartPage, int32_t aEndPage) override; NS_IMETHOD EndDocument() override; NS_IMETHOD BeginPage() override { return NS_OK; } diff --git a/widget/moz.build b/widget/moz.build index b9b0c12f92..4b70a7768d 100644 --- a/widget/moz.build +++ b/widget/moz.build @@ -95,6 +95,7 @@ EXPORTS += [ 'InputData.h', 'nsBaseScreen.h', 'nsBaseWidget.h', + 'nsDeviceContextSpecProxy.h', 'nsIDeviceContextSpec.h', 'nsIPluginWidget.h', 'nsIRollupListener.h', @@ -148,6 +149,7 @@ UNIFIED_SOURCES += [ 'nsClipboardProxy.cpp', 'nsColorPickerProxy.cpp', 'nsContentProcessWidgetFactory.cpp', + 'nsDeviceContextSpecProxy.cpp', 'nsDragServiceProxy.cpp', 'nsFilePickerProxy.cpp', 'nsHTMLFormatConverter.cpp', diff --git a/widget/nsDeviceContextSpecProxy.cpp b/widget/nsDeviceContextSpecProxy.cpp new file mode 100644 index 0000000000..560816ce27 --- /dev/null +++ b/widget/nsDeviceContextSpecProxy.cpp @@ -0,0 +1,178 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsDeviceContextSpecProxy.h" + +#include "gfxASurface.h" +#include "gfxPlatform.h" +#include "mozilla/gfx/DrawEventRecorder.h" +#include "mozilla/layout/RemotePrintJobChild.h" +#include "mozilla/RefPtr.h" +#include "mozilla/unused.h" +#include "nsComponentManagerUtils.h" +#include "nsIPrintSession.h" +#include "nsIPrintSettings.h" + +using mozilla::Unused; + +NS_IMPL_ISUPPORTS(nsDeviceContextSpecProxy, nsIDeviceContextSpec) + +NS_IMETHODIMP +nsDeviceContextSpecProxy::Init(nsIWidget* aWidget, + nsIPrintSettings* aPrintSettings, + bool aIsPrintPreview) +{ + nsresult rv; + mRealDeviceContextSpec = + do_CreateInstance("@mozilla.org/gfx/devicecontextspec;1", &rv); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + mRealDeviceContextSpec->Init(nullptr, aPrintSettings, false); + if (NS_WARN_IF(NS_FAILED(rv))) { + mRealDeviceContextSpec = nullptr; + return rv; + } + + mPrintSettings = aPrintSettings; + + if (aIsPrintPreview) { + return NS_OK; + } + + // nsIPrintSettings only has a weak reference to nsIPrintSession, so we hold + // it to make sure it's available for the lifetime of the print. + rv = mPrintSettings->GetPrintSession(getter_AddRefs(mPrintSession)); + if (NS_FAILED(rv) || !mPrintSession) { + NS_WARNING("We can't print via the parent without an nsIPrintSession."); + return rv; + } + + rv = mPrintSession->GetRemotePrintJob(getter_AddRefs(mRemotePrintJob)); + if (NS_FAILED(rv) || !mRemotePrintJob) { + NS_WARNING("We can't print via the parent without a RemotePrintJobChild."); + return rv; + } + + return NS_OK; +} + +NS_IMETHODIMP +nsDeviceContextSpecProxy::GetSurfaceForPrinter(gfxASurface** aSurface) +{ + MOZ_ASSERT(aSurface); + MOZ_ASSERT(mRealDeviceContextSpec); + + // The real device context may need to have created a real printing surface + // even though we're not using it directly. + nsresult rv = mRealDeviceContextSpec->GetSurfaceForPrinter(aSurface); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + double width, height; + rv = mPrintSettings->GetEffectivePageSize(&width, &height); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + // convert twips to points + width /= TWIPS_PER_POINT_FLOAT; + height /= TWIPS_PER_POINT_FLOAT; + + RefPtr surface = gfxPlatform::GetPlatform()-> + CreateOffscreenSurface(mozilla::gfx::IntSize(width, height), + gfxImageFormat::ARGB32); + + surface.forget(aSurface); + return NS_OK; +} + +NS_IMETHODIMP +nsDeviceContextSpecProxy::GetDrawEventRecorder(mozilla::gfx::DrawEventRecorder** aDrawEventRecorder) +{ + MOZ_ASSERT(aDrawEventRecorder); + RefPtr result = mRecorder; + result.forget(aDrawEventRecorder); + return NS_OK; +} + +float +nsDeviceContextSpecProxy::GetDPI() +{ + MOZ_ASSERT(mRealDeviceContextSpec); + + return mRealDeviceContextSpec->GetDPI(); +} + +float +nsDeviceContextSpecProxy::GetPrintingScale() +{ + MOZ_ASSERT(mRealDeviceContextSpec); + + return mRealDeviceContextSpec->GetPrintingScale(); +} + +NS_IMETHODIMP +nsDeviceContextSpecProxy::BeginDocument(const nsAString& aTitle, + const nsAString& aPrintToFileName, + int32_t aStartPage, int32_t aEndPage) +{ + mRecorder = new DrawEventRecorderMemory(); + return mRemotePrintJob->InitializePrint(nsString(aTitle), + nsString(aPrintToFileName), + aStartPage, aEndPage); +} + +NS_IMETHODIMP +nsDeviceContextSpecProxy::EndDocument() +{ + Unused << mRemotePrintJob->SendFinalizePrint(); + return NS_OK; +} + +NS_IMETHODIMP +nsDeviceContextSpecProxy::AbortDocument() +{ + Unused << mRemotePrintJob->SendAbortPrint(NS_OK); + return NS_OK; +} + +NS_IMETHODIMP +nsDeviceContextSpecProxy::BeginPage() +{ + return NS_OK; +} + +NS_IMETHODIMP +nsDeviceContextSpecProxy::EndPage() +{ + // Save the current page recording to shared memory. + mozilla::ipc::Shmem storedPage; + size_t recordingSize = mRecorder->RecordingSize(); + if (!mRemotePrintJob->AllocShmem(recordingSize, + mozilla::ipc::SharedMemory::TYPE_BASIC, + &storedPage)) { + NS_WARNING("Failed to create shared memory for remote printing."); + return NS_ERROR_FAILURE; + } + + bool success = mRecorder->CopyRecording(storedPage.get(), recordingSize); + if (!success) { + NS_WARNING("Copying recording to shared memory was not succesful."); + return NS_ERROR_FAILURE; + } + + // Wipe the recording to free memory. The recorder does not forget which data + // backed objects that it has stored. + mRecorder->WipeRecording(); + + // Send the page recording to the parent. + mRemotePrintJob->ProcessPage(storedPage); + + return NS_OK; +} diff --git a/widget/nsDeviceContextSpecProxy.h b/widget/nsDeviceContextSpecProxy.h new file mode 100644 index 0000000000..345139ea31 --- /dev/null +++ b/widget/nsDeviceContextSpecProxy.h @@ -0,0 +1,63 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef nsDeviceContextSpecProxy_h +#define nsDeviceContextSpecProxy_h + +#include "nsIDeviceContextSpec.h" +#include "nsCOMPtr.h" + +class nsIPrintSession; + +namespace mozilla { +namespace gfx { +class DrawEventRecorderMemory; +} + +namespace layout { +class RemotePrintJobChild; +} +} + +class nsDeviceContextSpecProxy final : public nsIDeviceContextSpec +{ +public: + NS_DECL_ISUPPORTS + + NS_METHOD Init(nsIWidget* aWidget, nsIPrintSettings* aPrintSettings, + bool aIsPrintPreview) final; + + NS_METHOD GetSurfaceForPrinter(gfxASurface** aSurface) final; + + NS_METHOD GetDrawEventRecorder(mozilla::gfx::DrawEventRecorder** aDrawEventRecorder) final; + + float GetDPI() final; + + float GetPrintingScale() final; + + NS_METHOD BeginDocument(const nsAString& aTitle, + const nsAString& aPrintToFileName, + int32_t aStartPage, int32_t aEndPage) final; + + NS_METHOD EndDocument() final; + + NS_METHOD AbortDocument() final; + + NS_METHOD BeginPage() final; + + NS_METHOD EndPage() final; + +private: + ~nsDeviceContextSpecProxy() {} + + nsCOMPtr mPrintSettings; + nsCOMPtr mPrintSession; + nsCOMPtr mRealDeviceContextSpec; + RefPtr mRemotePrintJob; + RefPtr mRecorder; +}; + +#endif // nsDeviceContextSpecProxy_h diff --git a/widget/nsIDeviceContextSpec.h b/widget/nsIDeviceContextSpec.h index c91436a036..4d5f084ef0 100644 --- a/widget/nsIDeviceContextSpec.h +++ b/widget/nsIDeviceContextSpec.h @@ -12,9 +12,15 @@ class nsIWidget; class nsIPrintSettings; class gfxASurface; +namespace mozilla { +namespace gfx{ +class DrawEventRecorder; +} +} + #define NS_IDEVICE_CONTEXT_SPEC_IID \ -{ 0xb5548fb1, 0xf43e, 0x4921, \ - { 0x82, 0x19, 0xc3, 0x82, 0x06, 0xee, 0x74, 0x5c } } +{ 0xf407cfba, 0xbe28, 0x46c9, \ + { 0x8a, 0xba, 0x04, 0x2d, 0xae, 0xbb, 0x4f, 0x23 } } class nsIDeviceContextSpec : public nsISupports { @@ -34,12 +40,40 @@ public: NS_IMETHOD GetSurfaceForPrinter(gfxASurface **nativeSurface) = 0; + /** + * If required override to return a recorder to record the print. + * + * @param aDrawEventRecorder out param for the recorder to use + * @return NS_OK or a suitable error code + */ + NS_IMETHOD GetDrawEventRecorder(mozilla::gfx::DrawEventRecorder** aDrawEventRecorder) + { + MOZ_ASSERT(aDrawEventRecorder); + *aDrawEventRecorder = nullptr; + return NS_OK; + } + + /** + * Override to return something other than the default. + * + * @return DPI for printing. + */ + virtual float GetDPI() { return 72.0f; } + + /** + * Override to return something other than the default. + * + * @return the printing scale to be applied to the context for printing. + */ + virtual float GetPrintingScale() { return 1.0f; } + NS_IMETHOD BeginDocument(const nsAString& aTitle, - char16_t* aPrintToFileName, + const nsAString& aPrintToFileName, int32_t aStartPage, int32_t aEndPage) = 0; NS_IMETHOD EndDocument() = 0; + NS_IMETHOD AbortDocument() { return EndDocument(); } NS_IMETHOD BeginPage() = 0; NS_IMETHOD EndPage() = 0; }; diff --git a/widget/nsIPrintSession.idl b/widget/nsIPrintSession.idl index d94dfe7949..ca7541371c 100644 --- a/widget/nsIPrintSession.idl +++ b/widget/nsIPrintSession.idl @@ -12,11 +12,6 @@ * differs from nsIPrintSettings, which stores data which may * be valid across a number of jobs. * - * This interface is currently empty since, at this point, only - * platform-specific derived interfaces offer any functionality. - * It is here as a placeholder for when the printing session has - * XP functionality. - * * The creation of a component which implements this interface * will begin the session. Likewise, destruction of that object * will end the session. @@ -24,8 +19,22 @@ * @status */ -[uuid(2f977d52-5485-11d4-87e2-0010a4e75ef2)] +%{ C++ +namespace mozilla { +namespace layout { +class RemotePrintJobChild; +} +} +%} + +[ptr] native RemotePrintJobChildPtr(mozilla::layout::RemotePrintJobChild); + +[uuid(424ae4bb-10ca-4f35-b84e-eab893322df4)] interface nsIPrintSession : nsISupports { + /** + * The remote print job is used for printing via the parent process. + */ + [noscript] attribute RemotePrintJobChildPtr remotePrintJob; }; diff --git a/widget/nsPrimitiveHelpers.cpp b/widget/nsPrimitiveHelpers.cpp index fe70262061..d47101b40e 100644 --- a/widget/nsPrimitiveHelpers.cpp +++ b/widget/nsPrimitiveHelpers.cpp @@ -21,6 +21,9 @@ #include "nsPrimitiveHelpers.h" + +#include "mozilla/UniquePtr.h" +#include "nsAutoPtr.h" #include "nsCOMPtr.h" #include "nsXPCOM.h" #include "nsISupportsPrimitives.h" @@ -60,7 +63,7 @@ nsPrimitiveHelpers :: CreatePrimitiveForData ( const char* aFlavor, const void* do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID); if (primitive ) { if (aDataLen % 2) { - auto buffer = MakeUnique(aDataLen + 1); + auto buffer = mozilla::MakeUnique(aDataLen + 1); if (!MOZ_LIKELY(buffer)) return; diff --git a/widget/nsPrintOptionsImpl.cpp b/widget/nsPrintOptionsImpl.cpp index 4735a6f8df..06ae3d5ff8 100644 --- a/widget/nsPrintOptionsImpl.cpp +++ b/widget/nsPrintOptionsImpl.cpp @@ -3,11 +3,14 @@ * 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/. */ -#include "mozilla/embedding/PPrinting.h" -#include "nsPrintingProxy.h" #include "nsPrintOptionsImpl.h" + +#include "mozilla/embedding/PPrinting.h" +#include "mozilla/layout/RemotePrintJobChild.h" +#include "nsPrintingProxy.h" #include "nsReadableUtils.h" #include "nsPrintSettingsImpl.h" +#include "nsIPrintSession.h" #include "nsIDOMWindow.h" #include "nsIServiceManager.h" @@ -29,6 +32,8 @@ using namespace mozilla; using namespace mozilla::embedding; +typedef mozilla::layout::RemotePrintJobChild RemotePrintJobChild; + NS_IMPL_ISUPPORTS(nsPrintOptions, nsIPrintOptions, nsIPrintSettingsService) // Pref Constants @@ -233,6 +238,12 @@ NS_IMETHODIMP nsPrintOptions::DeserializeToPrintSettings(const PrintData& data, nsIPrintSettings* settings) { + nsCOMPtr session; + nsresult rv = settings->GetPrintSession(getter_AddRefs(session)); + if (NS_SUCCEEDED(rv) && session) { + session->SetRemotePrintJob( + static_cast(data.remotePrintJobChild())); + } settings->SetStartPageRange(data.startPageRange()); settings->SetEndPageRange(data.endPageRange()); diff --git a/widget/nsPrintSession.cpp b/widget/nsPrintSession.cpp index c4f265db2f..9b334b4247 100644 --- a/widget/nsPrintSession.cpp +++ b/widget/nsPrintSession.cpp @@ -5,6 +5,10 @@ #include "nsPrintSession.h" +#include "mozilla/layout/RemotePrintJobChild.h" + +typedef mozilla::layout::RemotePrintJobChild RemotePrintJobChild; + //***************************************************************************** //*** nsPrintSession //***************************************************************************** @@ -26,3 +30,19 @@ nsresult nsPrintSession::Init() { return NS_OK; } + +NS_IMETHODIMP +nsPrintSession::GetRemotePrintJob(RemotePrintJobChild** aRemotePrintJob) +{ + MOZ_ASSERT(aRemotePrintJob); + RefPtr result = mRemotePrintJob; + result.forget(aRemotePrintJob); + return NS_OK; +} + +NS_IMETHODIMP +nsPrintSession::SetRemotePrintJob(RemotePrintJobChild* aRemotePrintJob) +{ + mRemotePrintJob = aRemotePrintJob; + return NS_OK; +} diff --git a/widget/nsPrintSession.h b/widget/nsPrintSession.h index c7585adb94..cb349e76fb 100644 --- a/widget/nsPrintSession.h +++ b/widget/nsPrintSession.h @@ -7,8 +7,17 @@ #define nsPrintSession_h__ #include "nsIPrintSession.h" + +#include "mozilla/RefPtr.h" #include "nsWeakReference.h" +namespace mozilla { +namespace layout { +class RemotePrintJobChild; +} +} + + //***************************************************************************** //*** nsPrintSession //***************************************************************************** @@ -25,6 +34,9 @@ public: nsPrintSession(); virtual nsresult Init(); + +private: + RefPtr mRemotePrintJob; }; #endif // nsPrintSession_h__ diff --git a/widget/qt/nsDeviceContextSpecQt.cpp b/widget/qt/nsDeviceContextSpecQt.cpp index 6693d5551c..e754cc4eb0 100644 --- a/widget/qt/nsDeviceContextSpecQt.cpp +++ b/widget/qt/nsDeviceContextSpecQt.cpp @@ -151,7 +151,7 @@ NS_IMETHODIMP nsDeviceContextSpecQt::Init(nsIWidget* aWidget, NS_IMETHODIMP nsDeviceContextSpecQt::BeginDocument( const nsAString& aTitle, - char16_t* aPrintToFileName, + const nsAString& aPrintToFileName, int32_t aStartPage, int32_t aEndPage) { diff --git a/widget/qt/nsDeviceContextSpecQt.h b/widget/qt/nsDeviceContextSpecQt.h index d2bbbb6907..311a7f0e29 100644 --- a/widget/qt/nsDeviceContextSpecQt.h +++ b/widget/qt/nsDeviceContextSpecQt.h @@ -28,7 +28,7 @@ public: nsIPrintSettings* aPS, bool aIsPrintPreview); NS_IMETHOD BeginDocument(const nsAString& aTitle, - char16_t* aPrintToFileName, + const nsAString& aPrintToFileName, int32_t aStartPage, int32_t aEndPage); NS_IMETHOD EndDocument(); diff --git a/widget/windows/JumpListItem.h b/widget/windows/JumpListItem.h index 19973ccc43..c3d0733227 100644 --- a/widget/windows/JumpListItem.h +++ b/widget/windows/JumpListItem.h @@ -61,8 +61,8 @@ public: {} NS_DECL_ISUPPORTS_INHERITED - NS_IMETHOD GetType(int16_t *aType) { return JumpListItem::GetType(aType); } - NS_IMETHOD Equals(nsIJumpListItem *item, bool *_retval) { return JumpListItem::Equals(item, _retval); } + NS_IMETHOD GetType(int16_t *aType) override { return JumpListItem::GetType(aType); } + NS_IMETHOD Equals(nsIJumpListItem *item, bool *_retval) override { return JumpListItem::Equals(item, _retval); } static nsresult GetSeparator(RefPtr& aShellLink); }; @@ -77,8 +77,8 @@ public: {} NS_DECL_ISUPPORTS_INHERITED - NS_IMETHOD GetType(int16_t *aType) { return JumpListItem::GetType(aType); } - NS_IMETHOD Equals(nsIJumpListItem *item, bool *_retval); + NS_IMETHOD GetType(int16_t *aType) override { return JumpListItem::GetType(aType); } + NS_IMETHOD Equals(nsIJumpListItem *item, bool *_retval) override; NS_DECL_NSIJUMPLISTLINK static nsresult GetShellItem(nsCOMPtr& item, RefPtr& aShellItem); @@ -101,8 +101,8 @@ public: NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(JumpListShortcut, JumpListItem) - NS_IMETHOD GetType(int16_t *aType) { return JumpListItem::GetType(aType); } - NS_IMETHOD Equals(nsIJumpListItem *item, bool *_retval); + NS_IMETHOD GetType(int16_t *aType) override { return JumpListItem::GetType(aType); } + NS_IMETHOD Equals(nsIJumpListItem *item, bool *_retval) override; NS_DECL_NSIJUMPLISTSHORTCUT static nsresult GetShellLink(nsCOMPtr& item, diff --git a/widget/windows/TaskbarWindowPreview.h b/widget/windows/TaskbarWindowPreview.h index 2eba27d72f..d0719f739a 100644 --- a/widget/windows/TaskbarWindowPreview.h +++ b/widget/windows/TaskbarWindowPreview.h @@ -35,15 +35,15 @@ public: NS_DECL_NSITASKBAROVERLAYICONCONTROLLER NS_FORWARD_NSITASKBARPREVIEW(TaskbarPreview::) - virtual LRESULT WndProc(UINT nMsg, WPARAM wParam, LPARAM lParam); + virtual LRESULT WndProc(UINT nMsg, WPARAM wParam, LPARAM lParam) override; private: - virtual nsresult ShowActive(bool active); - virtual HWND &PreviewWindow(); + virtual nsresult ShowActive(bool active) override; + virtual HWND &PreviewWindow() override; - virtual nsresult UpdateTaskbarProperties(); - virtual nsresult Enable(); - virtual nsresult Disable(); - virtual void DetachFromNSWindow(); + virtual nsresult UpdateTaskbarProperties() override; + virtual nsresult Enable() override; + virtual nsresult Disable() override; + virtual void DetachFromNSWindow() override; nsresult UpdateButton(uint32_t index); nsresult UpdateButtons(); diff --git a/widget/windows/nsClipboard.h b/widget/windows/nsClipboard.h index c44afe6c20..87a7ae9d4b 100644 --- a/widget/windows/nsClipboard.h +++ b/widget/windows/nsClipboard.h @@ -35,8 +35,8 @@ public: // nsIClipboard NS_IMETHOD HasDataMatchingFlavors(const char** aFlavorList, uint32_t aLength, - int32_t aWhichClipboard, bool *_retval); - NS_IMETHOD EmptyClipboard(int32_t aWhichClipboard); + int32_t aWhichClipboard, bool *_retval) override; + NS_IMETHOD EmptyClipboard(int32_t aWhichClipboard) override; // Internal Native Routines static nsresult CreateNativeDataObject(nsITransferable * aTransferable, @@ -62,8 +62,8 @@ public: static UINT CF_HTML; protected: - NS_IMETHOD SetNativeClipboardData ( int32_t aWhichClipboard ); - NS_IMETHOD GetNativeClipboardData ( nsITransferable * aTransferable, int32_t aWhichClipboard ); + NS_IMETHOD SetNativeClipboardData ( int32_t aWhichClipboard ) override; + NS_IMETHOD GetNativeClipboardData ( nsITransferable * aTransferable, int32_t aWhichClipboard ) override; static bool IsInternetShortcut ( const nsAString& inFileName ) ; static bool FindURLFromLocalFile ( IDataObject* inDataObject, UINT inIndex, void** outData, uint32_t* outDataLen ) ; diff --git a/widget/windows/nsDeviceContextSpecWin.cpp b/widget/windows/nsDeviceContextSpecWin.cpp index 2d265d8d26..d3b48f9854 100644 --- a/widget/windows/nsDeviceContextSpecWin.cpp +++ b/widget/windows/nsDeviceContextSpecWin.cpp @@ -270,6 +270,7 @@ NS_IMETHODIMP nsDeviceContextSpecWin::GetSurfaceForPrinter(gfxASurface **surface { NS_ASSERTION(mDevMode, "DevMode can't be NULL here"); + *surface = nullptr; RefPtr newSurface; int16_t outputFormat = 0; @@ -315,19 +316,24 @@ NS_IMETHODIMP nsDeviceContextSpecWin::GetSurfaceForPrinter(gfxASurface **surface newSurface = new gfxWindowsSurface(dc, gfxWindowsSurface::FLAG_TAKE_DC | gfxWindowsSurface::FLAG_FOR_PRINTING); if (newSurface->GetType() == (gfxSurfaceType)-1) { gfxCriticalError() << "Invalid windows surface from " << gfx::hexa(dc); - newSurface = nullptr; + return NS_ERROR_FAILURE; } } } - if (newSurface) { - *surface = newSurface; - NS_ADDREF(*surface); - return NS_OK; - } + mPrintingSurface = newSurface; + newSurface.forget(surface); + return NS_OK; +} - *surface = nullptr; - return NS_ERROR_FAILURE; +float +nsDeviceContextSpecWin::GetPrintingScale() +{ + MOZ_ASSERT(mPrintingSurface); + + HDC dc = reinterpret_cast(mPrintingSurface.get())->GetDC(); + int32_t OSVal = GetDeviceCaps(dc, LOGPIXELSY); + return float(OSVal) / GetDPI(); } //---------------------------------------------------------------------------------- diff --git a/widget/windows/nsDeviceContextSpecWin.h b/widget/windows/nsDeviceContextSpecWin.h index 216c0e14b3..c0fc8197df 100644 --- a/widget/windows/nsDeviceContextSpecWin.h +++ b/widget/windows/nsDeviceContextSpecWin.h @@ -13,6 +13,7 @@ #include "nsISupportsPrimitives.h" #include #include "mozilla/Attributes.h" +#include "mozilla/RefPtr.h" class nsIWidget; @@ -23,16 +24,20 @@ public: NS_DECL_ISUPPORTS - NS_IMETHOD GetSurfaceForPrinter(gfxASurface **surface); + NS_IMETHOD GetSurfaceForPrinter(gfxASurface **surface) override; NS_IMETHOD BeginDocument(const nsAString& aTitle, - char16_t* aPrintToFileName, + const nsAString& aPrintToFileName, int32_t aStartPage, - int32_t aEndPage) { return NS_OK; } - NS_IMETHOD EndDocument() { return NS_OK; } - NS_IMETHOD BeginPage() { return NS_OK; } - NS_IMETHOD EndPage() { return NS_OK; } + int32_t aEndPage) override { return NS_OK; } + NS_IMETHOD EndDocument() override { return NS_OK; } + NS_IMETHOD BeginPage() override { return NS_OK; } + NS_IMETHOD EndPage() override { return NS_OK; } - NS_IMETHOD Init(nsIWidget* aWidget, nsIPrintSettings* aPS, bool aIsPrintPreview); + NS_IMETHOD Init(nsIWidget* aWidget, nsIPrintSettings* aPS, bool aIsPrintPreview) override; + + float GetDPI() final { return 144.0f; } + + float GetPrintingScale() final; void GetDriverName(wchar_t *&aDriverName) const { aDriverName = mDriverName; } void GetDeviceName(wchar_t *&aDeviceName) const { aDeviceName = mDeviceName; } @@ -64,6 +69,7 @@ protected: LPDEVMODEW mDevMode; nsCOMPtr mPrintSettings; + RefPtr mPrintingSurface; }; diff --git a/widget/windows/nsIdleServiceWin.h b/widget/windows/nsIdleServiceWin.h index 3e0852607f..c3fb1243fd 100644 --- a/widget/windows/nsIdleServiceWin.h +++ b/widget/windows/nsIdleServiceWin.h @@ -24,7 +24,7 @@ class nsIdleServiceWin : public nsIdleService public: NS_DECL_ISUPPORTS_INHERITED - bool PollIdleTime(uint32_t* aIdleTime); + bool PollIdleTime(uint32_t* aIdleTime) override; static already_AddRefed GetInstance() { @@ -40,7 +40,7 @@ public: protected: nsIdleServiceWin() { } virtual ~nsIdleServiceWin() { } - bool UsePollMode(); + bool UsePollMode() override; }; #endif // nsIdleServiceWin_h__ diff --git a/widget/windows/nsNativeThemeWin.h b/widget/windows/nsNativeThemeWin.h index 56ec44469e..306c6764f6 100644 --- a/widget/windows/nsNativeThemeWin.h +++ b/widget/windows/nsNativeThemeWin.h @@ -31,44 +31,44 @@ public: nsIFrame* aFrame, uint8_t aWidgetType, const nsRect& aRect, - const nsRect& aDirtyRect); + const nsRect& aDirtyRect) override; NS_IMETHOD GetWidgetBorder(nsDeviceContext* aContext, nsIFrame* aFrame, uint8_t aWidgetType, - nsIntMargin* aResult); + nsIntMargin* aResult) override; virtual bool GetWidgetPadding(nsDeviceContext* aContext, nsIFrame* aFrame, uint8_t aWidgetType, - nsIntMargin* aResult); + nsIntMargin* aResult) override; virtual bool GetWidgetOverflow(nsDeviceContext* aContext, nsIFrame* aFrame, uint8_t aWidgetType, - nsRect* aOverflowRect); + nsRect* aOverflowRect) override; NS_IMETHOD GetMinimumWidgetSize(nsPresContext* aPresContext, nsIFrame* aFrame, uint8_t aWidgetType, mozilla::LayoutDeviceIntSize* aResult, - bool* aIsOverridable); + bool* aIsOverridable) override; - virtual Transparency GetWidgetTransparency(nsIFrame* aFrame, uint8_t aWidgetType); + virtual Transparency GetWidgetTransparency(nsIFrame* aFrame, uint8_t aWidgetType) override; NS_IMETHOD WidgetStateChanged(nsIFrame* aFrame, uint8_t aWidgetType, - nsIAtom* aAttribute, bool* aShouldRepaint); + nsIAtom* aAttribute, bool* aShouldRepaint) override; - NS_IMETHOD ThemeChanged(); + NS_IMETHOD ThemeChanged() override; bool ThemeSupportsWidget(nsPresContext* aPresContext, nsIFrame* aFrame, - uint8_t aWidgetType); + uint8_t aWidgetType) override; - bool WidgetIsContainer(uint8_t aWidgetType); + bool WidgetIsContainer(uint8_t aWidgetType) override; bool ThemeDrawsFocusForWidget(uint8_t aWidgetType) override; - bool ThemeNeedsComboboxDropmarker(); + bool ThemeNeedsComboboxDropmarker() override; virtual bool WidgetAppearanceDependsOnWindowFocus(uint8_t aWidgetType) override; diff --git a/widget/windows/nsWindow.h b/widget/windows/nsWindow.h index 2250908f37..c8a34d7506 100644 --- a/widget/windows/nsWindow.h +++ b/widget/windows/nsWindow.h @@ -98,67 +98,67 @@ public: NS_IMETHOD Create(nsIWidget* aParent, nsNativeWidget aNativeParent, const LayoutDeviceIntRect& aRect, - nsWidgetInitData* aInitData = nullptr); - NS_IMETHOD Destroy(); - NS_IMETHOD SetParent(nsIWidget *aNewParent); - virtual nsIWidget* GetParent(void); - virtual float GetDPI(); - virtual double GetDefaultScaleInternal(); - NS_IMETHOD Show(bool bState); - virtual bool IsVisible() const; - NS_IMETHOD ConstrainPosition(bool aAllowSlop, int32_t *aX, int32_t *aY); - virtual void SetSizeConstraints(const SizeConstraints& aConstraints); - NS_IMETHOD Move(double aX, double aY); - NS_IMETHOD Resize(double aWidth, double aHeight, bool aRepaint); + nsWidgetInitData* aInitData = nullptr) override; + NS_IMETHOD Destroy() override; + NS_IMETHOD SetParent(nsIWidget *aNewParent) override; + virtual nsIWidget* GetParent(void) override; + virtual float GetDPI() override; + virtual double GetDefaultScaleInternal() override; + NS_IMETHOD Show(bool bState) override; + virtual bool IsVisible() const override; + NS_IMETHOD ConstrainPosition(bool aAllowSlop, int32_t *aX, int32_t *aY) override; + virtual void SetSizeConstraints(const SizeConstraints& aConstraints) override; + NS_IMETHOD Move(double aX, double aY) override; + NS_IMETHOD Resize(double aWidth, double aHeight, bool aRepaint) override; NS_IMETHOD Resize(double aX, double aY, double aWidth, double aHeight, bool aRepaint); NS_IMETHOD BeginResizeDrag(mozilla::WidgetGUIEvent* aEvent, int32_t aHorizontal, - int32_t aVertical); - NS_IMETHOD PlaceBehind(nsTopLevelWidgetZPlacement aPlacement, nsIWidget *aWidget, bool aActivate); - NS_IMETHOD SetSizeMode(nsSizeMode aMode); - NS_IMETHOD Enable(bool aState); - virtual bool IsEnabled() const; - NS_IMETHOD SetFocus(bool aRaise); + int32_t aVertical) override; + NS_IMETHOD PlaceBehind(nsTopLevelWidgetZPlacement aPlacement, nsIWidget *aWidget, bool aActivate) override; + NS_IMETHOD SetSizeMode(nsSizeMode aMode) override; + NS_IMETHOD Enable(bool aState) override; + virtual bool IsEnabled() const override; + NS_IMETHOD SetFocus(bool aRaise) override; NS_IMETHOD GetBounds(LayoutDeviceIntRect& aRect) override; NS_IMETHOD GetScreenBounds(LayoutDeviceIntRect& aRect) override; NS_IMETHOD GetRestoredBounds(LayoutDeviceIntRect& aRect) override; NS_IMETHOD GetClientBounds(LayoutDeviceIntRect& aRect) override; virtual LayoutDeviceIntPoint GetClientOffset() override; - void SetBackgroundColor(const nscolor& aColor); + void SetBackgroundColor(const nscolor& aColor) override; NS_IMETHOD SetCursor(imgIContainer* aCursor, - uint32_t aHotspotX, uint32_t aHotspotY); - NS_IMETHOD SetCursor(nsCursor aCursor); - virtual nsresult ConfigureChildren(const nsTArray& aConfigurations); - NS_IMETHOD MakeFullScreen(bool aFullScreen, nsIScreen* aScreen = nullptr); - NS_IMETHOD HideWindowChrome(bool aShouldHide); + uint32_t aHotspotX, uint32_t aHotspotY) override; + NS_IMETHOD SetCursor(nsCursor aCursor) override; + virtual nsresult ConfigureChildren(const nsTArray& aConfigurations) override; + NS_IMETHOD MakeFullScreen(bool aFullScreen, nsIScreen* aScreen = nullptr) override; + NS_IMETHOD HideWindowChrome(bool aShouldHide) override; NS_IMETHOD Invalidate(bool aEraseBackground = false, bool aUpdateNCArea = false, bool aIncludeChildren = false); NS_IMETHOD Invalidate(const LayoutDeviceIntRect& aRect); - virtual void* GetNativeData(uint32_t aDataType); + virtual void* GetNativeData(uint32_t aDataType) override; void SetNativeData(uint32_t aDataType, uintptr_t aVal) override; - virtual void FreeNativeData(void * data, uint32_t aDataType); - NS_IMETHOD SetTitle(const nsAString& aTitle); - NS_IMETHOD SetIcon(const nsAString& aIconSpec); - virtual LayoutDeviceIntPoint WidgetToScreenOffset(); + virtual void FreeNativeData(void * data, uint32_t aDataType) override; + NS_IMETHOD SetTitle(const nsAString& aTitle) override; + NS_IMETHOD SetIcon(const nsAString& aIconSpec) override; + virtual LayoutDeviceIntPoint WidgetToScreenOffset() override; virtual LayoutDeviceIntSize ClientToWindowSize(const LayoutDeviceIntSize& aClientSize) override; NS_IMETHOD DispatchEvent(mozilla::WidgetGUIEvent* aEvent, - nsEventStatus& aStatus); - NS_IMETHOD EnableDragDrop(bool aEnable); - NS_IMETHOD CaptureMouse(bool aCapture); + nsEventStatus& aStatus) override; + NS_IMETHOD EnableDragDrop(bool aEnable) override; + NS_IMETHOD CaptureMouse(bool aCapture) override; NS_IMETHOD CaptureRollupEvents(nsIRollupListener * aListener, - bool aDoCapture); - NS_IMETHOD GetAttention(int32_t aCycleCount); - virtual bool HasPendingInputEvent(); + bool aDoCapture) override; + NS_IMETHOD GetAttention(int32_t aCycleCount) override; + virtual bool HasPendingInputEvent() override; virtual LayerManager* GetLayerManager(PLayerTransactionChild* aShadowManager = nullptr, LayersBackend aBackendHint = mozilla::layers::LayersBackend::LAYERS_NONE, LayerManagerPersistence aPersistence = LAYER_MANAGER_CURRENT, - bool* aAllowRetaining = nullptr); + bool* aAllowRetaining = nullptr) override; NS_IMETHOD OnDefaultButtonLoaded(const LayoutDeviceIntRect& aButtonRect) override; NS_IMETHOD OverrideSystemMouseScrollSpeed(double aOriginalDeltaX, double aOriginalDeltaY, double& aOverriddenDeltaX, - double& aOverriddenDeltaY); + double& aOverriddenDeltaY) override; virtual nsresult SynthesizeNativeKeyEvent(int32_t aNativeKeyboardLayout, int32_t aNativeKeyCode, @@ -184,17 +184,17 @@ public: uint32_t aAdditionalFlags, nsIObserver* aObserver) override; NS_IMETHOD_(void) SetInputContext(const InputContext& aContext, - const InputContextAction& aAction); - NS_IMETHOD_(InputContext) GetInputContext(); + const InputContextAction& aAction) override; + NS_IMETHOD_(InputContext) GetInputContext() override; #ifdef MOZ_XUL - virtual void SetTransparencyMode(nsTransparencyMode aMode); - virtual nsTransparencyMode GetTransparencyMode(); - virtual void UpdateOpaqueRegion(const LayoutDeviceIntRegion& aOpaqueRegion); + virtual void SetTransparencyMode(nsTransparencyMode aMode) override; + virtual nsTransparencyMode GetTransparencyMode() override; + virtual void UpdateOpaqueRegion(const LayoutDeviceIntRegion& aOpaqueRegion) override; #endif // MOZ_XUL - virtual nsIMEUpdatePreference GetIMEUpdatePreference(); + virtual nsIMEUpdatePreference GetIMEUpdatePreference() override; NS_IMETHOD GetNonClientMargins(LayoutDeviceIntMargin& aMargins) override; NS_IMETHOD SetNonClientMargins(LayoutDeviceIntMargin& aMargins) override; - void SetDrawsInTitlebar(bool aState); + void SetDrawsInTitlebar(bool aState) override; already_AddRefed StartRemoteDrawing() override; virtual void EndRemoteDrawing() override; virtual void UpdateWindowDraggingRegion(const LayoutDeviceIntRegion& aRegion) override; @@ -277,7 +277,7 @@ public: } void SetTaskbarPreview(nsITaskbarWindowPreview *preview) { mTaskbarPreview = do_GetWeakReference(preview); } - NS_IMETHOD ReparentNativeWidget(nsIWidget* aNewParent); + NS_IMETHOD ReparentNativeWidget(nsIWidget* aNewParent) override; // Open file picker tracking void PickerOpen(); @@ -286,9 +286,9 @@ public: bool const DestroyCalled() { return mDestroyCalled; } bool IsPopup(); - virtual bool ShouldUseOffMainThreadCompositing(); + virtual bool ShouldUseOffMainThreadCompositing() override; - bool CaptureWidgetOnScreen(RefPtr aDT); + bool CaptureWidgetOnScreen(RefPtr aDT) override; const IMEContext& DefaultIMC() const { return mDefaultIMC; } @@ -386,7 +386,7 @@ protected: /** * Event handlers */ - virtual void OnDestroy(); + virtual void OnDestroy() override; virtual bool OnResize(nsIntRect &aWindowRect); bool OnGesture(WPARAM wParam, LPARAM lParam); bool OnTouch(WPARAM wParam, LPARAM lParam);