Compare commits

...
Author SHA1 Message Date
Moonchild 3a4dc8de41 Issue #3020 - Clear currentScript after running microtasks
Per HTML spec:

`document.currentScript` Returns null if the Document is not currently
executing a script or SVG script element (e.g., because the running
script is an event handler, or a timeout), or if the currently executing
script or SVG script element represents a module script.

---

It's ambiguous about whether, for micro tasks, it should return null.
(This section is labelled as "non-normative", as well.)
However, mainstream browsers handle this differently and don't return
null after running microtasks, so we need to clear this and not assume
null persistently, and run the auto-updater for it, regardless if
it's a module or not.
2026-03-24 20:44:13 +01:00
Moonchild 18595b01b6 Issue #3020 - Update currentScript when dealing with shadow DOM.
`currentScript` should be null when evaluating scripts from shadow DOM.
2026-03-24 15:53:04 +01:00
Moonchild f7215fc685 Issue #3020 - document.currentScript should be null in modules
This is done correctly in `EvaluateScript`, but `CreateModuleScript` was
still setting currentScript to an element.
2026-03-24 15:50:34 +01:00
Moonchild 08521d4651 Merge pull request 'Remove Itanium/ia64 support from xpcom' (#3018) from Basilisk-Dev/UXP-contrib:xpcom-itanium-cleanup into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/3018
2026-03-24 11:18:04 +00:00
Moonchild 00b177d75f Merge pull request 'Fix Shadow DOM spellchecker crash' (#3014) from spellcheck-shadowdom-work into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/3014
2026-03-23 23:48:49 +00:00
Moonchild a89a071049 Merge pull request 'implement TypedArray.prototype.with' (#3019) from Basilisk-Dev/UXP-contrib:typedarray-with into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/3019
2026-03-23 15:18:47 +00:00
Basilisk-Dev f9dc8a091a Issue #2551 - implement TypedArray.prototype.with 2026-03-23 08:50:01 -04:00
Basilisk-Dev 944299ed6c Issue #3007 - Remove Itanium/ia64 support from xpcom 2026-03-23 08:15:51 -04:00
Moonchild 0e1441155c Merge pull request 'Issue #3016 - allow url.CanParse to use custom-scheme bases to match current spec' (#3017) from Basilisk-Dev/UXP-contrib:url-canparse-spec-compliance into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/3017
2026-03-23 05:23:18 +00:00
Moonchild 7bf5dfe4e4 Merge pull request 'Modify valgrind logging in libavutil to require MOZ_VALGRIND' (#3010) from Basilisk-Dev/UXP-contrib:ffvpx-valgrind into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/3010
Reviewed-by: Moonchild <moonchild@palemoon.org>
2026-03-22 21:23:00 +00:00
Basilisk-Dev d4c34fc9f7 Issue #3009 - updated libavutil to keep HAVE_VALGRIND_VALGRIND_H as the primary gate, with MOZ_VALGRIND added inside it 2026-03-22 16:57:34 -04:00
Basilisk-Dev 6811005551 Issue #3016 - allow url.CanParse to use custom-scheme bases to match current spec 2026-03-22 16:48:43 -04:00
Moonchild 464cefa127 Merge pull request 'Attempt to fix Cloudflare image resizing' (#3012) from wuggy/UXP:master into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/3012
Reviewed-by: Moonchild <moonchild@palemoon.org>
2026-03-22 14:42:51 +00:00
Moonchild c94a1ab5d3 Merge pull request 'Issue #3007 - remove itanium support and references from webrtc' (#3015) from Basilisk-Dev/UXP-contrib:webrtc-itanium-cleanup into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/3015
2026-03-22 14:40:10 +00:00
Basilisk-Dev 8aa5b35605 Issue #3007 - remove itanium support and references from webrtc 2026-03-22 01:05:18 -04:00
Basilisk-Dev 25dd1fb31a Issue #3009 - restore valgrind functionality in libavutil and hide behind MOZ_VALGRIND instead 2026-03-21 22:52:25 -04:00
wuggy d8cf2c8b44 Cloudflare Image Resizing fix take 3 part 2 (all.js) 2026-03-21 13:28:57 +00:00
wuggy 938c5d08d4 Cloudflare Image Resizing fix take 3 part 1 (main fixup) 2026-03-21 13:26:34 +00:00
Moonchild 7fca2b8de3 Issue #2739 - Follow-up: remove missed configure bits.
We still accepted {en|dis}able-jxl as a valid old-configure option and
there were a few leftover pref conditionals.
2026-03-21 11:57:15 +01:00
wuggy ef19ad3ffd Cloudflare Image Resizing fix take 2
Better documentation and about:config pref controlled (network.url.cloudflare_image_resizing.enabled)
2026-03-20 19:02:52 +00:00
Moonchild ab88527fe6 Issue #3011 - Part 3: Handle edge case for spellchecking.
Make spellchecking work in Shadow DOM after anchor navigates away from it.
2026-03-20 17:07:55 +01:00
Moonchild 6c0ff1881a Issue #3011 - Part 2: Switch spellchecker root to Shadow DOM.
Set the root for spelling checker to shadow root if the contenteditable
nodes are in the shadow DOM. Bail if the position can't be set properly.
2026-03-20 14:45:11 +01:00
Moonchild 1e7f4c8474 Issue #3011 - Part 1: Add As{Text|Html}Editor() and AsEditorBase()
This adds helper functions to get specific types of content editors (if
possible) through the nsIEditor interface, as opposed to doing manual
casting and the ad hoc `GetHTMLEditor()` function.

Helper functions are spread out over multiple headers due to the
circular dependency issues that would be triggered otherwise.
2026-03-20 13:26:18 +01:00
wuggy fdf491d4ec Cloudflare Image Resizing fix 2026-03-20 10:18:45 +00:00
Basilisk-Dev 1f4cceca43 Issue #3009 - Remove valgrind logging in libavutil so that valgrind is no longer required at build time 2026-03-18 19:44:28 -04:00
Moonchild 542eaca577 Merge pull request 'LoongArch Support Followup - Do not hardcode jemalloc page size on LoongArch' (#3006) from Basilisk-Dev/UXP-contrib:loongarchpagesize into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/3006
2026-03-18 23:02:13 +00:00
Basilisk-Dev 1cb6f56418 Issue #2897 followup - Do not hardcode jemalloc page size on LoongArch
Loongarch can run on either a 4k or 16k page size
2026-03-18 18:14:27 -04:00
Moonchild a503e883d9 Merge pull request 'Don't attempt on-stack replacement for TLA modules when interpreter loop encounters JSOP_LOOPENTRY' (#3002) from jobbautista9/UXP:2229-jsop_loopentry into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/3002
2026-03-18 15:21:31 +00:00
Moonchild 347681c219 Merge pull request 'Implement array.prototype.toSpliced and array.prototype.with' (#3005) from Basilisk-Dev/UXP-contrib:arraybycopy into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/3005
2026-03-17 20:31:34 +00:00
Basilisk-Dev 2984237f4f Issue #2551 - implement array.prototype.toSpliced 2026-03-16 14:33:50 -04:00
Basilisk-Dev 1c4a73de71 Issue #2551 - implement array.prototype.with 2026-03-16 14:27:02 -04:00
Job Bautista d27df4d88f Issue #2229 - Follow-up: Don't attempt on-stack replacement for TLA modules
When interpreter loop encounters JSOP_LOOPENTRY, we should not let TLA modules
enter baseline JIT.
2026-03-16 11:28:25 +08:00
Moonchild 9562888e77 Merge pull request 'Flatten nested CSS to standard CSS before parsing (fix sites using nested CSS)' (#2999) from Basilisk-Dev/UXP-contrib:nested-css into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/2999
Reviewed-by: Moonchild <moonchild@palemoon.org>
2026-03-14 18:24:58 +00:00
Moonchild 5536b38401 Merge pull request 'Add AudioNode constructors' (#2988) from audionode-constructors-pr into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/2988
2026-03-14 18:19:08 +00:00
Moonchild c011b271a1 Issue #3001 - Restore table reference frame call.
While the result value was only used for debug purposes, the function
`FindReferenceFrameFor` also updates the reference frame for use
outside of debug builds. The opaque double use of this function
was not clear from code inspection and it was erroneously removed.

Resolves #3001
2026-03-14 19:16:41 +01:00
Basilisk-Dev c21fb81d3e Issue #2862 - css nesting pref true by default 2026-03-14 13:23:54 -04:00
Basilisk-Dev 5a3dcf5939 Issue #2862 - Remove unused vars in CSS flattener 2026-03-14 13:22:59 -04:00
Moonchild 1d709fe942 Merge pull request 'Update expat source to 2.7.4 and apply local patches' (#2998) from jobbautista9/UXP:expat-2.7.4 into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/2998
2026-03-13 17:06:21 +00:00
Moonchild e55c16146f Issue #2993 - Follow-up: Clobber. 2026-03-13 16:19:56 +01:00
Basilisk-Dev 997a9a3e13 Issue #2862 - Change tests from lowering to flattening 2026-03-13 09:01:56 -04:00
Basilisk-Dev 008f38579c Issue #2862 - Change code references from CSS lowering to CSS flattening 2026-03-13 08:58:18 -04:00
Basilisk-Dev d943e86b28 Issue #2862 - handle more edge cases in css lowering 2026-03-12 08:44:03 -04:00
Basilisk-Dev 3f2d707a83 Issue #2862 - more tests files for nested css 2026-03-12 08:43:58 -04:00
Basilisk-Dev b145a93ad6 Issue #2862 - Split the css lowering functionality out to a separate file for easier maintenance 2026-03-12 08:43:53 -04:00
Basilisk-Dev 3056028db4 Issue #2862 - Fix a few nested selectors 2026-03-12 08:43:48 -04:00
Basilisk-Dev b4dac14720 Issue #2862 - Modify the css lowerer so that the lowering pass now recognizes bare type-selector nested rules and combinator-led cases 2026-03-12 08:43:42 -04:00
Basilisk-Dev 76694b956f Issue #2862 - add initial nested css test file 2026-03-12 08:43:33 -04:00
Basilisk-Dev 9fab5b3e3c Issue #2862 - Initial attempt at a css lowering 2026-03-12 08:43:23 -04:00
Job Bautista d54491fdd0 Issue #2997 - Update expat source to 2.7.4 and apply local patches. 2026-03-12 13:50:10 +08:00
Moonchild 00c3c3a546 Merge pull request 'Only use SVE instructions on Apple Silicon (disable on aarch64 Linux)' (#2994) from Basilisk-Dev/UXP-contrib:vpx-sve into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/2994
2026-03-11 20:50:08 +00:00
Moonchild 1da5c344be Merge pull request 'Implement TypedArray.prototype.toReversed()' (#2996) from Basilisk-Dev/UXP-contrib:typed-toReversed into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/2996
2026-03-11 20:28:21 +00:00
Moonchild 76d66b5dad Merge pull request 'Work around macOS WebGL crash on unconsumed vertex attrib arrays' (#2995) from Basilisk-Dev/UXP-contrib:webgl-crash into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/2995
2026-03-11 20:23:20 +00:00
Basilisk-Dev e502735eb2 Issue #2993 - only use SVE instructions on Apple Silicon (disable on aarch64 Linux) 2026-03-11 15:07:09 -04:00
Basilisk-Dev edfebe1b99 Issue #2551 - Implement TypedArray.prototype.toReversed() 2026-03-11 15:04:16 -04:00
Moonchild 250e4f75da Merge pull request 'Avoid empty replacements in macro expansion.' (#2986) from 2978 into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/2986
2026-03-11 19:03:59 +00:00
Basilisk-Dev 53f1bdd9c2 Issue #2978 - Work around macOS WebGL crash on unconsumed vertex attrib arrays 2026-03-11 14:25:20 -04:00
Moonchild ade298d0a7 Merge pull request 'Issue #2990 - implement object.GroupBy' (#2991) from Basilisk-Dev/UXP-contrib:objectgroupby into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/2991
2026-03-10 15:24:08 +00:00
Basilisk-Dev 387b01ce14 Issue #2990 - implement object.GroupBy 2026-03-10 10:45:54 -04:00
Moonchild 47d2094329 Merge pull request 'Issue #2926 - Tweak mimalloc performance tunables' (#2989) from Basilisk-Dev/UXP-contrib:mimalloc-tweaks into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/2989
2026-03-10 13:48:48 +00:00
Basilisk-Dev 43f9a8e1f0 Issue #2926 - Tweak mimalloc performance tunables:
MI_DEFAULT_PURGE_DECOMMITS=0 - fewer costly kernel operations and fewer immediate recommit/zero-fill penalties on reuse.

MI_DEFAULT_PURGE_DELAY=500 - short-lived allocation bursts can reuse pages directly, avoiding purge/reclaim ping-pong.

MI_DEFAULT_GENERIC_COLLECT=50000 - lower background allocator housekeeping overhead on hot allocation paths.
2026-03-10 09:08:14 -04:00
Moonchild 30e287371f Issue #2987 - Part 19: Add MediaStreamAudioDestinationNode constructor. 2026-03-10 11:19:11 +01:00
Moonchild a9246d7b28 Issue #2987 - Part 18: Add MediaStreamAudioSourceNode constructor. 2026-03-10 11:19:05 +01:00
Moonchild db1d73f05d Issue #2987 - Part 17: Add MediaElementAudioSourceNode constructor. 2026-03-10 11:18:39 +01:00
Moonchild 72b14ea177 Issue #2987 - Part 16: Add AudioBuffer constructor. 2026-03-10 11:18:02 +01:00
Moonchild 430c4a3f79 Issue #2987 - Part 15: Add PeriodicWave constructor. 2026-03-10 11:17:57 +01:00
Moonchild 93ed92f63b Issue #2987 - Part 14: Add OscillatorNode constructor. 2026-03-10 11:17:53 +01:00
Moonchild 4a1312c060 Issue #2987 - Part 13: Add DynamicsCompressorNode constructor. 2026-03-10 11:17:47 +01:00
Moonchild 303e1ecf34 Issue #2987 - Part 12: Add ChannelMergerNode constructor. 2026-03-10 11:17:42 +01:00
Moonchild 57b0e4a65b Issue #2987 - Part 11: Add ChannelSplitterNode constructor. 2026-03-10 11:17:38 +01:00
Moonchild 804a301068 Issue #2987 - Part 10: Add ConvolverNode constructor. 2026-03-10 11:17:32 +01:00
Moonchild aedb8a4d08 Issue #2987 - Part 9: Add StereoPannerNode constructor. 2026-03-10 11:17:27 +01:00
Moonchild 93072ab51e Issue #2987 - Part 8: Add PannerNode constructor. 2026-03-10 11:17:22 +01:00
Moonchild ca11a325bd Issue #2987 - Part 7: Add WaveShaperNode constructor. 2026-03-10 11:17:17 +01:00
Moonchild 3b088af0b1 Issue #2987 - Part 6: Add IIRFilterNode constructor. 2026-03-10 11:17:12 +01:00
Moonchild 09e52646e9 Issue #2987 - Part 5: Add BiQuadFilterNode constructor. 2026-03-10 11:17:07 +01:00
Moonchild 26ca6f4fcc Issue #2987 - Part 4: Add DelayNode constructor. 2026-03-10 11:17:02 +01:00
Moonchild b467d710ac Issue #2987 - Part 3: Add GainNode constructor. 2026-03-10 11:16:56 +01:00
Moonchild f4f11fada8 Issue #2987 - Part 2: Add AudioBufferSourceNode constructor. 2026-03-10 11:16:49 +01:00
Moonchild 43b3b47426 Issue #2987 - Part 1: Add AnalyserNode constructor. 2026-03-10 11:16:43 +01:00
Moonchild 77f8cae06e Issue #2978 - Avoid empty replacements in macro expansion.
If the replacements array is empty, don't attempt to do any work on the
existing macro, and return. This should prevent infinite recursion in
some cases.
Order matters here: we're relying on the `if` statement shortcut so
`collectMacroArgs()` doesn't get called.
2026-03-09 16:04:57 +01:00
Moonchild daa31cfd59 No issue - Fix some fatal printing assertions.
- Turn a fatal assert into a warning if we can't guarantee a drawTarget.
  This should not be fatal since the DrawTarget is checked later.
- Remove a fatal assertion if a display table background is cross-document
  since non-display iframes may cause this situation without it being an
  error.
2026-03-09 11:30:38 +01:00
Moonchild b4ad4b7293 Issue #2981 - Add nullcheck in GetPointerCapabilities
Resolves #2981
2026-03-09 11:27:25 +01:00
Moonchild a2947909e8 Merge pull request 'Issue #2982 - Implement oklab/oklch' (#2983) from Basilisk-Dev/UXP-contrib:oklab-oklch into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/2983
2026-03-08 07:27:26 +00:00
Moonchild bc2d0521e7 Merge pull request 'Implement ES2022 error.cause property' (#2984) from dbsoft/UXP:error-cause-2304 into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/2984
2026-03-07 21:17:22 +00:00
Moonchild 95ca42dd06 Merge pull request 'Handle special cases for certain MacOS system fonts.' (#2985) from dbsoft/UXP:mac-variation-fonts into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/2985
2026-03-07 21:00:44 +00:00
Brian Smith 0c0dfca015 Issue #2304 - Part 5 - Add cause property when a cause is present.
I thought this was just to check whether it should be added, but is necessary.
2026-03-07 01:41:07 -06:00
Brian Smith 17cd2e4d07 Issue #2304 - Part 4 - Add xray support for the Error cause property.
https://bugzilla.mozilla.org/show_bug.cgi?id=1679653
2026-03-07 01:17:18 -06:00
Brian Smith f305547835 Issue #2304 - Part 3 - Implement the error cause proposal.
https://bugzilla.mozilla.org/show_bug.cgi?id=1679653
2026-03-07 00:41:42 -06:00
Brian Smith 5ee86104a8 Issue #2304 - Part 2 - Prerequisite: Teach GCPolicy about Maybe.
https://bugzilla.mozilla.org/show_bug.cgi?id=1377008
2026-03-06 23:47:55 -06:00
Basilisk-Dev 0ab247bee9 Issue #2982 - Fix regressions in the previous regression fix commit. 2026-03-06 16:27:12 -05:00
Basilisk-Dev 5370edc560 Issue #2982 - Fix regression in previous commit by handling possible floating point issues 2026-03-06 16:27:12 -05:00
Basilisk-Dev f27b6cbd21 Issue #2982 - clamp oklab/oklch to [0,1] before conversion to closer match spec 2026-03-06 16:27:12 -05:00
Basilisk-Dev de3485ed67 Issue #2982 - Make gradients work in oklch 2026-03-06 16:27:12 -05:00
Basilisk-Dev 7f8489bc11 Issue #2982 - Initial oklch test implementation 2026-03-06 16:27:07 -05:00
Brian Smith 8c1cf4cc02 Issue #2304 - Part 1 - Prerequisite: Make Handle<Maybe<>> more convenient.
This is required to implement JS::NothingHandleValue.
https://bugzilla.mozilla.org/show_bug.cgi?id=1631114
2026-03-06 13:13:21 -06:00
Moonchild b8fbac6365 Merge pull request 'Futureproof Internal ICU Whitespace' (#2980) from RealityRipple/UXP:alt-space-ex into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/2980
2026-03-06 12:53:00 +00:00
Andy c7cc4ef650 Support All White Spaces in ICU Replacement from PR #2921
In case Unicode adds additional alternate spaces to formats in the future, the wsCompat argument will be ready.
I also switched over to the `u_isUWhiteSpace` alias, which is functionally identical to `UCHAR_WHITE_SPACE` at present, just in case the alias ever expands beyond the const.
2026-03-06 03:36:27 -08:00
Moonchild 9d1789b62f Merge pull request 'Stop exposing plugin preferences if support isn't built' (#2975) from 2879 into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/2975
2026-03-06 09:52:50 +00:00
Moonchild 9a1c99e1a2 Issue #2879 - Stop exposing additional prefs
This stops exposing some additional preferences that are NPAPI-only.
2026-03-06 09:44:41 +01:00
Moonchild abc435f18e Merge pull request 'Futureproof ParseDate Whitespace' (#2979) from RealityRipple/UXP:alt-space into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/2979
2026-03-06 08:38:44 +00:00
Andy 2e6dab8672 Support Unicode White Spaces in ParseDate() 2026-03-05 17:32:10 -08:00
Moonchild e0b95b12da Merge pull request 'Implement ES2018 Proxy ownKeys duplicate-key invariant and update affected conformance tests.' (#2977) from Basilisk-Dev/UXP-contrib:es2018-proxy-updates into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/2977
2026-03-04 17:19:08 +00:00
Basilisk-Dev 722ecd0d97 Issue #2976 - Implement ES2018 Proxy ownKeys duplicate-key invariant and update affected conformance tests. 2026-03-04 10:37:58 -05:00
Moonchild e72cc38641 Issue #2879 - Remove obsolete crash reporter prefs. 2026-03-04 15:31:41 +01:00
Moonchild ae227b8743 Issue #2879 - Do not expose plugin-specific prefs if support isn't built.
- Puts prefs behind conditional defines
- Removes obsolete plugin finder pref
- Removes obsolete unrestricted xpconnect plugin pref
2026-03-04 14:54:13 +01:00
Moonchild a268e57967 Merge pull request 'Issue #2957 - make WeakRefObject finalize on main thread (no background finalize)' (#2973) from Basilisk-Dev/UXP-contrib:weakref-crash into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/2973
2026-03-04 11:11:57 +00:00
Moonchild 9f05dad78c Merge pull request 'Fix clang builds on 32-bit ARM Linux.' (#2972) from dbsoft/UXP:clang-arm-linux into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/2972
2026-03-04 11:10:57 +00:00
Basilisk-Dev ba0112d574 Issue #2957 - make WeakRefObject finalize on main thread (no background finalize) 2026-03-02 00:01:39 -05:00
Brian Smith 18096194f5 No Issue - Fix clang builds on 32-bit ARM Linux.
The clang integrated assembler can't handle these files.
2026-02-28 11:45:35 +00:00
Brian Smith b4e9888d91 No Issue - Handle special cases for MacOS system fonts.
Work done by Jazzzny based on the following bugs:
https://bugzilla.mozilla.org/show_bug.cgi?id=1321031
https://bugzilla.mozilla.org/show_bug.cgi?id=1349308
Example page:
http://codepen.io/dangayle/pen/RpMVqY
2026-02-26 19:14:46 -06:00
192 changed files with 12000 additions and 6102 deletions

No files matched your search

+1 -1
View File
@@ -22,4 +22,4 @@
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
# don't change CLOBBER for WebIDL changes any more.
Clobber for ICU 78.1
Clobber for libvpx changes
-1
View File
@@ -127,7 +127,6 @@ def old_configure_options(*options):
'--enable-alsa',
'--enable-appcompat-guid',
'--enable-av1',
'--enable-jxl',
'--enable-b2g-bt',
'--enable-b2g-camera',
'--enable-b2g-ril',
+1
View File
@@ -16,6 +16,7 @@
#include "mozilla/CORSMode.h"
#include "mozilla/EventDispatcher.h"
#include "mozilla/EventListenerManager.h"
#include "mozilla/HTMLEditor.h"
#include "mozilla/InternalMutationEvent.h"
#include "mozilla/Likely.h"
#include "mozilla/MemoryReporting.h"
+76 -14
View File
@@ -9,6 +9,7 @@
#include "mozilla/CheckedInt.h"
#include "mozilla/UniquePtrExtensions.h"
#include "nsPrintfCString.h"
#include "WebGLActiveInfo.h"
#include "WebGLBuffer.h"
#include "WebGLContextUtils.h"
#include "WebGLFramebuffer.h"
@@ -27,6 +28,30 @@ namespace mozilla {
// For a Tegra workaround.
static const int MAX_DRAW_CALLS_SINCE_FLUSH = 100;
static uint8_t
NumUsedLocationsByElemTypeForDraw(GLenum elemType)
{
switch (elemType) {
case LOCAL_GL_FLOAT_MAT2:
case LOCAL_GL_FLOAT_MAT2x3:
case LOCAL_GL_FLOAT_MAT2x4:
return 2;
case LOCAL_GL_FLOAT_MAT3x2:
case LOCAL_GL_FLOAT_MAT3:
case LOCAL_GL_FLOAT_MAT3x4:
return 3;
case LOCAL_GL_FLOAT_MAT4x2:
case LOCAL_GL_FLOAT_MAT4x3:
case LOCAL_GL_FLOAT_MAT4:
return 4;
default:
return 1;
}
}
////////////////////////////////////////
class ScopedResolveTexturesForDraw
@@ -331,6 +356,7 @@ class ScopedDrawHelper final
{
WebGLContext* const mWebGL;
bool mDidFake;
std::vector<GLuint> mDisabledUnusedAttribs;
public:
ScopedDrawHelper(WebGLContext* webgl, const char* funcName, uint32_t firstVertex,
@@ -367,11 +393,43 @@ public:
}
mDidFake = true;
const auto& linkInfo = mWebGL->mActiveProgramLinkInfo;
#ifdef XP_MACOSX
if (mWebGL->gl->WorkAroundDriverBugs()) {
std::vector<bool> isActiveAttrib(mWebGL->mBoundVertexArray->mAttribs.Length(),
false);
for (const auto& progAttrib : linkInfo->attribs) {
const auto loc = progAttrib.mLoc;
if (loc < 0) {
continue;
}
const auto usedLocs =
NumUsedLocationsByElemTypeForDraw(progAttrib.mActiveInfo->mElemType);
for (uint32_t i = 0; i < usedLocs; ++i) {
const auto usedLoc = static_cast<uint32_t>(loc) + i;
if (usedLoc < isActiveAttrib.size()) {
isActiveAttrib[usedLoc] = true;
}
}
}
for (uint32_t i = 0; i < mWebGL->mBoundVertexArray->mAttribs.Length(); ++i) {
const auto& attrib = mWebGL->mBoundVertexArray->mAttribs[i];
if (!attrib.mEnabled || isActiveAttrib[i]) {
continue;
}
mWebGL->gl->fDisableVertexAttribArray(i);
mDisabledUnusedAttribs.push_back(i);
}
}
#endif
////
// Check UBO sizes.
const auto& linkInfo = mWebGL->mActiveProgramLinkInfo;
for (const auto& cur : linkInfo->uniformBlocks) {
const auto& dataSize = cur->mDataSize;
const auto& binding = cur->mBinding;
@@ -477,6 +535,10 @@ public:
if (mDidFake) {
mWebGL->UndoFakeVertexAttrib0();
}
for (const auto loc : mDisabledUnusedAttribs) {
mWebGL->gl->fEnableVertexAttribArray(loc);
}
}
};
@@ -607,12 +669,12 @@ WebGLContext::DrawArraysInstanced(GLenum mode, GLint first, GLsizei vertCount,
return;
MakeContextCurrent();
if (vertCount > mMaxVertIdsPerDraw) {
ErrorOutOfMemory(
"Context's max vertCount is %u, but %u requested. [webgl.max-vert-ids-per-draw]", mMaxVertIdsPerDraw, vertCount);
return;
}
if (vertCount > mMaxVertIdsPerDraw) {
ErrorOutOfMemory(
"Context's max vertCount is %u, but %u requested. [webgl.max-vert-ids-per-draw]", mMaxVertIdsPerDraw, vertCount);
return;
}
bool error = false;
ScopedResolveTexturesForDraw scopedResolve(this, funcName, &error);
@@ -855,12 +917,12 @@ WebGLContext::DrawElementsInstanced(GLenum mode, GLsizei vertCount, GLenum type,
return;
MakeContextCurrent();
if (vertCount > mMaxVertIdsPerDraw) {
ErrorOutOfMemory(
"Context's max vertCount is %u, but %u requested. [webgl.max-vert-ids-per-draw]", mMaxVertIdsPerDraw, vertCount);
return;
}
if (vertCount > mMaxVertIdsPerDraw) {
ErrorOutOfMemory(
"Context's max vertCount is %u, but %u requested. [webgl.max-vert-ids-per-draw]", mMaxVertIdsPerDraw, vertCount);
return;
}
bool error = false;
ScopedResolveTexturesForDraw scopedResolve(this, funcName, &error);
+39
View File
@@ -100,6 +100,45 @@ public:
uint32_t mChunksToProcess = 0;
};
/* static */ already_AddRefed<AnalyserNode>
AnalyserNode::Create(AudioContext& aAudioContext,
const AnalyserOptions& aOptions,
ErrorResult& aRv)
{
if (aAudioContext.CheckClosed(aRv)) {
return nullptr;
}
RefPtr<AnalyserNode> analyserNode = new AnalyserNode(&aAudioContext);
analyserNode->Initialize(aOptions, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
analyserNode->SetFftSize(aOptions.mFftSize, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
analyserNode->SetMinDecibels(aOptions.mMinDecibels, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
analyserNode->SetMaxDecibels(aOptions.mMaxDecibels, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
analyserNode->SetSmoothingTimeConstant(aOptions.mSmoothingTimeConstant, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
return analyserNode.forget();
}
AnalyserNode::AnalyserNode(AudioContext* aContext)
: AudioNode(aContext,
1,
+15 -4
View File
@@ -14,16 +14,26 @@ namespace mozilla {
namespace dom {
class AudioContext;
struct AnalyserOptions;
class AnalyserNode final : public AudioNode
{
public:
explicit AnalyserNode(AudioContext* aContext);
static already_AddRefed<AnalyserNode>
Create(AudioContext& aAudioContext, const AnalyserOptions& aOptions,
ErrorResult& aRv);
NS_DECL_ISUPPORTS_INHERITED
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
static already_AddRefed<AnalyserNode>
Constructor(const GlobalObject& aGlobal, AudioContext& aAudioContext,
const AnalyserOptions& aOptions, ErrorResult& aRv)
{
return Create(aAudioContext, aOptions, aRv);
}
void GetFloatFrequencyData(const Float32Array& aArray);
void GetByteFrequencyData(const Uint8Array& aArray);
void GetFloatTimeDomainData(const Float32Array& aArray);
@@ -61,10 +71,9 @@ public:
virtual size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override;
virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override;
protected:
~AnalyserNode() {}
private:
~AnalyserNode() = default;
friend class AnalyserNodeEngine;
void AppendChunk(const AudioChunk& aChunk);
bool AllocateBuffer();
@@ -73,6 +82,8 @@ private:
void GetTimeDomainData(float* aData, size_t aLength);
private:
explicit AnalyserNode(AudioContext* aContext);
FFTBlock mAnalysisBlock;
nsTArray<AudioChunk> mChunks;
double mMinDecibels;
+18
View File
@@ -178,6 +178,24 @@ AudioBuffer::~AudioBuffer()
mozilla::DropJSObjects(this);
}
/* static */ already_AddRefed<AudioBuffer>
AudioBuffer::Constructor(const GlobalObject& aGlobal,
AudioContext& aAudioContext,
const AudioBufferOptions& aOptions,
ErrorResult& aRv)
{
if (!aOptions.mNumberOfChannels) {
aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
return nullptr;
}
float sampleRate = aOptions.mSampleRate.WasPassed()
? aOptions.mSampleRate.Value()
: aAudioContext.SampleRate();
return Create(&aAudioContext, aOptions.mNumberOfChannels, aOptions.mLength,
sampleRate, aRv);
}
void
AudioBuffer::ClearJSChannels()
{
+5 -1
View File
@@ -24,6 +24,7 @@ class ThreadSharedFloatArrayBufferList;
namespace dom {
struct AudioBufferOptions;
class AudioContext;
/**
@@ -56,6 +57,10 @@ public:
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(AudioBuffer)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(AudioBuffer)
static already_AddRefed<AudioBuffer>
Constructor(const GlobalObject& aGlobal, AudioContext& aAudioContext,
const AudioBufferOptions& aOptions, ErrorResult& aRv);
nsPIDOMWindowInner* GetParentObject() const
{
nsCOMPtr<nsPIDOMWindowInner> parentObject = do_QueryReferent(mOwnerWindow);
@@ -134,4 +139,3 @@ protected:
} // namespace mozilla
#endif
+22 -2
View File
@@ -607,10 +607,30 @@ AudioBufferSourceNode::AudioBufferSourceNode(AudioContext* aContext)
mStream->AddMainThreadListener(this);
}
AudioBufferSourceNode::~AudioBufferSourceNode()
/* static */ already_AddRefed<AudioBufferSourceNode>
AudioBufferSourceNode::Create(JSContext* aCx, AudioContext& aAudioContext,
const AudioBufferSourceOptions& aOptions,
ErrorResult& aRv)
{
}
if (aAudioContext.CheckClosed(aRv)) {
return nullptr;
}
RefPtr<AudioBufferSourceNode> audioNode = new AudioBufferSourceNode(&aAudioContext);
if (aOptions.mBuffer.WasPassed()) {
MOZ_ASSERT(aCx);
audioNode->SetBuffer(aCx, aOptions.mBuffer.Value());
}
audioNode->Detune()->SetValue(aOptions.mDetune);
audioNode->SetLoop(aOptions.mLoop);
audioNode->SetLoopEnd(aOptions.mLoopEnd);
audioNode->SetLoopStart(aOptions.mLoopStart);
audioNode->PlaybackRate()->SetValue(aOptions.mPlaybackRate);
return audioNode.forget();
}
void
AudioBufferSourceNode::DestroyMediaStream()
{
+16 -8
View File
@@ -12,13 +12,16 @@
namespace mozilla {
namespace dom {
struct AudioBufferSourceOptions;
class AudioParam;
class AudioBufferSourceNode final : public AudioNode,
public MainThreadMediaStreamListener
class AudioBufferSourceNode final : public AudioNode
, public MainThreadMediaStreamListener
{
public:
explicit AudioBufferSourceNode(AudioContext* aContext);
static already_AddRefed<AudioBufferSourceNode>
Create(JSContext* aCx, AudioContext& aAudioContext,
const AudioBufferSourceOptions& aOptions, ErrorResult& aRv);
void DestroyMediaStream() override;
@@ -33,6 +36,13 @@ public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(AudioBufferSourceNode, AudioNode)
static already_AddRefed<AudioBufferSourceNode>
Constructor(const GlobalObject& aGlobal, AudioContext& aAudioContext,
const AudioBufferSourceOptions& aOptions, ErrorResult& aRv)
{
return Create(aGlobal.Context(), aAudioContext, aOptions, aRv);
}
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
void Start(double aWhen, double aOffset,
@@ -98,10 +108,10 @@ public:
size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override;
size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override;
protected:
virtual ~AudioBufferSourceNode();
private:
explicit AudioBufferSourceNode(AudioContext* aContext);
~AudioBufferSourceNode() = default;
friend class AudioBufferSourceNodeEngine;
// START is sent during Start().
// STOP is sent during Stop().
@@ -129,7 +139,6 @@ private:
void SendBufferParameterToStream(JSContext* aCx);
void SendOffsetAndDurationParametersToStream(AudioNodeStream* aStream);
private:
double mLoopStart;
double mLoopEnd;
double mOffset;
@@ -145,4 +154,3 @@ private:
} // namespace mozilla
#endif
+49 -166
View File
@@ -11,10 +11,26 @@
#include "mozilla/OwningNonNull.h"
#include "mozilla/dom/AnalyserNode.h"
#include "mozilla/dom/AnalyserNodeBinding.h"
#include "mozilla/dom/AudioBufferSourceNodeBinding.h"
#include "mozilla/dom/AudioContextBinding.h"
#include "mozilla/dom/BiquadFilterNodeBinding.h"
#include "mozilla/dom/ChannelMergerNodeBinding.h"
#include "mozilla/dom/ChannelSplitterNodeBinding.h"
#include "mozilla/dom/ConvolverNodeBinding.h"
#include "mozilla/dom/DelayNodeBinding.h"
#include "mozilla/dom/DynamicsCompressorNodeBinding.h"
#include "mozilla/dom/GainNodeBinding.h"
#include "mozilla/dom/IIRFilterNodeBinding.h"
#include "mozilla/dom/HTMLMediaElement.h"
#include "mozilla/dom/MediaElementAudioSourceNodeBinding.h"
#include "mozilla/dom/MediaStreamAudioSourceNodeBinding.h"
#include "mozilla/dom/OfflineAudioContextBinding.h"
#include "mozilla/dom/OscillatorNodeBinding.h"
#include "mozilla/dom/PannerNodeBinding.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/StereoPannerNodeBinding.h"
#include "mozilla/dom/WaveShaperNodeBinding.h"
#include "AudioBuffer.h"
#include "AudioBufferSourceNode.h"
@@ -245,13 +261,9 @@ bool AudioContext::CheckClosed(ErrorResult& aRv)
already_AddRefed<AudioBufferSourceNode>
AudioContext::CreateBufferSource(ErrorResult& aRv)
{
if (CheckClosed(aRv)) {
return nullptr;
}
RefPtr<AudioBufferSourceNode> bufferNode =
new AudioBufferSourceNode(this);
return bufferNode.forget();
return AudioBufferSourceNode::Create(nullptr, *this,
AudioBufferSourceOptions(),
aRv);
}
already_AddRefed<ConstantSourceNode>
@@ -303,18 +315,8 @@ bool IsValidBufferSize(uint32_t aBufferSize) {
already_AddRefed<MediaStreamAudioDestinationNode>
AudioContext::CreateMediaStreamDestination(ErrorResult& aRv)
{
if (mIsOffline) {
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return nullptr;
}
if (CheckClosed(aRv)) {
return nullptr;
}
RefPtr<MediaStreamAudioDestinationNode> node =
new MediaStreamAudioDestinationNode(this);
return node.forget();
return MediaStreamAudioDestinationNode::Create(*this, AudioNodeOptions(),
aRv);
}
already_AddRefed<ScriptProcessorNode>
@@ -344,181 +346,93 @@ AudioContext::CreateScriptProcessor(uint32_t aBufferSize,
already_AddRefed<AnalyserNode>
AudioContext::CreateAnalyser(ErrorResult& aRv)
{
if (CheckClosed(aRv)) {
return nullptr;
}
RefPtr<AnalyserNode> analyserNode = new AnalyserNode(this);
return analyserNode.forget();
return AnalyserNode::Create(*this, AnalyserOptions(), aRv);
}
already_AddRefed<StereoPannerNode>
AudioContext::CreateStereoPanner(ErrorResult& aRv)
{
if (CheckClosed(aRv)) {
return nullptr;
}
RefPtr<StereoPannerNode> stereoPannerNode = new StereoPannerNode(this);
return stereoPannerNode.forget();
return StereoPannerNode::Create(*this, StereoPannerOptions(), aRv);
}
already_AddRefed<MediaElementAudioSourceNode>
AudioContext::CreateMediaElementSource(HTMLMediaElement& aMediaElement,
ErrorResult& aRv)
{
if (mIsOffline) {
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return nullptr;
}
MediaElementAudioSourceOptions options;
options.mMediaElement = aMediaElement;
if (CheckClosed(aRv)) {
return nullptr;
}
RefPtr<DOMMediaStream> stream =
aMediaElement.CaptureAudio(aRv, mDestination->Stream()->Graph());
if (aRv.Failed()) {
return nullptr;
}
return MediaElementAudioSourceNode::Create(this, stream, aRv);
return MediaElementAudioSourceNode::Create(*this, options, aRv);
}
already_AddRefed<MediaStreamAudioSourceNode>
AudioContext::CreateMediaStreamSource(DOMMediaStream& aMediaStream,
ErrorResult& aRv)
{
if (mIsOffline) {
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return nullptr;
}
MediaStreamAudioSourceOptions options;
options.mMediaStream = aMediaStream;
if (CheckClosed(aRv)) {
return nullptr;
}
return MediaStreamAudioSourceNode::Create(this, &aMediaStream, aRv);
return MediaStreamAudioSourceNode::Create(*this, options, aRv);
}
already_AddRefed<GainNode>
AudioContext::CreateGain(ErrorResult& aRv)
{
if (CheckClosed(aRv)) {
return nullptr;
}
RefPtr<GainNode> gainNode = new GainNode(this);
return gainNode.forget();
return GainNode::Create(*this, GainOptions(), aRv);
}
already_AddRefed<WaveShaperNode>
AudioContext::CreateWaveShaper(ErrorResult& aRv)
{
if (CheckClosed(aRv)) {
return nullptr;
}
RefPtr<WaveShaperNode> waveShaperNode = new WaveShaperNode(this);
return waveShaperNode.forget();
return WaveShaperNode::Create(*this, WaveShaperOptions(), aRv);
}
already_AddRefed<DelayNode>
AudioContext::CreateDelay(double aMaxDelayTime, ErrorResult& aRv)
{
if (CheckClosed(aRv)) {
return nullptr;
}
if (aMaxDelayTime > 0. && aMaxDelayTime < 180.) {
RefPtr<DelayNode> delayNode = new DelayNode(this, aMaxDelayTime);
return delayNode.forget();
}
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return nullptr;
DelayOptions options;
options.mMaxDelayTime = aMaxDelayTime;
return DelayNode::Create(*this, options, aRv);
}
already_AddRefed<PannerNode>
AudioContext::CreatePanner(ErrorResult& aRv)
{
if (CheckClosed(aRv)) {
return nullptr;
}
RefPtr<PannerNode> pannerNode = new PannerNode(this);
mPannerNodes.PutEntry(pannerNode);
return pannerNode.forget();
return PannerNode::Create(*this, PannerOptions(), aRv);
}
already_AddRefed<ConvolverNode>
AudioContext::CreateConvolver(ErrorResult& aRv)
{
if (CheckClosed(aRv)) {
return nullptr;
}
RefPtr<ConvolverNode> convolverNode = new ConvolverNode(this);
return convolverNode.forget();
return ConvolverNode::Create(nullptr, *this, ConvolverOptions(), aRv);
}
already_AddRefed<ChannelSplitterNode>
AudioContext::CreateChannelSplitter(uint32_t aNumberOfOutputs, ErrorResult& aRv)
{
if (aNumberOfOutputs == 0 ||
aNumberOfOutputs > WebAudioUtils::MaxChannelCount) {
aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
return nullptr;
}
if (CheckClosed(aRv)) {
return nullptr;
}
RefPtr<ChannelSplitterNode> splitterNode =
new ChannelSplitterNode(this, aNumberOfOutputs);
return splitterNode.forget();
ChannelSplitterOptions options;
options.mNumberOfOutputs = aNumberOfOutputs;
return ChannelSplitterNode::Create(*this, options, aRv);
}
already_AddRefed<ChannelMergerNode>
AudioContext::CreateChannelMerger(uint32_t aNumberOfInputs, ErrorResult& aRv)
{
if (aNumberOfInputs == 0 ||
aNumberOfInputs > WebAudioUtils::MaxChannelCount) {
aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
return nullptr;
}
if (CheckClosed(aRv)) {
return nullptr;
}
RefPtr<ChannelMergerNode> mergerNode =
new ChannelMergerNode(this, aNumberOfInputs);
return mergerNode.forget();
ChannelMergerOptions options;
options.mNumberOfInputs = aNumberOfInputs;
return ChannelMergerNode::Create(*this, options, aRv);
}
already_AddRefed<DynamicsCompressorNode>
AudioContext::CreateDynamicsCompressor(ErrorResult& aRv)
{
if (CheckClosed(aRv)) {
return nullptr;
}
RefPtr<DynamicsCompressorNode> compressorNode =
new DynamicsCompressorNode(this);
return compressorNode.forget();
return DynamicsCompressorNode::Create(*this, DynamicsCompressorOptions(), aRv);
}
already_AddRefed<BiquadFilterNode>
AudioContext::CreateBiquadFilter(ErrorResult& aRv)
{
if (CheckClosed(aRv)) {
return nullptr;
}
RefPtr<BiquadFilterNode> filterNode =
new BiquadFilterNode(this);
return filterNode.forget();
return BiquadFilterNode::Create(*this, BiquadFilterOptions(), aRv);
}
already_AddRefed<IIRFilterNode>
@@ -526,47 +440,16 @@ AudioContext::CreateIIRFilter(const mozilla::dom::binding_detail::AutoSequence<d
const mozilla::dom::binding_detail::AutoSequence<double>& aFeedback,
mozilla::ErrorResult& aRv)
{
if (CheckClosed(aRv)) {
return nullptr;
}
if (aFeedforward.Length() == 0 || aFeedforward.Length() > 20) {
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return nullptr;
}
if (aFeedback.Length() == 0 || aFeedback.Length() > 20) {
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return nullptr;
}
bool feedforwardAllZeros = true;
for (size_t i = 0; i < aFeedforward.Length(); ++i) {
if (aFeedforward.Elements()[i] != 0.0) {
feedforwardAllZeros = false;
}
}
if (feedforwardAllZeros || aFeedback.Elements()[0] == 0.0) {
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return nullptr;
}
RefPtr<IIRFilterNode> filterNode =
new IIRFilterNode(this, aFeedforward, aFeedback);
return filterNode.forget();
IIRFilterOptions options;
options.mFeedforward = aFeedforward;
options.mFeedback = aFeedback;
return IIRFilterNode::Create(*this, options, aRv);
}
already_AddRefed<OscillatorNode>
AudioContext::CreateOscillator(ErrorResult& aRv)
{
if (CheckClosed(aRv)) {
return nullptr;
}
RefPtr<OscillatorNode> oscillatorNode =
new OscillatorNode(this);
return oscillatorNode.forget();
return OscillatorNode::Create(*this, OscillatorOptions(), aRv);
}
already_AddRefed<PeriodicWave>
+2 -2
View File
@@ -316,6 +316,8 @@ public:
IMPL_EVENT_HANDLER(mozinterruptbegin)
IMPL_EVENT_HANDLER(mozinterruptend)
bool CheckClosed(ErrorResult& aRv);
private:
void DisconnectFromWindow();
void RemoveFromDecodeQueue(WebAudioDecodeJob* aDecodeJob);
@@ -326,8 +328,6 @@ private:
friend struct ::mozilla::WebAudioDecodeJob;
bool CheckClosed(ErrorResult& aRv);
nsTArray<MediaStream*> GetAllStreams() const;
private:
+22
View File
@@ -71,6 +71,28 @@ AudioNode::~AudioNode()
}
}
void
AudioNode::Initialize(const AudioNodeOptions& aOptions, ErrorResult& aRv)
{
if (aOptions.mChannelCount.WasPassed()) {
SetChannelCount(aOptions.mChannelCount.Value(), aRv);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
}
if (aOptions.mChannelCountMode.WasPassed()) {
SetChannelCountModeValue(aOptions.mChannelCountMode.Value(), aRv);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
}
if (aOptions.mChannelInterpretation.WasPassed()) {
SetChannelInterpretationValue(aOptions.mChannelInterpretation.Value());
}
}
size_t
AudioNode::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
{
+3
View File
@@ -250,6 +250,9 @@ private:
bool DisconnectFromOutputIfConnected(uint32_t aOutputIndex, uint32_t aInputIndex);
protected:
// Helper for the Constructors for nodes.
void Initialize(const AudioNodeOptions& aOptions, ErrorResult& aRv);
// Helpers for sending different value types to streams
void SendDoubleParameterToStream(uint32_t aIndex, double aValue);
void SendInt32ParameterToStream(uint32_t aIndex, int32_t aValue);
+22 -1
View File
@@ -262,8 +262,29 @@ BiquadFilterNode::BiquadFilterNode(AudioContext* aContext)
aContext->Graph());
}
BiquadFilterNode::~BiquadFilterNode()
/* static */ already_AddRefed<BiquadFilterNode>
BiquadFilterNode::Create(AudioContext& aAudioContext,
const BiquadFilterOptions& aOptions,
ErrorResult& aRv)
{
if (aAudioContext.CheckClosed(aRv)) {
return nullptr;
}
RefPtr<BiquadFilterNode> audioNode = new BiquadFilterNode(&aAudioContext);
audioNode->Initialize(aOptions, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
audioNode->SetType(aOptions.mType);
audioNode->Q()->SetValue(aOptions.mQ);
audioNode->Detune()->SetValue(aOptions.mDetune);
audioNode->Frequency()->SetValue(aOptions.mFrequency);
audioNode->Gain()->SetValue(aOptions.mGain);
return audioNode.forget();
}
size_t
+14 -5
View File
@@ -14,15 +14,25 @@ namespace mozilla {
namespace dom {
class AudioContext;
struct BiquadFilterOptions;
class BiquadFilterNode final : public AudioNode
{
public:
explicit BiquadFilterNode(AudioContext* aContext);
static already_AddRefed<BiquadFilterNode>
Create(AudioContext& aAudioContext, const BiquadFilterOptions& aOptions,
ErrorResult& aRv);
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(BiquadFilterNode, AudioNode)
static already_AddRefed<BiquadFilterNode>
Constructor(const GlobalObject& aGlobal, AudioContext& aAudioContext,
const BiquadFilterOptions& aOptions, ErrorResult& aRv)
{
return Create(aAudioContext, aOptions, aRv);
}
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
BiquadFilterType Type() const
@@ -63,10 +73,10 @@ public:
size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override;
size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override;
protected:
virtual ~BiquadFilterNode();
private:
explicit BiquadFilterNode(AudioContext* aContext);
~BiquadFilterNode() = default;
BiquadFilterType mType;
RefPtr<AudioParam> mFrequency;
RefPtr<AudioParam> mDetune;
@@ -78,4 +88,3 @@ private:
} // namespace mozilla
#endif
+23 -2
View File
@@ -74,8 +74,30 @@ ChannelMergerNode::ChannelMergerNode(AudioContext* aContext,
aContext->Graph());
}
ChannelMergerNode::~ChannelMergerNode()
/* static */ already_AddRefed<ChannelMergerNode>
ChannelMergerNode::Create(AudioContext& aAudioContext,
const ChannelMergerOptions& aOptions,
ErrorResult& aRv)
{
if (aAudioContext.CheckClosed(aRv)) {
return nullptr;
}
if (aOptions.mNumberOfInputs == 0 ||
aOptions.mNumberOfInputs > WebAudioUtils::MaxChannelCount) {
aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
return nullptr;
}
RefPtr<ChannelMergerNode> audioNode =
new ChannelMergerNode(&aAudioContext, aOptions.mNumberOfInputs);
audioNode->Initialize(aOptions, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
return audioNode.forget();
}
JSObject*
@@ -86,4 +108,3 @@ ChannelMergerNode::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
} // namespace dom
} // namespace mozilla
+15 -6
View File
@@ -12,15 +12,24 @@ namespace mozilla {
namespace dom {
class AudioContext;
struct ChannelMergerOptions;
class ChannelMergerNode final : public AudioNode
{
public:
ChannelMergerNode(AudioContext* aContext,
uint16_t aInputCount);
static already_AddRefed<ChannelMergerNode>
Create(AudioContext& aAudioContext, const ChannelMergerOptions& aOptions,
ErrorResult& aRv);
NS_DECL_ISUPPORTS_INHERITED
static already_AddRefed<ChannelMergerNode>
Constructor(const GlobalObject& aGlobal, AudioContext& aAudioContext,
const ChannelMergerOptions& aOptions, ErrorResult& aRv)
{
return Create(aAudioContext, aOptions, aRv);
}
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
uint16_t NumberOfInputs() const override { return mInputCount; }
@@ -35,10 +44,11 @@ public:
return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
}
protected:
virtual ~ChannelMergerNode();
private:
ChannelMergerNode(AudioContext* aContext,
uint16_t aInputCount);
~ChannelMergerNode() = default;
const uint16_t mInputCount;
};
@@ -46,4 +56,3 @@ private:
} // namespace mozilla
#endif
+23 -2
View File
@@ -65,8 +65,30 @@ ChannelSplitterNode::ChannelSplitterNode(AudioContext* aContext,
aContext->Graph());
}
ChannelSplitterNode::~ChannelSplitterNode()
/* static */ already_AddRefed<ChannelSplitterNode>
ChannelSplitterNode::Create(AudioContext& aAudioContext,
const ChannelSplitterOptions& aOptions,
ErrorResult& aRv)
{
if (aAudioContext.CheckClosed(aRv)) {
return nullptr;
}
if (aOptions.mNumberOfOutputs == 0 ||
aOptions.mNumberOfOutputs > WebAudioUtils::MaxChannelCount) {
aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
return nullptr;
}
RefPtr<ChannelSplitterNode> audioNode =
new ChannelSplitterNode(&aAudioContext, aOptions.mNumberOfOutputs);
audioNode->Initialize(aOptions, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
return audioNode.forget();
}
JSObject*
@@ -77,4 +99,3 @@ ChannelSplitterNode::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProt
} // namespace dom
} // namespace mozilla
+15 -6
View File
@@ -12,15 +12,24 @@ namespace mozilla {
namespace dom {
class AudioContext;
struct ChannelSplitterOptions;
class ChannelSplitterNode final : public AudioNode
{
public:
ChannelSplitterNode(AudioContext* aContext,
uint16_t aOutputCount);
static already_AddRefed<ChannelSplitterNode>
Create(AudioContext& aAudioContext, const ChannelSplitterOptions& aOptions,
ErrorResult& aRv);
NS_DECL_ISUPPORTS_INHERITED
static already_AddRefed<ChannelSplitterNode>
Constructor(const GlobalObject& aGlobal, AudioContext& aAudioContext,
const ChannelSplitterOptions& aOptions, ErrorResult& aRv)
{
return Create(aAudioContext, aOptions, aRv);
}
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
uint16_t NumberOfOutputs() const override { return mOutputCount; }
@@ -35,10 +44,11 @@ public:
return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
}
protected:
virtual ~ChannelSplitterNode();
private:
ChannelSplitterNode(AudioContext* aContext,
uint16_t aOutputCount);
~ChannelSplitterNode() = default;
const uint16_t mOutputCount;
};
@@ -46,4 +56,3 @@ private:
} // namespace mozilla
#endif
+27 -2
View File
@@ -203,8 +203,34 @@ ConvolverNode::ConvolverNode(AudioContext* aContext)
aContext->Graph());
}
ConvolverNode::~ConvolverNode()
/* static */ already_AddRefed<ConvolverNode>
ConvolverNode::Create(JSContext* aCx, AudioContext& aAudioContext,
const ConvolverOptions& aOptions,
ErrorResult& aRv)
{
if (aAudioContext.CheckClosed(aRv)) {
return nullptr;
}
RefPtr<ConvolverNode> audioNode = new ConvolverNode(&aAudioContext);
audioNode->Initialize(aOptions, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
// This must be done before setting the buffer.
audioNode->SetNormalize(!aOptions.mDisableNormalization);
if (aOptions.mBuffer.WasPassed()) {
MOZ_ASSERT(aCx);
audioNode->SetBuffer(aCx, aOptions.mBuffer.Value(), aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
}
return audioNode.forget();
}
size_t
@@ -291,4 +317,3 @@ ConvolverNode::SetNormalize(bool aNormalize)
} // namespace dom
} // namespace mozilla
+17 -6
View File
@@ -12,14 +12,26 @@
namespace mozilla {
namespace dom {
class AudioContext;
struct ConvolverOptions;
class ConvolverNode final : public AudioNode
{
public:
explicit ConvolverNode(AudioContext* aContext);
static already_AddRefed<ConvolverNode>
Create(JSContext* aCx, AudioContext& aAudioContext,
const ConvolverOptions& aOptions, ErrorResult& aRv);
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ConvolverNode, AudioNode);
static already_AddRefed<ConvolverNode>
Constructor(const GlobalObject& aGlobal, AudioContext& aAudioContext,
const ConvolverOptions& aOptions, ErrorResult& aRv)
{
return Create(aGlobal.Context(), aAudioContext, aOptions, aRv);
}
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
AudioBuffer* GetBuffer(JSContext* aCx) const
@@ -27,7 +39,7 @@ public:
return mBuffer;
}
void SetBuffer(JSContext* aCx, AudioBuffer* aBufferi, ErrorResult& aRv);
void SetBuffer(JSContext* aCx, AudioBuffer* aBuffer, ErrorResult& aRv);
bool Normalize() const
{
@@ -61,10 +73,10 @@ public:
size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override;
size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override;
protected:
virtual ~ConvolverNode();
private:
explicit ConvolverNode(AudioContext* aContext);
~ConvolverNode() = default;
RefPtr<AudioBuffer> mBuffer;
bool mNormalize;
};
@@ -74,4 +86,3 @@ private:
} //end namespace mozilla
#endif
+23 -1
View File
@@ -205,8 +205,30 @@ DelayNode::DelayNode(AudioContext* aContext, double aMaxDelay)
aContext->Graph());
}
DelayNode::~DelayNode()
/* static */ already_AddRefed<DelayNode>
DelayNode::Create(AudioContext& aAudioContext,
const DelayOptions& aOptions,
ErrorResult& aRv)
{
if (aAudioContext.CheckClosed(aRv)) {
return nullptr;
}
if (aOptions.mMaxDelayTime <= 0. || aOptions.mMaxDelayTime >= 180.) {
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return nullptr;
}
RefPtr<DelayNode> audioNode = new DelayNode(&aAudioContext,
aOptions.mMaxDelayTime);
audioNode->Initialize(aOptions, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
audioNode->DelayTime()->SetValue(aOptions.mDelayTime);
return audioNode.forget();
}
size_t
+14 -6
View File
@@ -13,15 +13,25 @@ namespace mozilla {
namespace dom {
class AudioContext;
struct DelayOptions;
class DelayNode final : public AudioNode
{
public:
DelayNode(AudioContext* aContext, double aMaxDelay);
static already_AddRefed<DelayNode>
Create(AudioContext& aAudioContext, const DelayOptions& aOptions,
ErrorResult& aRv);
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(DelayNode, AudioNode)
static already_AddRefed<DelayNode>
Constructor(const GlobalObject& aGlobal, AudioContext& aAudioContext,
const DelayOptions& aOptions, ErrorResult& aRv)
{
return Create(aAudioContext, aOptions, aRv);
}
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
AudioParam* DelayTime() const
@@ -37,13 +47,12 @@ public:
size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override;
size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override;
protected:
virtual ~DelayNode();
private:
DelayNode(AudioContext* aContext, double aMaxDelay);
~DelayNode() = default;
friend class DelayNodeEngine;
private:
RefPtr<AudioParam> mDelay;
};
@@ -51,4 +60,3 @@ private:
} // namespace mozilla
#endif
+23 -1
View File
@@ -204,8 +204,30 @@ DynamicsCompressorNode::DynamicsCompressorNode(AudioContext* aContext)
aContext->Graph());
}
DynamicsCompressorNode::~DynamicsCompressorNode()
/* static */ already_AddRefed<DynamicsCompressorNode>
DynamicsCompressorNode::Create(AudioContext& aAudioContext,
const DynamicsCompressorOptions& aOptions,
ErrorResult& aRv)
{
if (aAudioContext.CheckClosed(aRv)) {
return nullptr;
}
RefPtr<DynamicsCompressorNode> audioNode =
new DynamicsCompressorNode(&aAudioContext);
audioNode->Initialize(aOptions, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
audioNode->Attack()->SetValue(aOptions.mAttack);
audioNode->Knee()->SetValue(aOptions.mKnee);
audioNode->Ratio()->SetValue(aOptions.mRatio);
audioNode->GetRelease()->SetValue(aOptions.mRelease);
audioNode->Threshold()->SetValue(aOptions.mThreshold);
return audioNode.forget();
}
size_t
+14 -5
View File
@@ -13,15 +13,25 @@ namespace mozilla {
namespace dom {
class AudioContext;
struct DynamicsCompressorOptions;
class DynamicsCompressorNode final : public AudioNode
{
public:
explicit DynamicsCompressorNode(AudioContext* aContext);
static already_AddRefed<DynamicsCompressorNode>
Create(AudioContext& aAudioContext, const DynamicsCompressorOptions& aOptions,
ErrorResult& aRv);
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(DynamicsCompressorNode, AudioNode)
static already_AddRefed<DynamicsCompressorNode>
Constructor(const GlobalObject& aGlobal, AudioContext& aAudioContext,
const DynamicsCompressorOptions& aOptions, ErrorResult& aRv)
{
return Create(aAudioContext, aOptions, aRv);
}
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
AudioParam* Threshold() const
@@ -69,10 +79,10 @@ public:
mReduction = aReduction;
}
protected:
virtual ~DynamicsCompressorNode();
private:
explicit DynamicsCompressorNode(AudioContext* aContext);
~DynamicsCompressorNode() = default;
RefPtr<AudioParam> mThreshold;
RefPtr<AudioParam> mKnee;
RefPtr<AudioParam> mRatio;
@@ -85,4 +95,3 @@ private:
} // namespace mozilla
#endif
+17 -1
View File
@@ -128,8 +128,24 @@ GainNode::GainNode(AudioContext* aContext)
aContext->Graph());
}
GainNode::~GainNode()
/* static */ already_AddRefed<GainNode>
GainNode::Create(AudioContext& aAudioContext,
const GainOptions& aOptions,
ErrorResult& aRv)
{
if (aAudioContext.CheckClosed(aRv)) {
return nullptr;
}
RefPtr<GainNode> audioNode = new GainNode(&aAudioContext);
audioNode->Initialize(aOptions, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
audioNode->Gain()->SetValue(aOptions.mGain);
return audioNode.forget();
}
size_t
+14 -5
View File
@@ -13,15 +13,25 @@ namespace mozilla {
namespace dom {
class AudioContext;
struct GainOptions;
class GainNode final : public AudioNode
{
public:
explicit GainNode(AudioContext* aContext);
static already_AddRefed<GainNode>
Create(AudioContext& aAudioContext, const GainOptions& aOptions,
ErrorResult& aRv);
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(GainNode, AudioNode)
static already_AddRefed<GainNode>
Constructor(const GlobalObject& aGlobal, AudioContext& aAudioContext,
const GainOptions& aOptions, ErrorResult& aRv)
{
return Create(aAudioContext, aOptions, aRv);
}
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
AudioParam* Gain() const
@@ -37,10 +47,10 @@ public:
size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override;
size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override;
protected:
virtual ~GainNode();
private:
explicit GainNode(AudioContext* aContext);
~GainNode() = default;
RefPtr<AudioParam> mGain;
};
@@ -48,4 +58,3 @@ private:
} // namespace mozilla
#endif
+41 -3
View File
@@ -138,8 +138,8 @@ private:
};
IIRFilterNode::IIRFilterNode(AudioContext* aContext,
const mozilla::dom::binding_detail::AutoSequence<double>& aFeedforward,
const mozilla::dom::binding_detail::AutoSequence<double>& aFeedback)
const Sequence<double>& aFeedforward,
const Sequence<double>& aFeedback)
: AudioNode(aContext,
2,
ChannelCountMode::Max,
@@ -173,8 +173,46 @@ IIRFilterNode::IIRFilterNode(AudioContext* aContext,
aContext->Graph());
}
IIRFilterNode::~IIRFilterNode()
/* static */ already_AddRefed<IIRFilterNode>
IIRFilterNode::Create(AudioContext& aAudioContext,
const IIRFilterOptions& aOptions,
ErrorResult& aRv)
{
if (aAudioContext.CheckClosed(aRv)) {
return nullptr;
}
if (aOptions.mFeedforward.Length() == 0 || aOptions.mFeedforward.Length() > 20) {
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return nullptr;
}
if (aOptions.mFeedback.Length() == 0 || aOptions.mFeedback.Length() > 20) {
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return nullptr;
}
bool feedforwardAllZeros = true;
for (size_t i = 0; i < aOptions.mFeedforward.Length(); ++i) {
if (aOptions.mFeedforward.Elements()[i] != 0.0) {
feedforwardAllZeros = false;
}
}
if (feedforwardAllZeros || aOptions.mFeedback.Elements()[0] == 0.0) {
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return nullptr;
}
RefPtr<IIRFilterNode> audioNode =
new IIRFilterNode(&aAudioContext, aOptions.mFeedforward, aOptions.mFeedback);
audioNode->Initialize(aOptions, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
return audioNode.forget();
}
size_t
+18 -10
View File
@@ -14,18 +14,25 @@ namespace mozilla {
namespace dom {
class AudioContext;
struct IIRFilterOptions;
class IIRFilterNode final : public AudioNode
{
public:
explicit IIRFilterNode(AudioContext* aContext,
const mozilla::dom::binding_detail::AutoSequence<double>& aFeedforward,
const mozilla::dom::binding_detail::AutoSequence<double>& aFeedback);
static already_AddRefed<IIRFilterNode>
Create(AudioContext& aAudioContext, const IIRFilterOptions& aOptions,
ErrorResult& aRv);
NS_DECL_ISUPPORTS_INHERITED
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
static already_AddRefed<IIRFilterNode>
Constructor(const GlobalObject& aGlobal, AudioContext& aAudioContext,
const IIRFilterOptions& aOptions, ErrorResult& aRv)
{
return Create(aAudioContext, aOptions, aRv);
}
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
void GetFrequencyResponse(const Float32Array& aFrequencyHz,
const Float32Array& aMagResponse,
@@ -39,16 +46,17 @@ public:
size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override;
size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override;
protected:
virtual ~IIRFilterNode();
private:
nsTArray<double> mFeedback;
nsTArray<double> mFeedforward;
IIRFilterNode(AudioContext* aContext,
const Sequence<double>& aFeedforward,
const Sequence<double>& aFeedback);
~IIRFilterNode() = default;
nsTArray<double> mFeedback;
nsTArray<double> mFeedforward;
};
} // namespace dom
} // namespace mozilla
#endif
@@ -15,13 +15,29 @@ MediaElementAudioSourceNode::MediaElementAudioSourceNode(AudioContext* aContext)
}
/* static */ already_AddRefed<MediaElementAudioSourceNode>
MediaElementAudioSourceNode::Create(AudioContext* aContext,
DOMMediaStream* aStream, ErrorResult& aRv)
MediaElementAudioSourceNode::Create(AudioContext& aAudioContext,
const MediaElementAudioSourceOptions& aOptions,
ErrorResult& aRv)
{
RefPtr<MediaElementAudioSourceNode> node =
new MediaElementAudioSourceNode(aContext);
if (aAudioContext.IsOffline()) {
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return nullptr;
}
node->Init(aStream, aRv);
if (aAudioContext.CheckClosed(aRv)) {
return nullptr;
}
RefPtr<MediaElementAudioSourceNode> node =
new MediaElementAudioSourceNode(&aAudioContext);
RefPtr<DOMMediaStream> stream =
aOptions.mMediaElement->CaptureAudio(aRv, aAudioContext.Destination()->Stream()->Graph());
if (aRv.Failed()) {
return nullptr;
}
node->Init(stream, aRv);
if (aRv.Failed()) {
return nullptr;
}
@@ -11,11 +11,23 @@
namespace mozilla {
namespace dom {
class AudioContext;
struct MediaElementAudioSourceOptions;
class MediaElementAudioSourceNode final : public MediaStreamAudioSourceNode
{
public:
static already_AddRefed<MediaElementAudioSourceNode>
Create(AudioContext* aContext, DOMMediaStream* aStream, ErrorResult& aRv);
Create(AudioContext& aAudioContext,
const MediaElementAudioSourceOptions& aOptions,
ErrorResult& aRv);
static already_AddRefed<MediaElementAudioSourceNode>
Constructor(const GlobalObject& aGlobal, AudioContext& aAudioContext,
const MediaElementAudioSourceOptions& aOptions, ErrorResult& aRv)
{
return Create(aAudioContext, aOptions, aRv);
}
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
@@ -15,7 +15,7 @@
namespace mozilla {
namespace dom {
class AudioDestinationTrackSource :
class AudioDestinationTrackSource final :
public MediaStreamTrackSource
{
public:
@@ -49,7 +49,7 @@ public:
}
private:
virtual ~AudioDestinationTrackSource() {}
~AudioDestinationTrackSource() = default;
RefPtr<MediaStreamAudioDestinationNode> mNode;
};
@@ -101,8 +101,29 @@ MediaStreamAudioDestinationNode::MediaStreamAudioDestinationNode(AudioContext* a
mPort = outputStream->AllocateInputPort(mStream, AudioNodeStream::AUDIO_TRACK);
}
MediaStreamAudioDestinationNode::~MediaStreamAudioDestinationNode()
/* static */ already_AddRefed<MediaStreamAudioDestinationNode>
MediaStreamAudioDestinationNode::Create(AudioContext& aAudioContext,
const AudioNodeOptions& aOptions,
ErrorResult& aRv)
{
if (aAudioContext.IsOffline()) {
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return nullptr;
}
if (aAudioContext.CheckClosed(aRv)) {
return nullptr;
}
RefPtr<MediaStreamAudioDestinationNode> audioNode =
new MediaStreamAudioDestinationNode(&aAudioContext);
audioNode->Initialize(aOptions, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
return audioNode.forget();
}
size_t
@@ -11,14 +11,26 @@
namespace mozilla {
namespace dom {
class AudioContext;
struct AudioNodeOptions;
class MediaStreamAudioDestinationNode final : public AudioNode
{
public:
explicit MediaStreamAudioDestinationNode(AudioContext* aContext);
static already_AddRefed<MediaStreamAudioDestinationNode>
Create(AudioContext& aAudioContext, const AudioNodeOptions& aOptions,
ErrorResult& aRv);
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(MediaStreamAudioDestinationNode, AudioNode)
static already_AddRefed<MediaStreamAudioDestinationNode>
Constructor(const GlobalObject& aGlobal, AudioContext& aAudioContext,
const AudioNodeOptions& aOptions, ErrorResult& aRv)
{
return Create(aAudioContext, aOptions, aRv);
}
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
uint16_t NumberOfOutputs() const final override
@@ -41,10 +53,10 @@ public:
size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override;
size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override;
protected:
virtual ~MediaStreamAudioDestinationNode();
private:
explicit MediaStreamAudioDestinationNode(AudioContext* aContext);
~MediaStreamAudioDestinationNode() = default;
RefPtr<DOMMediaStream> mDOMStream;
RefPtr<MediaInputPort> mPort;
};
@@ -44,13 +44,23 @@ MediaStreamAudioSourceNode::MediaStreamAudioSourceNode(AudioContext* aContext)
}
/* static */ already_AddRefed<MediaStreamAudioSourceNode>
MediaStreamAudioSourceNode::Create(AudioContext* aContext,
DOMMediaStream* aStream, ErrorResult& aRv)
MediaStreamAudioSourceNode::Create(AudioContext& aAudioContext,
const MediaStreamAudioSourceOptions& aOptions,
ErrorResult& aRv)
{
RefPtr<MediaStreamAudioSourceNode> node =
new MediaStreamAudioSourceNode(aContext);
if (aAudioContext.IsOffline()) {
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return nullptr;
}
node->Init(aStream, aRv);
if (aAudioContext.CheckClosed(aRv)) {
return nullptr;
}
RefPtr<MediaStreamAudioSourceNode> node =
new MediaStreamAudioSourceNode(&aAudioContext);
node->Init(aOptions.mMediaStream, aRv);
if (aRv.Failed()) {
return nullptr;
}
@@ -14,6 +14,9 @@ namespace mozilla {
namespace dom {
class AudioContext;
struct MediaStreamAudioSourceOptions;
class MediaStreamAudioSourceNodeEngine final : public AudioNodeEngine
{
public:
@@ -45,11 +48,19 @@ class MediaStreamAudioSourceNode : public AudioNode,
{
public:
static already_AddRefed<MediaStreamAudioSourceNode>
Create(AudioContext* aContext, DOMMediaStream* aStream, ErrorResult& aRv);
Create(AudioContext& aContext, const MediaStreamAudioSourceOptions& aOptions,
ErrorResult& aRv);
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(MediaStreamAudioSourceNode, AudioNode)
static already_AddRefed<MediaStreamAudioSourceNode>
Constructor(const GlobalObject& aGlobal, AudioContext& aAudioContext,
const MediaStreamAudioSourceOptions& aOptions, ErrorResult& aRv)
{
return Create(aAudioContext, aOptions, aRv);
}
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
void DestroyMediaStream() override;
+28 -1
View File
@@ -425,8 +425,35 @@ OscillatorNode::OscillatorNode(AudioContext* aContext)
mStream->AddMainThreadListener(this);
}
OscillatorNode::~OscillatorNode()
/* static */ already_AddRefed<OscillatorNode>
OscillatorNode::Create(AudioContext& aAudioContext,
const OscillatorOptions& aOptions,
ErrorResult& aRv)
{
if (aAudioContext.CheckClosed(aRv)) {
return nullptr;
}
RefPtr<OscillatorNode> audioNode = new OscillatorNode(&aAudioContext);
audioNode->Initialize(aOptions, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
audioNode->SetType(aOptions.mType, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
audioNode->Frequency()->SetValue(aOptions.mFrequency);
audioNode->Detune()->SetValue(aOptions.mDetune);
if (aOptions.mPeriodicWave.WasPassed()) {
audioNode->SetPeriodicWave(aOptions.mPeriodicWave.Value());
}
return audioNode.forget();
}
size_t
+14 -6
View File
@@ -15,16 +15,26 @@ namespace mozilla {
namespace dom {
class AudioContext;
struct OscillatorOptions;
class OscillatorNode final : public AudioNode,
public MainThreadMediaStreamListener
{
public:
explicit OscillatorNode(AudioContext* aContext);
static already_AddRefed<OscillatorNode>
Create(AudioContext& aAudioContext, const OscillatorOptions& aOptions,
ErrorResult& aRv);
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(OscillatorNode, AudioNode)
static already_AddRefed<OscillatorNode>
Constructor(const GlobalObject& aGlobal, AudioContext& aAudioContext,
const OscillatorOptions& aOptions, ErrorResult& aRv)
{
return Create(aAudioContext, aOptions, aRv);
}
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
void DestroyMediaStream() override;
@@ -81,14 +91,13 @@ public:
size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override;
size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override;
protected:
virtual ~OscillatorNode();
private:
explicit OscillatorNode(AudioContext* aContext);
~OscillatorNode() = default;
void SendTypeToStream();
void SendPeriodicWaveToStream();
private:
OscillatorType mType;
RefPtr<PeriodicWave> mPeriodicWave;
RefPtr<AudioParam> mFrequency;
@@ -100,4 +109,3 @@ private:
} // namespace mozilla
#endif
+32 -1
View File
@@ -329,6 +329,38 @@ PannerNode::~PannerNode()
}
}
/* static */ already_AddRefed<PannerNode>
PannerNode::Create(AudioContext& aAudioContext,
const PannerOptions& aOptions,
ErrorResult& aRv)
{
if (aAudioContext.CheckClosed(aRv)) {
return nullptr;
}
RefPtr<PannerNode> audioNode = new PannerNode(&aAudioContext);
audioNode->Initialize(aOptions, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
audioNode->SetPanningModel(aOptions.mPanningModel);
audioNode->SetDistanceModel(aOptions.mDistanceModel);
audioNode->SetPosition(aOptions.mPositionX, aOptions.mPositionY,
aOptions.mPositionZ);
audioNode->SetOrientation(aOptions.mOrientationX, aOptions.mOrientationY,
aOptions.mOrientationZ);
audioNode->SetRefDistance(aOptions.mRefDistance);
audioNode->SetMaxDistance(aOptions.mMaxDistance);
audioNode->SetRolloffFactor(aOptions.mRolloffFactor);
audioNode->SetConeInnerAngle(aOptions.mConeInnerAngle);
audioNode->SetConeOuterAngle(aOptions.mConeOuterAngle);
audioNode->SetConeOuterGain(aOptions.mConeOuterGain);
return audioNode.forget();
}
void PannerNode::SetPanningModel(PanningModelType aPanningModel)
{
mPanningModel = aPanningModel;
@@ -784,4 +816,3 @@ PannerNode::SendDopplerToSourcesIfNeeded()
} // namespace dom
} // namespace mozilla
+15 -5
View File
@@ -19,13 +19,24 @@ namespace dom {
class AudioContext;
class AudioBufferSourceNode;
struct PannerOptions;
class PannerNode final : public AudioNode,
public SupportsWeakPtr<PannerNode>
{
public:
static already_AddRefed<PannerNode>
Create(AudioContext& aAudioContext, const PannerOptions& aOptions,
ErrorResult& aRv);
MOZ_DECLARE_WEAKREFERENCE_TYPENAME(PannerNode)
explicit PannerNode(AudioContext* aContext);
static already_AddRefed<PannerNode>
Constructor(const GlobalObject& aGlobal, AudioContext& aAudioContext,
const PannerOptions& aOptions, ErrorResult& aRv)
{
return Create(aAudioContext, aOptions, aRv);
}
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
@@ -229,10 +240,10 @@ public:
size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override;
size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override;
protected:
virtual ~PannerNode();
private:
explicit PannerNode(AudioContext* aContext);
~PannerNode();
friend class AudioListener;
friend class PannerNodeEngine;
enum EngineParameters {
@@ -292,4 +303,3 @@ private:
} // namespace mozilla
#endif
+26 -1
View File
@@ -43,6 +43,32 @@ PeriodicWave::PeriodicWave(AudioContext* aContext,
mCoefficients->SetData(1, nullptr, free, buffer+aLength);
}
/* static */ already_AddRefed<PeriodicWave>
PeriodicWave::Constructor(const GlobalObject& aGlobal,
AudioContext& aAudioContext,
const PeriodicWaveOptions& aOptions,
ErrorResult& aRv)
{
if (!aOptions.mReal.WasPassed() || !aOptions.mImag.WasPassed() ||
aOptions.mReal.Value().Length() != aOptions.mImag.Value().Length() ||
aOptions.mReal.Value().Length() == 0) {
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return nullptr;
}
RefPtr<PeriodicWave> wave =
new PeriodicWave(&aAudioContext, aOptions.mReal.Value().Elements(),
aOptions.mImag.Value().Elements(),
aOptions.mReal.Value().Length(),
aOptions.mDisableNormalization,
aRv);
if (aRv.Failed()) {
return nullptr;
}
return wave.forget();
}
size_t
PeriodicWave::SizeOfExcludingThisIfNotShared(MallocSizeOf aMallocSizeOf) const
{
@@ -70,4 +96,3 @@ PeriodicWave::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
} // namespace dom
} // namespace mozilla
+8 -1
View File
@@ -16,6 +16,9 @@ namespace mozilla {
namespace dom {
class AudioContext;
struct PeriodicWaveOptions;
class PeriodicWave final : public nsWrapperCache
{
public:
@@ -29,6 +32,10 @@ public:
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(PeriodicWave)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(PeriodicWave)
static already_AddRefed<PeriodicWave>
Constructor(const GlobalObject& aGlobal, AudioContext& aAudioContext,
const PeriodicWaveOptions& aOptions, ErrorResult& aRv);
AudioContext* GetParentObject() const
{
return mContext;
@@ -55,7 +62,7 @@ public:
size_t SizeOfIncludingThisIfNotShared(MallocSizeOf aMallocSizeOf) const;
private:
~PeriodicWave() {}
~PeriodicWave() = default;
RefPtr<AudioContext> mContext;
RefPtr<ThreadSharedFloatArrayBufferList> mCoefficients;
+17 -1
View File
@@ -182,8 +182,24 @@ StereoPannerNode::StereoPannerNode(AudioContext* aContext)
aContext->Graph());
}
StereoPannerNode::~StereoPannerNode()
/* static */ already_AddRefed<StereoPannerNode>
StereoPannerNode::Create(AudioContext& aAudioContext,
const StereoPannerOptions& aOptions,
ErrorResult& aRv)
{
if (aAudioContext.CheckClosed(aRv)) {
return nullptr;
}
RefPtr<StereoPannerNode> audioNode = new StereoPannerNode(&aAudioContext);
audioNode->Initialize(aOptions, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
audioNode->Pan()->SetValue(aOptions.mPan);
return audioNode.forget();
}
size_t
+15 -5
View File
@@ -13,12 +13,23 @@ namespace mozilla {
namespace dom {
class AudioContext;
struct StereoPannerOptions;
class StereoPannerNode final : public AudioNode
{
public:
static already_AddRefed<StereoPannerNode>
Create(AudioContext& aAudioContext, const StereoPannerOptions& aOptions,
ErrorResult& aRv);
MOZ_DECLARE_REFCOUNTED_TYPENAME(StereoPannerNode)
explicit StereoPannerNode(AudioContext* aContext);
static already_AddRefed<StereoPannerNode>
Constructor(const GlobalObject& aGlobal, AudioContext& aAudioContext,
const StereoPannerOptions& aOptions, ErrorResult& aRv)
{
return Create(aAudioContext, aOptions, aRv);
}
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
@@ -55,10 +66,10 @@ public:
virtual size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override;
virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override;
protected:
virtual ~StereoPannerNode();
private:
explicit StereoPannerNode(AudioContext* aContext);
~StereoPannerNode() = default;
RefPtr<AudioParam> mPan;
};
@@ -66,4 +77,3 @@ private:
} // namespace mozilla
#endif
+91 -41
View File
@@ -18,7 +18,6 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(WaveShaperNode)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(WaveShaperNode, AudioNode)
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
tmp->ClearCurve();
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(WaveShaperNode, AudioNode)
@@ -26,7 +25,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(WaveShaperNode)
NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mCurve)
NS_IMPL_CYCLE_COLLECTION_TRACE_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WaveShaperNode)
@@ -313,27 +311,39 @@ WaveShaperNode::WaveShaperNode(AudioContext* aContext)
2,
ChannelCountMode::Max,
ChannelInterpretation::Speakers)
, mCurve(nullptr)
, mType(OverSampleType::None)
{
mozilla::HoldJSObjects(this);
WaveShaperNodeEngine* engine = new WaveShaperNodeEngine(this);
mStream = AudioNodeStream::Create(aContext, engine,
AudioNodeStream::NO_STREAM_FLAGS,
aContext->Graph());
}
WaveShaperNode::~WaveShaperNode()
/* static */ already_AddRefed<WaveShaperNode>
WaveShaperNode::Create(AudioContext& aAudioContext,
const WaveShaperOptions& aOptions,
ErrorResult& aRv)
{
ClearCurve();
}
if (aAudioContext.CheckClosed(aRv)) {
return nullptr;
}
void
WaveShaperNode::ClearCurve()
{
mCurve = nullptr;
mozilla::DropJSObjects(this);
RefPtr<WaveShaperNode> audioNode = new WaveShaperNode(&aAudioContext);
audioNode->Initialize(aOptions, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
if (aOptions.mCurve.WasPassed()) {
audioNode->SetCurveInternal(aOptions.mCurve.Value(), aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
}
audioNode->SetOversample(aOptions.mOversample);
return audioNode.forget();
}
JSObject*
@@ -345,45 +355,85 @@ WaveShaperNode::WrapObject(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
void
WaveShaperNode::SetCurve(const Nullable<Float32Array>& aCurve, ErrorResult& aRv)
{
nsTArray<float> curve;
if (!aCurve.IsNull()) {
const Float32Array& floats = aCurve.Value();
// Let's purge the cached value for the curve attribute.
WaveShaperNodeBinding::ClearCachedCurveValue(this);
floats.ComputeLengthAndData();
if (floats.IsShared()) {
// Throw if the object is mapping shared memory (must opt in).
aRv.ThrowTypeError<MSG_TYPEDARRAY_IS_SHARED>(NS_LITERAL_STRING("Argument of WaveShaperNode.setCurve"));
return;
}
uint32_t argLength = floats.Length();
if (argLength < 2) {
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return;
}
if (!curve.SetLength(argLength, fallible)) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return;
}
PodCopy(curve.Elements(), floats.Data(), floats.Length());
mCurve = floats.Obj();
} else {
mCurve = nullptr;
if (aCurve.IsNull()) {
CleanCurveInternal();
return;
}
const Float32Array& floats = aCurve.Value();
floats.ComputeLengthAndData();
if (floats.IsShared()) {
// Throw if the object is mapping shared memory (must opt in).
aRv.ThrowTypeError<MSG_TYPEDARRAY_IS_SHARED>(NS_LITERAL_STRING("Argument of WaveShaperNode.setCurve"));
return;
}
nsTArray<float> curve;
uint32_t argLength = floats.Length();
if (!curve.SetLength(argLength, fallible)) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return;
}
PodCopy(curve.Elements(), floats.Data(), argLength);
SetCurveInternal(curve, aRv);
}
void
WaveShaperNode::SetCurveInternal(const nsTArray<float>& aCurve,
ErrorResult& aRv)
{
if (aCurve.Length() < 2) {
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return;
}
mCurve = aCurve;
SendCurveToStream();
}
void
WaveShaperNode::CleanCurveInternal()
{
mCurve.Clear();
SendCurveToStream();
}
void
WaveShaperNode::SendCurveToStream()
{
AudioNodeStream* ns = mStream;
MOZ_ASSERT(ns, "Why don't we have a stream here?");
ns->SetRawArrayData(curve);
nsTArray<float> copyCurve(mCurve);
ns->SetRawArrayData(copyCurve);
}
void
WaveShaperNode::GetCurve(JSContext* aCx,
JS::MutableHandle<JSObject*> aRetval)
{
// Let's return a null value if the list is empty.
if (mCurve.IsEmpty()) {
aRetval.set(nullptr);
return;
}
MOZ_ASSERT(mCurve.Length() >= 2);
aRetval.set(Float32Array::Create(aCx, this, mCurve.Length(),
mCurve.Elements()));
}
void
WaveShaperNode::SetOversample(OverSampleType aType)
{
mType = aType;
SendInt32ParameterToStream(WaveShaperNodeEngine::TYPE, static_cast<int32_t>(aType));
SendInt32ParameterToStream(WaveShaperNodeEngine::TYPE,
static_cast<int32_t>(aType));
}
} // namespace dom
+21 -11
View File
@@ -14,21 +14,28 @@ namespace mozilla {
namespace dom {
class AudioContext;
struct WaveShaperOptions;
class WaveShaperNode final : public AudioNode
{
public:
explicit WaveShaperNode(AudioContext *aContext);
static already_AddRefed<WaveShaperNode>
Create(AudioContext& aAudioContext, const WaveShaperOptions& aOptions,
ErrorResult& aRv);
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(WaveShaperNode, AudioNode)
static already_AddRefed<WaveShaperNode>
Constructor(const GlobalObject& aGlobal, AudioContext& aAudioContext,
const WaveShaperOptions& aOptions, ErrorResult& aRv)
{
return Create(aAudioContext, aOptions, aRv);
}
JSObject* WrapObject(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
void GetCurve(JSContext* aCx, JS::MutableHandle<JSObject*> aRetval) const
{
aRetval.set(mCurve);
}
void GetCurve(JSContext* aCx, JS::MutableHandle<JSObject*> aRetval);
void SetCurve(const Nullable<Float32Array>& aData, ErrorResult& aRv);
OverSampleType Oversample() const
@@ -54,14 +61,17 @@ public:
return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
}
protected:
virtual ~WaveShaperNode();
private:
void ClearCurve();
explicit WaveShaperNode(AudioContext *aContext);
~WaveShaperNode() = default;
private:
JS::Heap<JSObject*> mCurve;
void SetCurveInternal(const nsTArray<float>& aCurve,
ErrorResult& aRv);
void CleanCurveInternal();
void SendCurveToStream();
nsTArray<float> mCurve;
OverSampleType mType;
};
+79 -4
View File
@@ -10,9 +10,7 @@
<pre id="test">
<script class="testbody" type="text/javascript">
SimpleTest.waitForExplicitFinish();
addLoadEvent(function() {
function testNode() {
var context = new AudioContext();
var buffer = context.createBuffer(1, 2048, context.sampleRate);
for (var i = 0; i < 2048; ++i) {
@@ -84,7 +82,7 @@ addLoadEvent(function() {
analyser.maxDecibels = -101;
}, DOMException.INDEX_SIZE_ERR);
is(analyser.smoothingTimeConstant, 0.8, "Correct default value for smoothingTimeConstant");
ok(Math.abs(analyser.smoothingTimeConstant - 0.8) < 0.001, "Correct default value for smoothingTimeConstant");
expectException(function() {
analyser.smoothingTimeConstant = -0.1;
}, DOMException.INDEX_SIZE_ERR);
@@ -93,6 +91,83 @@ addLoadEvent(function() {
}, DOMException.INDEX_SIZE_ERR);
analyser.smoothingTimeConstant = 0;
analyser.smoothingTimeConstant = 1;
}
function testConstructor() {
var context = new AudioContext();
var analyser = new AnalyserNode(context);
is(analyser.channelCount, 1, "analyser node has 1 input channels by default");
is(analyser.channelCountMode, "max", "Correct channelCountMode for the analyser node");
is(analyser.channelInterpretation, "speakers", "Correct channelCountInterpretation for the analyser node");
is(analyser.fftSize, 2048, "Correct default value for fftSize");
is(analyser.frequencyBinCount, 1024, "Correct default value for frequencyBinCount");
is(analyser.minDecibels, -100, "Correct default value for minDecibels");
is(analyser.maxDecibels, -30, "Correct default value for maxDecibels");
ok(Math.abs(analyser.smoothingTimeConstant - 0.8) < 0.001, "Correct default value for smoothingTimeConstant");
expectException(function() {
analyser = new AnalyserNode(context, { fftSize: 0 });
}, DOMException.INDEX_SIZE_ERR);
expectException(function() {
analyser = new AnalyserNode(context, { fftSize: 1 });
}, DOMException.INDEX_SIZE_ERR);
expectException(function() {
analyser = new AnalyserNode(context, { fftSize: 8 });
}, DOMException.INDEX_SIZE_ERR);
expectException(function() {
analyser = new AnalyserNode(context, { fftSize: 100 }); // non-power of two
}, DOMException.INDEX_SIZE_ERR);
expectException(function() {
analyser = new AnalyserNode(context, { fftSize: 2049 });
}, DOMException.INDEX_SIZE_ERR);
expectException(function() {
analyser = new AnalyserNode(context, { fftSize: 4097 });
}, DOMException.INDEX_SIZE_ERR);
expectException(function() {
analyser = new AnalyserNode(context, { fftSize: 8193 });
}, DOMException.INDEX_SIZE_ERR);
expectException(function() {
analyser = new AnalyserNode(context, { fftSize: 16385 });
}, DOMException.INDEX_SIZE_ERR);
expectException(function() {
analyser = new AnalyserNode(context, { fftSize: 32769 });
}, DOMException.INDEX_SIZE_ERR);
expectException(function() {
analyser = new AnalyserNode(context, { fftSize: 65536 });
}, DOMException.INDEX_SIZE_ERR);
analyser = new AnalyserNode(context, { fftSize: 1024 });
is(analyser.frequencyBinCount, 512, "Correct new value for frequencyBinCount");
expectException(function() {
analyser = new AnalyserNode(context, { minDecibels: -30 });
}, DOMException.INDEX_SIZE_ERR);
expectException(function() {
analyser = new AnalyserNode(context, { minDecibels: -29 });
}, DOMException.INDEX_SIZE_ERR);
expectException(function() {
analyser = new AnalyserNode(context, { maxDecibels: -100 });
}, DOMException.INDEX_SIZE_ERR);
expectException(function() {
analyser = new AnalyserNode(context, { maxDecibels: -101 });
}, DOMException.INDEX_SIZE_ERR);
expectException(function() {
analyser = new AnalyserNode(context, { smoothingTimeConstant: -0.1 });
}, DOMException.INDEX_SIZE_ERR);
expectException(function() {
analyser = new AnalyserNode(context, { smoothingTimeConstant: -1.1 });
}, DOMException.INDEX_SIZE_ERR);
analyser = new AnalyserNode(context, { smoothingTimeConstant: 0 });
analyser = new AnalyserNode(context, { smoothingTimeConstant: 1 });
}
SimpleTest.waitForExplicitFinish();
addLoadEvent(function() {
testNode();
testConstructor();
SimpleTest.finish();
});
@@ -19,12 +19,8 @@ var gTest = {
buffer.getChannelData(0)[i] = Math.sin(440 * 2 * Math.PI * i / context.sampleRate);
}
var source = context.createBufferSource();
source.buffer = buffer;
var source = new AudioBufferSourceNode(context, {buffer: buffer, loop: true, loopStart: buffer.duration * 0.25, loopEnd: buffer.duration * 0.75 });
source.start(0);
source.loop = true;
source.loopStart = buffer.duration * 0.25;
source.loopEnd = buffer.duration * 0.75;
return source;
},
createExpectedBuffers: function(context) {
@@ -24,7 +24,7 @@ var gTest = {
buffers.push(buffer);
}
var merger = context.createChannelMerger();
var merger = new ChannelMergerNode(context);
is(merger.channelCount, 1, "merger node has 1 input channels");
is(merger.channelCountMode, "explicit", "Correct channelCountMode for the merger node");
is(merger.channelInterpretation, "speakers", "Correct channelCountInterpretation for the merger node");
@@ -29,7 +29,7 @@ addLoadEvent(function() {
var source = context.createBufferSource();
var splitter = context.createChannelSplitter();
var splitter = new ChannelSplitterNode(context);
is(splitter.channelCount, 2, "splitter node has 2 input channels by default");
is(splitter.channelCountMode, "max", "Correct channelCountMode for the splitter node");
is(splitter.channelInterpretation, "speakers", "Correct channelCountInterpretation for the splitter node");
@@ -13,7 +13,7 @@
SimpleTest.waitForExplicitFinish();
addLoadEvent(function() {
var context = new AudioContext();
var conv = context.createConvolver();
var conv = new ConvolverNode(context);
is(conv.channelCount, 2, "Convolver node has 2 input channels by default");
is(conv.channelCountMode, "clamped-max", "Correct channelCountMode for the Convolver node");
+28 -1
View File
@@ -14,6 +14,19 @@ var gTest = {
length: 4096,
numberOfChannels: 1,
createGraph: function(context) {
var delay = new DelayNode(context);
ok(delay.delayTime, "The audioparam member must exist");
is(delay.delayTime.value, 0, "Correct initial value");
is(delay.delayTime.defaultValue, 0, "Correct default value");
delay.delayTime.value = 0.5;
is(delay.delayTime.value, 0.5, "Correct initial value");
is(delay.delayTime.defaultValue, 0, "Correct default value");
delay = new DelayNode(context, { delayTime: 0.5 });
ok(delay.delayTime, "The audioparam member must exist");
is(delay.delayTime.value, 0.5, "Correct initial value");
is(delay.delayTime.defaultValue, 0, "Correct default value");
var buffer = context.createBuffer(1, 2048, context.sampleRate);
for (var i = 0; i < 2048; ++i) {
buffer.getChannelData(0)[i] = Math.sin(440 * 2 * Math.PI * i / context.sampleRate);
@@ -21,7 +34,7 @@ var gTest = {
var source = context.createBufferSource();
var delay = context.createDelay();
delay = context.createDelay();
source.buffer = buffer;
@@ -49,6 +62,20 @@ var gTest = {
expectException(function() {
context.createDelay(-1);
}, DOMException.NOT_SUPPORTED_ERR);
expectException(function() {
new DelayNode(context, { maxDelayTime: 0 });
}, DOMException.NOT_SUPPORTED_ERR);
expectException(function() {
new DelayNode(context, { maxDelayTime: 180 });
}, DOMException.NOT_SUPPORTED_ERR);
expectTypeError(function() {
new DelayNode(context, { maxDelayTime: NaN });
}, DOMException.NOT_SUPPORTED_ERR);
expectException(function() {
new DelayNode(context, { maxDelayTime: -1 });
}, DOMException.NOT_SUPPORTED_ERR);
context.createDelay(1); // should not throw
// Delay the source stream by 2048 frames
@@ -20,7 +20,7 @@ addLoadEvent(function() {
var osc = context.createOscillator();
var sp = context.createScriptProcessor();
var compressor = context.createDynamicsCompressor();
var compressor = new DynamicsCompressorNode(context);
osc.connect(compressor);
osc.connect(sp);
+18 -3
View File
@@ -14,17 +14,32 @@ var gTest = {
length: 2048,
numberOfChannels: 1,
createGraph: function(context) {
var gain = new GainNode(context);
ok(gain.gain, "The audioparam member must exist");
is(gain.gain.value, 1.0, "Correct initial value");
is(gain.gain.defaultValue, 1.0, "Correct default value");
gain.gain.value = 0.5;
is(gain.gain.value, 0.5, "Correct initial value");
is(gain.gain.defaultValue, 1.0, "Correct default value");
gain = new GainNode(context, { gain: 0.5 });
ok(gain.gain, "The audioparam member must exist");
is(gain.gain.value, 0.5, "Correct initial value");
is(gain.gain.defaultValue, 1.0, "Correct default value");
gain.gain.value = 0.5;
is(gain.gain.value, 0.5, "Correct initial value");
is(gain.gain.defaultValue, 1.0, "Correct default value");
var buffer = context.createBuffer(1, 2048, context.sampleRate);
for (var i = 0; i < 2048; ++i) {
buffer.getChannelData(0)[i] = Math.sin(440 * 2 * Math.PI * i / context.sampleRate);
}
var source = context.createBufferSource();
var gain = context.createGain();
source.buffer = buffer;
gain = context.createGain();
source.connect(gain);
ok(gain.gain, "The audioparam member must exist");
@@ -56,7 +56,7 @@ function test() {
}
audio.onloadedmetadata = function() {
var node = context.createMediaElementSource(audio);
var node = new MediaElementAudioSourceNode(context, { mediaElement: audio });
var sp = context.createScriptProcessor(2048, 1);
node.connect(sp);
// Use a fuzz factor of 100 to account for samples that just happen to be zero
@@ -23,7 +23,7 @@ addLoadEvent(function() {
var source = context.createBufferSource();
source.buffer = buffer;
var dest = context.createMediaStreamDestination();
var dest = new MediaStreamAudioDestinationNode(context);
source.connect(dest);
var elem = document.getElementById('audioelem');
@@ -31,7 +31,7 @@ var gTest = {
source.connect(dest);
source.start(0);
var mediaStreamSource = context.createMediaStreamSource(dest.stream);
var mediaStreamSource = new MediaStreamAudioSourceNode(context, { mediaStream: dest.stream });
// channelCount and channelCountMode should have no effect
mediaStreamSource.channelCount = 1;
mediaStreamSource.channelCountMode = "explicit";
@@ -14,7 +14,7 @@ SimpleTest.waitForExplicitFinish();
addLoadEvent(function() {
var context = new AudioContext();
var osc = context.createOscillator();
var osc = new OscillatorNode(context);
is(osc.channelCount, 2, "Oscillator node has 2 input channels by default");
is(osc.channelCountMode, "max", "Correct channelCountMode for the Oscillator node");
+1 -1
View File
@@ -25,7 +25,7 @@ addLoadEvent(function() {
var source = context.createBufferSource();
var panner = context.createPanner();
var panner = new PannerNode(context);
source.buffer = buffer;
@@ -49,7 +49,7 @@ function applyMonoToStereoPanning(c, panning) {
// Test the DOM interface
var context = new OfflineAudioContext(1, 1, SR);
var stereoPanner = context.createStereoPanner();
var stereoPanner = new StereoPannerNode(context);
ok(stereoPanner.pan, "The AudioParam member must exist");
is(stereoPanner.pan.value, 0.0, "Correct initial value");
is(stereoPanner.pan.defaultValue, 0.0, "Correct default value");
@@ -70,8 +70,11 @@ function sine(t) {
// A couple mono and stereo buffers: the StereoPannerNode equation is different
// if the input is mono or stereo
var stereoBuffer = context.createBuffer(2, BUF_SIZE, context.sampleRate);
var monoBuffer = context.createBuffer(1, BUF_SIZE, context.sampleRate);
var stereoBuffer = new AudioBuffer(context, { numberOfChannels: 2,
length: BUF_SIZE });
var monoBuffer = new AudioBuffer(context, { numberOfChannels: 1,
length: BUF_SIZE,
sampleRate: context.sampleRate });
for (var i = 0; i < BUF_SIZE; ++i) {
monoBuffer.getChannelData(0)[i] =
stereoBuffer.getChannelData(0)[i] =
@@ -81,7 +84,9 @@ for (var i = 0; i < BUF_SIZE; ++i) {
// Expected test vectors
function expectedBufferNoop(gain) {
gain = gain || 1.0;
var expectedBuffer = context.createBuffer(2, BUF_SIZE, SR);
var expectedBuffer = new AudioBuffer(context, { numberOfChannels: 2,
length: BUF_SIZE,
sampleRate: SR });
for (var i = 0; i < BUF_SIZE; i++) {
expectedBuffer.getChannelData(0)[i] = gain * sine(i);
expectedBuffer.getChannelData(1)[i] = gain * sine(i);
@@ -91,7 +96,9 @@ function expectedBufferNoop(gain) {
function expectedBufferForStereo(gain) {
gain = gain || 1.0;
var expectedBuffer = context.createBuffer(2, BUF_SIZE, SR);
var expectedBuffer = new AudioBuffer(context, { numberOfChannels: 2,
length: BUF_SIZE,
sampleRate: SR });
var gainPanning = gainForPanningStereoToStereo(PANNING);
gainPanning[0] *= gain;
gainPanning[1] *= gain;
@@ -106,7 +113,9 @@ function expectedBufferForStereo(gain) {
function expectedBufferForMono(gain) {
gain = gain || 1.0;
var expectedBuffer = context.createBuffer(2, BUF_SIZE, SR);
var expectedBuffer = new AudioBuffer(context, { numberOfChannels: 2,
length: BUF_SIZE,
sampleRate: SR });
var gainPanning = gainForPanningMonoToStereo(PANNING);
gainPanning[0] *= gain;
gainPanning[1] *= gain;
+1 -1
View File
@@ -17,7 +17,7 @@ var gTest = {
var source = context.createBufferSource();
source.buffer = this.buffer;
var shaper = context.createWaveShaper();
var shaper = new WaveShaperNode(context);
shaper.curve = this.curve;
source.connect(shaper);
+7 -12
View File
@@ -613,14 +613,6 @@ ScriptLoader::CreateModuleScript(ModuleLoadRequest* aRequest)
nsresult rv;
{
// Update our current script.
Maybe<AutoCurrentScriptUpdater> masterScriptUpdater;
nsCOMPtr<nsIDocument> master = mDocument->MasterDocument();
if (master != mDocument) {
masterScriptUpdater.emplace(master->ScriptLoader(),
aRequest->Element());
}
JSContext* cx = aes.cx();
JS::Rooted<JSObject*> module(cx);
@@ -2323,8 +2315,14 @@ ScriptLoader::EvaluateScript(ScriptLoadRequest* aRequest)
return NS_ERROR_FAILURE;
}
// Update our current script.
// This must be destroyed after destroying nsAutoMicroTask.
nsIScriptElement* currentScript =
aRequest->IsModuleRequest() ? nullptr : aRequest->Element();
AutoCurrentScriptUpdater scriptUpdater(this, currentScript);
// New script entry point required, due to the "Create a script" sub-step of
// http://www.whatwg.org/specs/web-apps/current-work/#execute-the-script-block
// http://html.spec.whatwg.org/multipage/#execute-the-script-block
nsAutoMicroTask mt;
AutoEntryScript aes(globalObject, "<script> element", true);
JSContext* cx = aes.cx();
@@ -2382,9 +2380,6 @@ ScriptLoader::EvaluateScript(ScriptLoadRequest* aRequest)
FinishDynamicImport(cx, request, rv);
}
} else {
// Update our current script.
AutoCurrentScriptUpdater scriptUpdater(this, aRequest->Element());
JS::CompileOptions options(cx);
rv = FillCompileOptionsForRequest(aes, aRequest, global, &options);
+3 -1
View File
@@ -324,7 +324,9 @@ class ScriptLoader final : public nsISupports
: mOldScript(aScriptLoader->mCurrentScript)
, mScriptLoader(aScriptLoader)
{
mScriptLoader->mCurrentScript = aCurrentScript;
nsCOMPtr<nsINode> node = do_QueryInterface(aCurrentScript);
mScriptLoader->mCurrentScript =
node && !node->IsInShadowTree() ? aCurrentScript : nullptr;
}
~AutoCurrentScriptUpdater()
{
+85 -23
View File
@@ -57,7 +57,84 @@ CreateObjectURLInternal(const GlobalObject& aGlobal, T aObject,
CopyASCIItoUTF16(url, aResult);
}
// The URL implementation for the main-thread
bool
IsRootRelativePathInput(const nsAString& aURL)
{
return !aURL.IsEmpty() && aURL.CharAt(0) == '/' &&
(aURL.Length() == 1 || aURL.CharAt(1) != '/');
}
bool
BuildRootRelativeFallbackSpec(const nsAString& aURL, nsIURI* aBase,
nsACString& aFallbackSpec)
{
MOZ_ASSERT(aBase);
MOZ_ASSERT(IsRootRelativePathInput(aURL));
nsAutoCString baseSpec;
if (NS_FAILED(aBase->GetSpec(baseSpec)) || baseSpec.IsEmpty()) {
return false;
}
int32_t colon = baseSpec.FindChar(':');
if (colon <= 0) {
return false;
}
uint32_t afterColon = static_cast<uint32_t>(colon + 1);
if (afterColon >= baseSpec.Length() || baseSpec.CharAt(afterColon) != '/') {
// Opaque paths (for example mailto:test@example.com) are not valid bases
// for root-relative URL input.
return false;
}
nsAutoCString input;
if (!AppendUTF16toUTF8(aURL, input, fallible)) {
return false;
}
// Preserve authority when present (scheme://authority/path -> scheme://authority/input)
if (afterColon + 1 < baseSpec.Length() && baseSpec.CharAt(afterColon + 1) == '/') {
uint32_t authorityEnd = afterColon + 2;
while (authorityEnd < baseSpec.Length()) {
char c = baseSpec.CharAt(authorityEnd);
if (c == '/' || c == '?' || c == '#') {
break;
}
++authorityEnd;
}
aFallbackSpec.Assign(Substring(baseSpec, 0, authorityEnd));
aFallbackSpec.Append(input);
return true;
}
// Single-slash hierarchical base (scheme:/path -> scheme:/input)
aFallbackSpec.Assign(Substring(baseSpec, 0, afterColon));
aFallbackSpec.Append(input);
return true;
}
bool
TryResolveRootRelativeAgainstBase(const nsAString& aURL, nsIURI* aBase,
nsIURI** aOutURI)
{
MOZ_ASSERT(aOutURI);
if (!aBase || !IsRootRelativePathInput(aURL)) {
return false;
}
nsAutoCString fallbackSpec;
if (!BuildRootRelativeFallbackSpec(aURL, aBase, fallbackSpec)) {
return false;
}
nsresult rv = NS_NewURI(aOutURI, fallbackSpec, nullptr, nullptr,
nsContentUtils::GetIOService());
return NS_SUCCEEDED(rv);
}
class URLMainThread final : public URL
{
public:
@@ -229,7 +306,8 @@ URLMainThread::Constructor(nsISupports* aParent, const nsAString& aURL,
nsCOMPtr<nsIURI> uri;
nsresult rv = NS_NewURI(getter_AddRefs(uri), aURL, nullptr, aBase,
nsContentUtils::GetIOService());
if (NS_FAILED(rv)) {
if (NS_FAILED(rv) &&
!TryResolveRootRelativeAgainstBase(aURL, aBase, getter_AddRefs(uri))) {
// No need to warn in this case. It's common to use the URL constructor
// to determine if a URL is valid and an exception will be propagated.
aRv.ThrowTypeError<MSG_INVALID_URL>(aURL);
@@ -1714,30 +1792,14 @@ URL::IsValidURL(const GlobalObject& aGlobal, const nsAString& aURL,
bool
URL::CanParse(const GlobalObject& aGlobal, const nsAString& aURL,
const Optional<nsAString>& aBase) {
nsCOMPtr<nsIURI> baseUri;
if (aBase.WasPassed()) {
// Don't use NS_ConvertUTF16toUTF8 because that doesn't let us handle OOM.
nsAutoCString base;
if (!AppendUTF16toUTF8(aBase.Value(), base, fallible)) {
// Just return false with OOM errors as no ErrorResult.
return false;
}
nsresult rv = NS_NewURI(getter_AddRefs(baseUri), base);
if (NS_FAILED(rv)) {
// Invalid base URL, return false.
return false;
}
}
nsAutoCString urlStr;
if (!AppendUTF16toUTF8(aURL, urlStr, fallible)) {
// Just return false with OOM errors as no ErrorResult.
ErrorResult rv;
RefPtr<URL> parsed = URL::Constructor(aGlobal, aURL, aBase, rv);
if (rv.Failed() || !parsed) {
rv.SuppressException();
return false;
}
nsCOMPtr<nsIURI> uri;
return NS_SUCCEEDED(NS_NewURI(getter_AddRefs(uri), urlStr, nullptr, baseUri));
return true;
}
URLSearchParams*
+414 -412
View File
@@ -1,460 +1,462 @@
<!DOCTYPE HTML>
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Test URL API</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=887364">Mozilla Bug 887364</a>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=991471">Mozilla Bug 991471</a>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=996055">Mozilla Bug 996055</a>
<p id="display"></p>
<div id="content" style="display: none">
<iframe name="x" id="x"></iframe>
<iframe name="y" id="y"></iframe>
</div>
<pre id="test">
</pre>
<script type="application/javascript">
<head>
<meta charset="utf-8" />
<title>Test URL API</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=887364">Mozilla Bug 887364</a>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=991471">Mozilla Bug 991471</a>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=996055">Mozilla Bug 996055</a>
<p id="display"></p>
<div id="content" style="display: none">
<iframe name="x" id="x"></iframe>
<iframe name="y" id="y"></iframe>
</div>
<pre id="test"></pre>
<script type="application/javascript">
/** Test for Bug 887364 **/
ok("URL" in window, "window.URL exists");
/** Test for Bug 887364 **/
ok("URL" in window, "window.URL exists");
var tests = [
{
url: "http://www.abc.com",
base: undefined,
error: false,
href: "http://www.abc.com/",
origin: "http://www.abc.com",
protocol: "http:",
username: "",
password: "",
host: "www.abc.com",
hostname: "www.abc.com",
port: "",
pathname: "/",
search: "",
hash: "",
},
{
url: "ftp://auser:apw@www.abc.com",
base: undefined,
error: false,
href: "ftp://auser:apw@www.abc.com/",
origin: "ftp://www.abc.com",
protocol: "ftp:",
username: "auser",
password: "apw",
host: "www.abc.com",
hostname: "www.abc.com",
port: "",
pathname: "/",
search: "",
hash: "",
},
{
url: "http://www.abc.com:90/apath/",
base: undefined,
error: false,
href: "http://www.abc.com:90/apath/",
origin: "http://www.abc.com:90",
protocol: "http:",
username: "",
password: "",
host: "www.abc.com:90",
hostname: "www.abc.com",
port: "90",
pathname: "/apath/",
search: "",
hash: "",
},
{
url: "http://www.abc.com/apath/afile.txt#ahash",
base: undefined,
error: false,
href: "http://www.abc.com/apath/afile.txt#ahash",
origin: "http://www.abc.com",
protocol: "http:",
username: "",
password: "",
host: "www.abc.com",
hostname: "www.abc.com",
port: "",
pathname: "/apath/afile.txt",
search: "",
hash: "#ahash",
},
{
url: "http://example.com/?test#hash",
base: undefined,
error: false,
href: "http://example.com/?test#hash",
origin: "http://example.com",
protocol: "http:",
username: "",
password: "",
host: "example.com",
hostname: "example.com",
port: "",
pathname: "/",
search: "?test",
hash: "#hash",
},
{
url: "http://example.com/?test",
base: undefined,
error: false,
href: "http://example.com/?test",
origin: "http://example.com",
protocol: "http:",
username: "",
password: "",
host: "example.com",
hostname: "example.com",
port: "",
pathname: "/",
search: "?test",
hash: "",
},
{ url: "http://example.com/carrot#question%3f", base: undefined, error: false, hash: "#question%3f" },
{
url: "https://example.com:4443?",
base: undefined,
error: false,
protocol: "https:",
port: "4443",
pathname: "/",
hash: "",
search: "",
},
{
url: "http://www.abc.com/apath/afile.txt#ahash?asearch",
base: undefined,
error: false,
href: "http://www.abc.com/apath/afile.txt#ahash?asearch",
protocol: "http:",
pathname: "/apath/afile.txt",
hash: "#ahash?asearch",
search: "",
},
{
url: "http://www.abc.com/apath/afile.txt?asearch#ahash",
base: undefined,
error: false,
href: "http://www.abc.com/apath/afile.txt?asearch#ahash",
protocol: "http:",
pathname: "/apath/afile.txt",
hash: "#ahash",
search: "?asearch",
},
{
url: "http://abc.com/apath/afile.txt?#ahash",
base: undefined,
error: false,
pathname: "/apath/afile.txt",
hash: "#ahash",
search: "",
},
{
url: "http://auser:apassword@www.abc.com:90/apath/afile.txt?asearch#ahash",
base: undefined,
error: false,
protocol: "http:",
username: "auser",
password: "apassword",
host: "www.abc.com:90",
hostname: "www.abc.com",
port: "90",
pathname: "/apath/afile.txt",
hash: "#ahash",
search: "?asearch",
origin: "http://www.abc.com:90",
},
var tests = [
{ url: 'http://www.abc.com',
base: undefined,
error: false,
href: 'http://www.abc.com/',
origin: 'http://www.abc.com',
protocol: 'http:',
username: '',
password: '',
host: 'www.abc.com',
hostname: 'www.abc.com',
port: '',
pathname: '/',
search: '',
hash: ''
},
{ url: 'ftp://auser:apw@www.abc.com',
base: undefined,
error: false,
href: 'ftp://auser:apw@www.abc.com/',
origin: 'ftp://www.abc.com',
protocol: 'ftp:',
username: 'auser',
password: 'apw',
host: 'www.abc.com',
hostname: 'www.abc.com',
port: '',
pathname: '/',
search: '',
hash: ''
},
{ url: 'http://www.abc.com:90/apath/',
base: undefined,
error: false,
href: 'http://www.abc.com:90/apath/',
origin: 'http://www.abc.com:90',
protocol: 'http:',
username: '',
password: '',
host: 'www.abc.com:90',
hostname: 'www.abc.com',
port: '90',
pathname: '/apath/',
search: '',
hash: ''
},
{ url: 'http://www.abc.com/apath/afile.txt#ahash',
base: undefined,
error: false,
href: 'http://www.abc.com/apath/afile.txt#ahash',
origin: 'http://www.abc.com',
protocol: 'http:',
username: '',
password: '',
host: 'www.abc.com',
hostname: 'www.abc.com',
port: '',
pathname: '/apath/afile.txt',
search: '',
hash: '#ahash'
},
{ url: 'http://example.com/?test#hash',
base: undefined,
error: false,
href: 'http://example.com/?test#hash',
origin: 'http://example.com',
protocol: 'http:',
username: '',
password: '',
host: 'example.com',
hostname: 'example.com',
port: '',
pathname: '/',
search: '?test',
hash: '#hash'
},
{ url: 'http://example.com/?test',
base: undefined,
error: false,
href: 'http://example.com/?test',
origin: 'http://example.com',
protocol: 'http:',
username: '',
password: '',
host: 'example.com',
hostname: 'example.com',
port: '',
pathname: '/',
search: '?test',
hash: ''
},
{ url: 'http://example.com/carrot#question%3f',
base: undefined,
error: false,
hash: '#question%3f'
},
{ url: 'https://example.com:4443?',
base: undefined,
error: false,
protocol: 'https:',
port: '4443',
pathname: '/',
hash: '',
search: ''
},
{ url: 'http://www.abc.com/apath/afile.txt#ahash?asearch',
base: undefined,
error: false,
href: 'http://www.abc.com/apath/afile.txt#ahash?asearch',
protocol: 'http:',
pathname: '/apath/afile.txt',
hash: '#ahash?asearch',
search: ''
},
{ url: 'http://www.abc.com/apath/afile.txt?asearch#ahash',
base: undefined,
error: false,
href: 'http://www.abc.com/apath/afile.txt?asearch#ahash',
protocol: 'http:',
pathname: '/apath/afile.txt',
hash: '#ahash',
search: '?asearch'
},
{ url: 'http://abc.com/apath/afile.txt?#ahash',
base: undefined,
error: false,
pathname: '/apath/afile.txt',
hash: '#ahash',
search: ''
},
{ url: 'http://auser:apassword@www.abc.com:90/apath/afile.txt?asearch#ahash',
base: undefined,
error: false,
protocol: 'http:',
username: 'auser',
password: 'apassword',
host: 'www.abc.com:90',
hostname: 'www.abc.com',
port: '90',
pathname: '/apath/afile.txt',
hash: '#ahash',
search: '?asearch',
origin: 'http://www.abc.com:90'
},
{ url: "/foo#bar", base: "www.test.org", error: true },
{ url: "/foo#bar", base: null, error: true },
{ url: "/foo#bar", base: 42, error: true },
{ url: "ftp://ftp.something.net", base: undefined, error: false, protocol: "ftp:" },
{ url: "file:///tmp/file", base: undefined, error: false, protocol: "file:" },
{ url: "gopher://gopher.something.net", base: undefined, error: false, protocol: "gopher:" },
{ url: "ws://ws.something.net", base: undefined, error: false, protocol: "ws:" },
{ url: "wss://ws.something.net", base: undefined, error: false, protocol: "wss:" },
{ url: "foo://foo.something.net", base: undefined, error: false, protocol: "foo:" },
{ url: '/foo#bar',
base: 'www.test.org',
error: true,
},
{ url: '/foo#bar',
base: null,
error: true,
},
{ url: '/foo#bar',
base: 42,
error: true,
},
{ url: 'ftp://ftp.something.net',
base: undefined,
error: false,
protocol: 'ftp:',
},
{ url: 'file:///tmp/file',
base: undefined,
error: false,
protocol: 'file:',
},
{ url: 'gopher://gopher.something.net',
base: undefined,
error: false,
protocol: 'gopher:',
},
{ url: 'ws://ws.something.net',
base: undefined,
error: false,
protocol: 'ws:',
},
{ url: 'wss://ws.something.net',
base: undefined,
error: false,
protocol: 'wss:',
},
{ url: 'foo://foo.something.net',
base: undefined,
error: false,
protocol: 'foo:',
},
{
url: "about:blank",
base: undefined,
error: false,
protocol: "about:",
pathname: "blank",
skip_setters: false,
},
{ url: 'about:blank',
base: undefined,
error: false,
protocol: 'about:',
pathname: 'blank',
skip_setters: false,
},
{
url: "foo:bar?what#yeah",
base: undefined,
error: false,
protocol: "foo:",
pathname: "bar",
search: "?what",
hash: "#yeah",
skip_setters: false,
},
];
{ url: 'foo:bar?what#yeah',
base: undefined,
error: false,
protocol: 'foo:',
pathname: 'bar',
search: '?what',
hash: '#yeah',
skip_setters: false,
},
];
while (tests.length) {
var test = tests.shift();
while(tests.length) {
var test = tests.shift();
var error = false;
var url;
try {
if (test.base) {
url = new URL(test.url, test.base);
} else {
url = new URL(test.url);
}
} catch (e) {
error = true;
}
var error = false;
var url;
try {
if (test.base) {
url = new URL(test.url, test.base);
} else {
url = new URL(test.url);
}
} catch(e) {
error = true;
}
is(test.error, error, "Error creating URL");
if (test.error) {
continue;
}
is(test.error, error, "Error creating URL");
if (test.error) {
continue;
}
if ("href" in test) is(url.href, test.href, "href");
if ("origin" in test) is(url.origin, test.origin, "origin");
if ("protocol" in test) is(url.protocol, test.protocol, "protocol");
if ("username" in test) is(url.username, test.username, "username");
if ("password" in test) is(url.password, test.password, "password");
if ("host" in test) is(url.host, test.host, "host");
if ("hostname" in test) is(url.hostname, test.hostname, "hostname");
if ("port" in test) is(url.port, test.port, "port");
if ("pathname" in test) is(url.pathname, test.pathname, "pathname");
if ("search" in test) is(url.search, test.search, "search");
if ("hash" in test) is(url.hash, test.hash, "hash");
if ('href' in test) is(url.href, test.href, "href");
if ('origin' in test) is(url.origin, test.origin, "origin");
if ('protocol' in test) is(url.protocol, test.protocol, "protocol");
if ('username' in test) is(url.username, test.username, "username");
if ('password' in test) is(url.password, test.password, "password");
if ('host' in test) is(url.host, test.host, "host");
if ('hostname' in test) is(url.hostname, test.hostname, "hostname");
if ('port' in test) is(url.port, test.port, "port");
if ('pathname' in test) is(url.pathname, test.pathname, "pathname");
if ('search' in test) is(url.search, test.search, "search");
if ('hash' in test) is(url.hash, test.hash, "hash");
if ("skip_setters" in test && test.skip_setters == false) {
info("Skip setter methods for URL: " + test);
continue;
}
if ('skip_setters' in test && test.skip_setters == false) {
info("Skip setter methods for URL: " + test);
continue;
}
url = new URL("https://www.example.net/what#foo?bar");
ok(url, "Url exists!");
url = new URL('https://www.example.net/what#foo?bar');
ok(url, "Url exists!");
if ("href" in test) url.href = test.href;
if ("protocol" in test) url.protocol = test.protocol;
if ("username" in test && test.username) url.username = test.username;
if ("password" in test && test.password) url.password = test.password;
if ("host" in test) url.host = test.host;
if ("hostname" in test) url.hostname = test.hostname;
if ("port" in test) url.port = test.port;
if ("pathname" in test) url.pathname = test.pathname;
if ("search" in test) url.search = test.search;
if ("hash" in test) url.hash = test.hash;
if ('href' in test) url.href = test.href;
if ('protocol' in test) url.protocol = test.protocol;
if ('username' in test && test.username) url.username = test.username;
if ('password' in test && test.password) url.password = test.password;
if ('host' in test) url.host = test.host;
if ('hostname' in test) url.hostname = test.hostname;
if ('port' in test) url.port = test.port;
if ('pathname' in test) url.pathname = test.pathname;
if ('search' in test) url.search = test.search;
if ('hash' in test) url.hash = test.hash;
if ("href" in test) is(url.href, test.href, "href");
if ("origin" in test) is(url.origin, test.origin, "origin");
if ("protocol" in test) is(url.protocol, test.protocol, "protocol");
if ("username" in test) is(url.username, test.username, "username");
if ("password" in test) is(url.password, test.password, "password");
if ("host" in test) is(url.host, test.host, "host");
if ("hostname" in test) is(test.hostname, url.hostname, "hostname");
if ("port" in test) is(test.port, url.port, "port");
if ("pathname" in test) is(test.pathname, url.pathname, "pathname");
if ("search" in test) is(test.search, url.search, "search");
if ("hash" in test) is(test.hash, url.hash, "hash");
if ('href' in test) is(url.href, test.href, "href");
if ('origin' in test) is(url.origin, test.origin, "origin");
if ('protocol' in test) is(url.protocol, test.protocol, "protocol");
if ('username' in test) is(url.username, test.username, "username");
if ('password' in test) is(url.password, test.password, "password");
if ('host' in test) is(url.host, test.host, "host");
if ('hostname' in test) is(test.hostname, url.hostname, "hostname");
if ('port' in test) is(test.port, url.port, "port");
if ('pathname' in test) is(test.pathname, url.pathname, "pathname");
if ('search' in test) is(test.search, url.search, "search");
if ('hash' in test) is(test.hash, url.hash, "hash");
if ("href" in test) is(test.href, url + "", "stringify works");
}
</script>
if ('href' in test) is (test.href, url + '', 'stringify works');
}
<script>
/** Test for Bug 991471 **/
var url = new URL("http://localhost/");
url.hostname = "";
url.username = "tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt";
url.hostname = "www.mozilla.org";
url.username = "";
url.hostname = "www.mozilla.org";
is(url.href, "http://www.mozilla.org/", "No parsing error with empty host");
</script>
</script>
<script>
/** Test for Bug 996055 **/
var url = new URL("http://localhost/");
url.hostname = "";
is(url.href, "http://localhost/", "Empty hostname is ignored");
</script>
<script>
/** Test for Bug 991471 **/
var url = new URL("http://localhost/");
url.hostname = "";
url.username = "tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt";
url.hostname = "www.mozilla.org";
url.username = "";
url.hostname = "www.mozilla.org";
is(url.href, "http://www.mozilla.org/", "No parsing error with empty host");
</script>
<script>
/** Test for Bug 960014 **/
var url = new URL("http://localhost/");
url.hostname = "[2001::1]";
is(url.hostname, "[2001::1]", "IPv6 hostname");
is(url.href, "http://[2001::1]/");
<script>
/** Test for Bug 996055 **/
var url = new URL("http://localhost/");
url.hostname = "";
is(url.href, "http://localhost/", "Empty hostname is ignored");
</script>
url.hostname = "[::192.9.5.5]";
is(url.hostname, "[::192.9.5.5]", "IPv6 hostname");
is(url.href, "http://[::192.9.5.5]/");
<script>
/** Test for Bug 960014 **/
var url = new URL("http://localhost/");
url.hostname = "[2001::1]";
is(url.hostname, "[2001::1]", "IPv6 hostname");
is(url.href, "http://[2001::1]/");
url = new URL("http://localhost/");
url.hostname = "[::]";
is(url.hostname, "[::]", "IPv6 hostname");
url.hostname = "[::192.9.5.5]";
is(url.hostname, "[::192.9.5.5]", "IPv6 hostname");
is(url.href, "http://[::192.9.5.5]/");
url = new URL("http://localhost/");
url.host = "[2001::1]:30";
is(url.hostname, "[2001::1]", "IPv6 hostname");
is(url.port, "30", "Port");
is(url.host, "[2001::1]:30", "IPv6 host");
url = new URL("http://localhost/");
url.hostname = "[::]";
is(url.hostname, "[::]", "IPv6 hostname");
url = new URL("http://localhost/");
// This should silently fail since it's missing the brackets
url.hostname = "2001::1";
is(url.hostname, "localhost", "Setting bad hostname fails");
</script>
url = new URL("http://localhost/");
url.host = "[2001::1]:30";
is(url.hostname, "[2001::1]", "IPv6 hostname");
is(url.port, "30", "Port");
is(url.host, "[2001::1]:30", "IPv6 host");
<script>
var blob = new Blob(["a"]);
var url = URL.createObjectURL(blob);
url = new URL("http://localhost/");
// This should silently fail since it's missing the brackets
url.hostname = "2001::1";
is(url.hostname, "localhost", "Setting bad hostname fails");
</script>
var u = new URL(url);
ok(u.origin, "http://mochi.test:8888", "The URL generated from a blob URI has an origin");
</script>
<script>
var blob = new Blob(['a']);
var url = URL.createObjectURL(blob);
<script>
var blob = new Blob(["a"]);
var url = URL.createObjectURL(blob);
var u = new URL(url);
ok(u.origin, 'http://mochi.test:8888', "The URL generated from a blob URI has an origin");
</script>
var a = document.createElement("A");
a.href = url;
ok(a.origin, "http://mochi.test:8888", "The 'a' element has the correct origin");
</script>
<script>
var blob = new Blob(['a']);
var url = URL.createObjectURL(blob);
<script>
var blob = new Blob(["a"]);
var url = URL.createObjectURL(blob);
URL.revokeObjectURL(url);
URL.revokeObjectURL(url);
ok(true, "Calling revokeObjectURL twice should be ok");
</script>
var a = document.createElement('A');
a.href = url;
ok(a.origin, 'http://mochi.test:8888', "The 'a' element has the correct origin");
</script>
<script>
URL.revokeObjectURL("blob:something");
ok(true, "This should not throw.");
</script>
<script>
var blob = new Blob(['a']);
var url = URL.createObjectURL(blob);
URL.revokeObjectURL(url);
URL.revokeObjectURL(url);
ok(true, "Calling revokeObjectURL twice should be ok");
</script>
<script>
var base = new URL("http:\\\\test.com\\path/to\\file?query\\backslash#hash\\");
is(base.href, "http://test.com/path/to/file?query\\backslash#hash\\");
<script>
URL.revokeObjectURL('blob:something');
ok(true, "This should not throw.");
</script>
var url = new URL("..\\", base);
is(url.href, "http://test.com/path/");
<script>
var base = new URL("http:\\\\test.com\\path/to\\file?query\\backslash#hash\\");
is(base.href, "http://test.com/path/to/file?query\\backslash#hash\\");
url = new URL("\\test", base);
is(url.href, "http://test.com/test");
var url = new URL("..\\", base);
is(url.href, "http://test.com/path/");
url = new URL("\\test\\", base);
is(url.href, "http://test.com/test/");
url = new URL("\\test", base);
is(url.href, "http://test.com/test");
url = new URL("http://example.org/test", base);
is(url.href, "http://example.org/test");
url = new URL("\\test\\", base);
is(url.href, "http://test.com/test/");
url = new URL("ftp://tmp/test", base);
is(url.href, "ftp://tmp/test");
url = new URL("http://example.org/test", base);
is(url.href, "http://example.org/test");
url = new URL("ftp:\\\\tmp\\test", base);
is(url.href, "ftp://tmp/test");
url = new URL("ftp://tmp/test", base);
is(url.href, "ftp://tmp/test");
url = new URL("scheme://tmp\\test", base);
is(url.href, "scheme://tmp\\test");
</script>
url = new URL("ftp:\\\\tmp\\test", base);
is(url.href, "ftp://tmp/test");
<script>
/** Test for Bug 1275746 **/
SimpleTest.doesThrow(() => {
var url = new URL("http:");
}, "http: is not a valid URL");
SimpleTest.doesThrow(() => {
var url = new URL("http:///");
}, "http: is not a valid URL");
url = new URL("scheme://tmp\\test", base);
is(url.href, "scheme://tmp\\test");
</script>
var url = new URL("file:");
is(url.href, "file:///", "Parsing file: should work.");
<script>
/** Test for Bug 1275746 **/
SimpleTest.doesThrow(() => { var url = new URL("http:"); }, "http: is not a valid URL");
SimpleTest.doesThrow(() => { var url = new URL("http:///"); }, "http: is not a valid URL");
url = new URL("file:///");
is(url.href, "file:///", "Parsing file:/// should work.");
</script>
var url = new URL("file:");
is(url.href, "file:///", "Parsing file: should work.");
<script>
var url = new URL("scheme:path/to/file?query#hash");
is(url.href, "scheme:path/to/file?query#hash");
is(url.pathname, "path/to/file");
is(url.search, "?query");
is(url.hash, "#hash");
url = new URL("file:///");
is(url.href, "file:///", "Parsing file:/// should work.");
</script>
// pathname cannot be overwritten.
url.pathname = "new/path?newquery#newhash";
is(url.href, "scheme:path/to/file?query#hash");
<script>
var url = new URL("scheme:path/to/file?query#hash");
is(url.href, "scheme:path/to/file?query#hash");
is(url.pathname, "path/to/file");
is(url.search, "?query");
is(url.hash, "#hash");
// don't escape '#' until we implement a spec-compliant parser.
url.search = "?newquery#newhash";
is(url.href, "scheme:path/to/file?newquery#newhash#hash");
// pathname cannot be overwritten.
url.pathname = "new/path?newquery#newhash";
is(url.href, "scheme:path/to/file?query#hash");
// nulls get encoded, whitespace gets stripped
url = new URL("scheme:pa\0\nth/to/fi\0\nle?qu\0\nery#ha\0\nsh");
is(url.href, "scheme:pa%00th/to/fi%00le?qu%00ery#ha%00sh");
// don't escape '#' until we implement a spec-compliant parser.
url.search = "?newquery#newhash";
is(url.href, "scheme:path/to/file?newquery#newhash#hash");
url.search = "new\0\nquery";
is(url.href, "scheme:pa%00th/to/fi%00le?new%00%0Aquery#ha%00sh");
url.hash = "new\0\nhash";
is(url.href, "scheme:pa%00th/to/fi%00le?new%00%0Aquery#new%00%0Ahash");
// nulls get encoded, whitespace gets stripped
url = new URL("scheme:pa\0\nth/to/fi\0\nle?qu\0\nery#ha\0\nsh");
is(url.href, "scheme:pa%00th/to/fi%00le?qu%00ery#ha%00sh");
url = new URL("scheme:path#hash");
is(url.href, "scheme:path#hash");
url.search = "query";
is(url.href, "scheme:path?query#hash");
url.hash = "";
is(url.href, "scheme:path?query");
url.hash = "newhash";
is(url.href, "scheme:path?query#newhash");
url.search = "";
is(url.href, "scheme:path#newhash");
url.search = "new\0\nquery";
is(url.href, "scheme:pa%00th/to/fi%00le?new%00%0Aquery#ha%00sh");
url.hash = "new\0\nhash";
is(url.href, "scheme:pa%00th/to/fi%00le?new%00%0Aquery#new%00%0Ahash");
// we don't implement a spec-compliant parser yet.
// make sure we are bug compatible with existing implementations.
url = new URL('data:text/html,<a href="http://example.org/?q">Link</a>');
is(url.href, 'data:text/html,<a%20href="http://example.org/?q">Link</a>');
</script>
url = new URL("scheme:path#hash");
is(url.href, "scheme:path#hash");
url.search = "query";
is(url.href, "scheme:path?query#hash");
url.hash = "";
is(url.href, "scheme:path?query");
url.hash = "newhash";
is(url.href, "scheme:path?query#newhash");
url.search = "";
is(url.href, "scheme:path#newhash");
<script>
is(
new URL("/static/client/runtime.js", "x:/").href,
"x:/static/client/runtime.js",
"URL constructor accepts root-relative input with x:/ base",
);
ok("canParse" in URL, "URL.canParse exists");
ok(
URL.canParse("/static/client/runtime.js", "x:/"),
"URL.canParse accepts root-relative input with x:/ base",
);
ok(
URL.canParse("/static/client/runtime.js", document.baseURI),
"URL.canParse accepts root-relative input with document base",
);
ok(!URL.canParse("/static/client/runtime.js"), "URL.canParse rejects root-relative input without base");
ok(
!URL.canParse("/static/client/runtime.js", "mailto:test@example.com"),
"URL.canParse rejects root-relative input against opaque mailto: base",
);
SimpleTest.doesThrow(() => {
new URL("/static/client/runtime.js", "mailto:test@example.com");
}, "constructor rejects root-relative input against opaque mailto: base");
</script>
// we don't implement a spec-compliant parser yet.
// make sure we are bug compatible with existing implementations.
url = new URL("data:text/html,<a href=\"http://example.org/?q\">Link</a>");
is(url.href, "data:text/html,<a%20href=\"http://example.org/?q\">Link</a>");
</script>
<script>
var u = new URL('http://www.example.org');
ok(u.toJSON(), 'http://www.example.org', "URL.toJSON()");
is(JSON.stringify(u), "\"http://www.example.org/\"", "JSON.stringify(u) works");
</script>
</body>
<script>
var u = new URL("http://www.example.org");
ok(u.toJSON(), "http://www.example.org", "URL.toJSON()");
is(JSON.stringify(u), '"http://www.example.org/"', "JSON.stringify(u) works");
</script>
</body>
</html>
+220 -176
View File
@@ -1,212 +1,224 @@
function ok(a, msg) {
dump("OK: " + !!a + " => " + a + " " + msg + "\n");
postMessage({type: 'status', status: !!a, msg: a + ": " + msg });
postMessage({ type: "status", status: !!a, msg: a + ": " + msg });
}
function is(a, b, msg) {
dump("IS: " + (a===b) + " => " + a + " | " + b + " " + msg + "\n");
postMessage({type: 'status', status: a === b, msg: a + " === " + b + ": " + msg });
dump("IS: " + (a === b) + " => " + a + " | " + b + " " + msg + "\n");
postMessage({
type: "status",
status: a === b,
msg: a + " === " + b + ": " + msg,
});
}
onmessage = function() {
onmessage = function () {
status = false;
try {
if ((URL instanceof Object)) {
if (URL instanceof Object) {
status = true;
}
} catch(e) {
}
} catch (e) {}
var tests = [
{ url: 'http://www.abc.com',
{
url: "http://www.abc.com",
base: undefined,
error: false,
href: 'http://www.abc.com/',
origin: 'http://www.abc.com',
protocol: 'http:',
username: '',
password: '',
host: 'www.abc.com',
hostname: 'www.abc.com',
port: '',
pathname: '/',
search: '',
hash: ''
href: "http://www.abc.com/",
origin: "http://www.abc.com",
protocol: "http:",
username: "",
password: "",
host: "www.abc.com",
hostname: "www.abc.com",
port: "",
pathname: "/",
search: "",
hash: "",
},
{ url: 'ftp://auser:apw@www.abc.com',
{
url: "ftp://auser:apw@www.abc.com",
base: undefined,
error: false,
href: 'ftp://auser:apw@www.abc.com/',
origin: 'ftp://www.abc.com',
protocol: 'ftp:',
username: 'auser',
password: 'apw',
host: 'www.abc.com',
hostname: 'www.abc.com',
port: '',
pathname: '/',
search: '',
hash: ''
href: "ftp://auser:apw@www.abc.com/",
origin: "ftp://www.abc.com",
protocol: "ftp:",
username: "auser",
password: "apw",
host: "www.abc.com",
hostname: "www.abc.com",
port: "",
pathname: "/",
search: "",
hash: "",
},
{ url: 'http://www.abc.com:90/apath/',
{
url: "http://www.abc.com:90/apath/",
base: undefined,
error: false,
href: 'http://www.abc.com:90/apath/',
origin: 'http://www.abc.com:90',
protocol: 'http:',
username: '',
password: '',
host: 'www.abc.com:90',
hostname: 'www.abc.com',
port: '90',
pathname: '/apath/',
search: '',
hash: ''
href: "http://www.abc.com:90/apath/",
origin: "http://www.abc.com:90",
protocol: "http:",
username: "",
password: "",
host: "www.abc.com:90",
hostname: "www.abc.com",
port: "90",
pathname: "/apath/",
search: "",
hash: "",
},
{ url: 'http://www.abc.com/apath/afile.txt#ahash',
{
url: "http://www.abc.com/apath/afile.txt#ahash",
base: undefined,
error: false,
href: 'http://www.abc.com/apath/afile.txt#ahash',
origin: 'http://www.abc.com',
protocol: 'http:',
username: '',
password: '',
host: 'www.abc.com',
hostname: 'www.abc.com',
port: '',
pathname: '/apath/afile.txt',
search: '',
hash: '#ahash'
href: "http://www.abc.com/apath/afile.txt#ahash",
origin: "http://www.abc.com",
protocol: "http:",
username: "",
password: "",
host: "www.abc.com",
hostname: "www.abc.com",
port: "",
pathname: "/apath/afile.txt",
search: "",
hash: "#ahash",
},
{ url: 'http://example.com/?test#hash',
{
url: "http://example.com/?test#hash",
base: undefined,
error: false,
href: 'http://example.com/?test#hash',
origin: 'http://example.com',
protocol: 'http:',
username: '',
password: '',
host: 'example.com',
hostname: 'example.com',
port: '',
pathname: '/',
search: '?test',
hash: '#hash'
href: "http://example.com/?test#hash",
origin: "http://example.com",
protocol: "http:",
username: "",
password: "",
host: "example.com",
hostname: "example.com",
port: "",
pathname: "/",
search: "?test",
hash: "#hash",
},
{ url: 'http://example.com/?test',
{
url: "http://example.com/?test",
base: undefined,
error: false,
href: 'http://example.com/?test',
origin: 'http://example.com',
protocol: 'http:',
username: '',
password: '',
host: 'example.com',
hostname: 'example.com',
port: '',
pathname: '/',
search: '?test',
hash: ''
href: "http://example.com/?test",
origin: "http://example.com",
protocol: "http:",
username: "",
password: "",
host: "example.com",
hostname: "example.com",
port: "",
pathname: "/",
search: "?test",
hash: "",
},
{ url: 'http://example.com/carrot#question%3f',
{
url: "http://example.com/carrot#question%3f",
base: undefined,
error: false,
hash: '#question%3f'
hash: "#question%3f",
},
{ url: 'https://example.com:4443?',
{
url: "https://example.com:4443?",
base: undefined,
error: false,
protocol: 'https:',
port: '4443',
pathname: '/',
hash: '',
search: ''
protocol: "https:",
port: "4443",
pathname: "/",
hash: "",
search: "",
},
{ url: 'http://www.abc.com/apath/afile.txt#ahash?asearch',
{
url: "http://www.abc.com/apath/afile.txt#ahash?asearch",
base: undefined,
error: false,
href: 'http://www.abc.com/apath/afile.txt#ahash?asearch',
protocol: 'http:',
pathname: '/apath/afile.txt',
hash: '#ahash?asearch',
search: ''
href: "http://www.abc.com/apath/afile.txt#ahash?asearch",
protocol: "http:",
pathname: "/apath/afile.txt",
hash: "#ahash?asearch",
search: "",
},
{ url: 'http://www.abc.com/apath/afile.txt?asearch#ahash',
{
url: "http://www.abc.com/apath/afile.txt?asearch#ahash",
base: undefined,
error: false,
href: 'http://www.abc.com/apath/afile.txt?asearch#ahash',
protocol: 'http:',
pathname: '/apath/afile.txt',
hash: '#ahash',
search: '?asearch'
href: "http://www.abc.com/apath/afile.txt?asearch#ahash",
protocol: "http:",
pathname: "/apath/afile.txt",
hash: "#ahash",
search: "?asearch",
},
{ url: 'http://abc.com/apath/afile.txt?#ahash',
{
url: "http://abc.com/apath/afile.txt?#ahash",
base: undefined,
error: false,
pathname: '/apath/afile.txt',
hash: '#ahash',
search: ''
pathname: "/apath/afile.txt",
hash: "#ahash",
search: "",
},
{ url: 'http://auser:apassword@www.abc.com:90/apath/afile.txt?asearch#ahash',
{
url: "http://auser:apassword@www.abc.com:90/apath/afile.txt?asearch#ahash",
base: undefined,
error: false,
protocol: 'http:',
username: 'auser',
password: 'apassword',
host: 'www.abc.com:90',
hostname: 'www.abc.com',
port: '90',
pathname: '/apath/afile.txt',
hash: '#ahash',
search: '?asearch',
origin: 'http://www.abc.com:90'
protocol: "http:",
username: "auser",
password: "apassword",
host: "www.abc.com:90",
hostname: "www.abc.com",
port: "90",
pathname: "/apath/afile.txt",
hash: "#ahash",
search: "?asearch",
origin: "http://www.abc.com:90",
},
{ url: '/foo#bar',
base: 'www.test.org',
error: true,
},
{ url: '/foo#bar',
base: null,
error: true,
},
{ url: '/foo#bar',
base: 42,
error: true,
},
{ url: 'ftp://ftp.something.net',
{ url: "/foo#bar", base: "www.test.org", error: true },
{ url: "/foo#bar", base: null, error: true },
{ url: "/foo#bar", base: 42, error: true },
{
url: "ftp://ftp.something.net",
base: undefined,
error: false,
protocol: 'ftp:',
protocol: "ftp:",
},
{ url: 'file:///tmp/file',
{
url: "file:///tmp/file",
base: undefined,
error: false,
protocol: 'file:',
protocol: "file:",
},
{ url: 'gopher://gopher.something.net',
{
url: "gopher://gopher.something.net",
base: undefined,
error: false,
protocol: 'gopher:',
protocol: "gopher:",
},
{ url: 'ws://ws.something.net',
{
url: "ws://ws.something.net",
base: undefined,
error: false,
protocol: 'ws:',
protocol: "ws:",
},
{ url: 'wss://ws.something.net',
{
url: "wss://ws.something.net",
base: undefined,
error: false,
protocol: 'wss:',
protocol: "wss:",
},
{ url: 'foo://foo.something.net',
{
url: "foo://foo.something.net",
base: undefined,
error: false,
protocol: 'foo:',
protocol: "foo:",
},
];
while(tests.length) {
while (tests.length) {
var test = tests.shift();
var error = false;
@@ -217,7 +229,7 @@ onmessage = function() {
} else {
url = new URL(test.url);
}
} catch(e) {
} catch (e) {
error = true;
}
@@ -226,47 +238,79 @@ onmessage = function() {
continue;
}
if ('href' in test) is(url.href, test.href, "href");
if ('origin' in test) is(url.origin, test.origin, "origin");
if ('protocol' in test) is(url.protocol, test.protocol, "protocol");
if ('username' in test) is(url.username, test.username, "username");
if ('password' in test) is(url.password, test.password, "password");
if ('host' in test) is(url.host, test.host, "host");
if ('hostname' in test) is(url.hostname, test.hostname, "hostname");
if ('port' in test) is(url.port, test.port, "port");
if ('pathname' in test) is(url.pathname, test.pathname, "pathname");
if ('search' in test) is(url.search, test.search, "search");
if ('hash' in test) is(url.hash, test.hash, "hash");
if ("href" in test) is(url.href, test.href, "href");
if ("origin" in test) is(url.origin, test.origin, "origin");
if ("protocol" in test) is(url.protocol, test.protocol, "protocol");
if ("username" in test) is(url.username, test.username, "username");
if ("password" in test) is(url.password, test.password, "password");
if ("host" in test) is(url.host, test.host, "host");
if ("hostname" in test) is(url.hostname, test.hostname, "hostname");
if ("port" in test) is(url.port, test.port, "port");
if ("pathname" in test) is(url.pathname, test.pathname, "pathname");
if ("search" in test) is(url.search, test.search, "search");
if ("hash" in test) is(url.hash, test.hash, "hash");
url = new URL('https://www.example.net/what#foo?bar');
url = new URL("https://www.example.net/what#foo?bar");
ok(url, "Url exists!");
if ('href' in test) url.href = test.href;
if ('protocol' in test) url.protocol = test.protocol;
if ('username' in test && test.username) url.username = test.username;
if ('password' in test && test.password) url.password = test.password;
if ('host' in test) url.host = test.host;
if ('hostname' in test) url.hostname = test.hostname;
if ('port' in test) url.port = test.port;
if ('pathname' in test) url.pathname = test.pathname;
if ('search' in test) url.search = test.search;
if ('hash' in test) url.hash = test.hash;
if ("href" in test) url.href = test.href;
if ("protocol" in test) url.protocol = test.protocol;
if ("username" in test && test.username) url.username = test.username;
if ("password" in test && test.password) url.password = test.password;
if ("host" in test) url.host = test.host;
if ("hostname" in test) url.hostname = test.hostname;
if ("port" in test) url.port = test.port;
if ("pathname" in test) url.pathname = test.pathname;
if ("search" in test) url.search = test.search;
if ("hash" in test) url.hash = test.hash;
if ('href' in test) is(url.href, test.href, "href");
if ('origin' in test) is(url.origin, test.origin, "origin");
if ('protocol' in test) is(url.protocol, test.protocol, "protocol");
if ('username' in test) is(url.username, test.username, "username");
if ('password' in test) is(url.password, test.password, "password");
if ('host' in test) is(url.host, test.host, "host");
if ('hostname' in test) is(test.hostname, url.hostname, "hostname");
if ('port' in test) is(test.port, url.port, "port");
if ('pathname' in test) is(test.pathname, url.pathname, "pathname");
if ('search' in test) is(test.search, url.search, "search");
if ('hash' in test) is(test.hash, url.hash, "hash");
if ("href" in test) is(url.href, test.href, "href");
if ("origin" in test) is(url.origin, test.origin, "origin");
if ("protocol" in test) is(url.protocol, test.protocol, "protocol");
if ("username" in test) is(url.username, test.username, "username");
if ("password" in test) is(url.password, test.password, "password");
if ("host" in test) is(url.host, test.host, "host");
if ("hostname" in test) is(test.hostname, url.hostname, "hostname");
if ("port" in test) is(test.port, url.port, "port");
if ("pathname" in test) is(test.pathname, url.pathname, "pathname");
if ("search" in test) is(test.search, url.search, "search");
if ("hash" in test) is(test.hash, url.hash, "hash");
if ('href' in test) is (test.href, url + '', 'stringify works');
if ("href" in test) is(test.href, url + "", "stringify works");
}
postMessage({type: 'finish' });
}
is(
new URL("/static/client/runtime.js", "x:/").href,
"x:/static/client/runtime.js",
"URL constructor accepts root-relative input with x:/ base",
);
ok("canParse" in URL, "URL.canParse exists");
ok(
URL.canParse("/static/client/runtime.js", "x:/"),
"URL.canParse accepts root-relative input with x:/ base",
);
ok(
URL.canParse("/static/client/runtime.js", self.location.href),
"URL.canParse accepts root-relative input with worker location base",
);
ok(
!URL.canParse("/static/client/runtime.js"),
"URL.canParse rejects root-relative input without base",
);
ok(
!URL.canParse("/static/client/runtime.js", "mailto:test@example.com"),
"URL.canParse rejects root-relative input against opaque mailto: base",
);
let mailtoRelativeFailed = false;
try {
new URL("/static/client/runtime.js", "mailto:test@example.com");
} catch (e) {
mailtoRelativeFailed = true;
}
ok(
mailtoRelativeFailed,
"constructor rejects root-relative input against opaque mailto: base",
);
postMessage({ type: "finish" });
};
+9 -2
View File
@@ -10,7 +10,15 @@
* liability, trademark and document use rules apply.
*/
[Pref="dom.webaudio.enabled"]
dictionary AnalyserOptions : AudioNodeOptions {
unsigned long fftSize = 2048;
float maxDecibels = -30;
float minDecibels = -100;
float smoothingTimeConstant = 0.8;
};
[Pref="dom.webaudio.enabled",
Constructor(AudioContext context, optional AnalyserOptions options)]
interface AnalyserNode : AudioNode {
// Real-time frequency-domain data
@@ -38,4 +46,3 @@ interface AnalyserNode : AudioNode {
// Mozilla extension
AnalyserNode implements AudioNodePassThrough;
+8 -2
View File
@@ -10,7 +10,14 @@
* liability, trademark and document use rules apply.
*/
[Pref="dom.webaudio.enabled"]
dictionary AudioBufferOptions {
unsigned long numberOfChannels = 1;
required unsigned long length;
float sampleRate;
};
[Pref="dom.webaudio.enabled",
Constructor(AudioContext context, AudioBufferOptions options)]
interface AudioBuffer {
readonly attribute float sampleRate;
@@ -29,4 +36,3 @@ interface AudioBuffer {
[Throws]
void copyToChannel(Float32Array source, long channelNumber, optional unsigned long startInChannel = 0);
};
+11 -1
View File
@@ -10,7 +10,17 @@
* liability, trademark and document use rules apply.
*/
[Pref="dom.webaudio.enabled"]
dictionary AudioBufferSourceOptions {
AudioBuffer? buffer;
float detune = 0;
boolean loop = false;
double loopEnd = 0;
double loopStart = 0;
float playbackRate = 1;
};
[Pref="dom.webaudio.enabled",
Constructor(AudioContext context, optional AudioBufferSourceOptions options)]
interface AudioBufferSourceNode : AudioNode {
attribute AudioBuffer? buffer;
+6
View File
@@ -21,6 +21,12 @@ enum ChannelInterpretation {
"discrete"
};
dictionary AudioNodeOptions {
unsigned long channelCount;
ChannelCountMode channelCountMode;
ChannelInterpretation channelInterpretation;
};
[Pref="dom.webaudio.enabled"]
interface AudioNode : EventTarget {
+10 -1
View File
@@ -21,7 +21,16 @@ enum BiquadFilterType {
"allpass"
};
[Pref="dom.webaudio.enabled"]
dictionary BiquadFilterOptions : AudioNodeOptions {
BiquadFilterType type = "lowpass";
float Q = 1;
float detune = 0;
float frequency = 350;
float gain = 0;
};
[Pref="dom.webaudio.enabled",
Constructor(AudioContext context, optional BiquadFilterOptions options)]
interface BiquadFilterNode : AudioNode {
attribute BiquadFilterType type;
+6 -3
View File
@@ -10,8 +10,11 @@
* liability, trademark and document use rules apply.
*/
[Pref="dom.webaudio.enabled"]
interface ChannelMergerNode : AudioNode {
dictionary ChannelMergerOptions : AudioNodeOptions {
unsigned long numberOfInputs = 6;
};
[Pref="dom.webaudio.enabled",
Constructor(AudioContext context, optional ChannelMergerOptions options)]
interface ChannelMergerNode : AudioNode {
};
+6 -1
View File
@@ -10,7 +10,12 @@
* liability, trademark and document use rules apply.
*/
[Pref="dom.webaudio.enabled"]
dictionary ChannelSplitterOptions : AudioNodeOptions {
unsigned long numberOfOutputs = 6;
};
[Pref="dom.webaudio.enabled",
Constructor(AudioContext context, optional ChannelSplitterOptions options)]
interface ChannelSplitterNode : AudioNode {
};
+7 -1
View File
@@ -10,7 +10,13 @@
* liability, trademark and document use rules apply.
*/
[Pref="dom.webaudio.enabled"]
dictionary ConvolverOptions : AudioNodeOptions {
AudioBuffer? buffer;
boolean disableNormalization = false;
};
[Pref="dom.webaudio.enabled",
Constructor(AudioContext context, optional ConvolverOptions options)]
interface ConvolverNode : AudioNode {
[SetterThrows]
+7 -1
View File
@@ -10,7 +10,13 @@
* liability, trademark and document use rules apply.
*/
[Pref="dom.webaudio.enabled"]
dictionary DelayOptions : AudioNodeOptions {
double maxDelayTime = 1;
double delayTime = 0;
};
[Pref="dom.webaudio.enabled",
Constructor(AudioContext context, optional DelayOptions options)]
interface DelayNode : AudioNode {
readonly attribute AudioParam delayTime;
+10 -1
View File
@@ -10,7 +10,16 @@
* liability, trademark and document use rules apply.
*/
[Pref="dom.webaudio.enabled"]
dictionary DynamicsCompressorOptions : AudioNodeOptions {
float attack = 0.003;
float knee = 30;
float ratio = 12;
float release = 0.25;
float threshold = -24;
};
[Pref="dom.webaudio.enabled",
Constructor(AudioContext context, optional DynamicsCompressorOptions options)]
interface DynamicsCompressorNode : AudioNode {
readonly attribute AudioParam threshold; // in Decibels
+6 -1
View File
@@ -10,7 +10,12 @@
* liability, trademark and document use rules apply.
*/
[Pref="dom.webaudio.enabled"]
dictionary GainOptions : AudioNodeOptions {
float gain = 1.0;
};
[Pref="dom.webaudio.enabled",
Constructor(AudioContext context, optional GainOptions options)]
interface GainNode : AudioNode {
readonly attribute AudioParam gain;
+7 -1
View File
@@ -9,7 +9,13 @@
* liability, trademark and document use rules apply.
*/
[Pref="dom.webaudio.enabled"]
dictionary IIRFilterOptions : AudioNodeOptions {
required sequence<double> feedforward;
required sequence<double> feedback;
};
[Pref="dom.webaudio.enabled",
Constructor(AudioContext context, IIRFilterOptions options)]
interface IIRFilterNode : AudioNode {
void getFrequencyResponse(Float32Array frequencyHz, Float32Array magResponse, Float32Array phaseResponse);
};
@@ -10,7 +10,12 @@
* liability, trademark and document use rules apply.
*/
[Pref="dom.webaudio.enabled"]
dictionary MediaElementAudioSourceOptions {
required HTMLMediaElement mediaElement;
};
[Pref="dom.webaudio.enabled",
Constructor(AudioContext context, MediaElementAudioSourceOptions options)]
interface MediaElementAudioSourceNode : AudioNode {
};
@@ -10,9 +10,8 @@
* liability, trademark and document use rules apply.
*/
[Pref="dom.webaudio.enabled"]
[Pref="dom.webaudio.enabled",
Constructor(AudioContext context, optional AudioNodeOptions options)]
interface MediaStreamAudioDestinationNode : AudioNode {
readonly attribute MediaStream stream;
};
+6 -1
View File
@@ -10,7 +10,12 @@
* liability, trademark and document use rules apply.
*/
[Pref="dom.webaudio.enabled"]
dictionary MediaStreamAudioSourceOptions {
required MediaStream mediaStream;
};
[Pref="dom.webaudio.enabled",
Constructor(AudioContext context, MediaStreamAudioSourceOptions options)]
interface MediaStreamAudioSourceNode : AudioNode {
};
+9 -2
View File
@@ -18,7 +18,15 @@ enum OscillatorType {
"custom"
};
[Pref="dom.webaudio.enabled"]
dictionary OscillatorOptions : AudioNodeOptions {
OscillatorType type = "sine";
float frequency = 440;
float detune = 0;
PeriodicWave periodicWave;
};
[Pref="dom.webaudio.enabled",
Constructor(AudioContext context, optional OscillatorOptions options)]
interface OscillatorNode : AudioNode {
[SetterThrows]
@@ -39,4 +47,3 @@ interface OscillatorNode : AudioNode {
// Mozilla extensions
OscillatorNode implements AudioNodePassThrough;
+19 -1
View File
@@ -21,7 +21,25 @@ enum DistanceModelType {
"exponential"
};
[Pref="dom.webaudio.enabled"]
dictionary PannerOptions : AudioNodeOptions {
PanningModelType panningModel = "equalpower";
DistanceModelType distanceModel = "inverse";
float positionX = 0;
float positionY = 0;
float positionZ = 0;
float orientationX = 1;
float orientationY = 0;
float orientationZ = 0;
double refDistance = 1;
double maxDistance = 10000;
double rolloffFactor = 1;
double coneInnerAngle = 360;
double coneOuterAngle = 360;
double coneOuterGain = 0;
};
[Pref="dom.webaudio.enabled",
Constructor(AudioContext context, optional PannerOptions options)]
interface PannerNode : AudioNode {
// Default for stereo is equalpower
+7 -3
View File
@@ -10,8 +10,12 @@
* liability, trademark and document use rules apply.
*/
[Pref="dom.webaudio.enabled"]
interface PeriodicWave {
dictionary PeriodicWaveOptions : PeriodicWaveConstraints {
sequence<float> real;
sequence<float> imag;
};
[Pref="dom.webaudio.enabled",
Constructor(AudioContext context, PeriodicWaveOptions options)]
interface PeriodicWave {
};
+6 -1
View File
@@ -10,7 +10,12 @@
* liability, trademark and document use rules apply.
*/
[Pref="dom.webaudio.enabled"]
dictionary StereoPannerOptions : AudioNodeOptions {
float pan = 0;
};
[Pref="dom.webaudio.enabled",
Constructor(AudioContext context, optional StereoPannerOptions options)]
interface StereoPannerNode : AudioNode {
readonly attribute AudioParam pan;
};
+8 -2
View File
@@ -16,10 +16,16 @@ enum OverSampleType {
"4x"
};
[Pref="dom.webaudio.enabled"]
dictionary WaveShaperOptions : AudioNodeOptions {
sequence<float> curve;
OverSampleType oversample = "none";
};
[Pref="dom.webaudio.enabled",
Constructor(AudioContext context, optional WaveShaperOptions options)]
interface WaveShaperNode : AudioNode {
[SetterThrows]
[Cached, Pure, SetterThrows]
attribute Float32Array? curve;
attribute OverSampleType oversample;
+1
View File
@@ -142,6 +142,7 @@ EditorBase::EditorBase()
, mDispatchInputEvent(true)
, mIsInEditAction(false)
, mHidingCaret(false)
, mIsHTMLEditorClass(false)
{
}
+20
View File
@@ -114,6 +114,7 @@ class DeleteNodeTransaction;
class DeleteTextTransaction;
class EditAggregateTransaction;
class ErrorResult;
class HTMLEditor;
class InsertNodeTransaction;
class InsertTextTransaction;
class JoinNodeTransaction;
@@ -121,6 +122,7 @@ class PlaceholderTransaction;
class RemoveStyleSheetTransaction;
class SplitNodeTransaction;
class TextComposition;
class TextEditor;
struct EditorDOMPoint;
namespace dom {
@@ -1113,14 +1115,32 @@ protected:
bool mIsInEditAction;
// Whether caret is hidden forcibly.
bool mHidingCaret;
// Whether we are an HTML editor class.
bool mIsHTMLEditorClass;
friend bool NSCanUnload(nsISupports* serviceMgr);
friend class AutoRules;
friend class AutoSelectionRestorer;
friend class AutoTransactionsConserveSelection;
friend class RangeUpdater;
friend class nsIEditor;
};
} // namespace mozilla
// nsIEditor helper functions.
// Here because of code context.
mozilla::EditorBase*
nsIEditor::AsEditorBase()
{
return static_cast<mozilla::EditorBase*>(this);
}
const mozilla::EditorBase*
nsIEditor::AsEditorBase() const
{
return static_cast<const mozilla::EditorBase*>(this);
}
#endif // #ifndef mozilla_EditorBase_h
+8 -1
View File
@@ -233,9 +233,16 @@ NS_IMPL_CYCLE_COLLECTION_INHERITED(HTMLEditRules, TextEditRules,
NS_IMETHODIMP
HTMLEditRules::Init(TextEditor* aTextEditor)
{
if (NS_WARN_IF(!aTextEditor)) {
return NS_ERROR_INVALID_ARG;
}
InitFields();
mHTMLEditor = static_cast<HTMLEditor*>(aTextEditor);
mHTMLEditor = aTextEditor->AsHTMLEditor();
if (NS_WARN_IF(!mHTMLEditor)) {
return NS_ERROR_INVALID_ARG;
}
// call through to base class Init
nsresult rv = TextEditRules::Init(aTextEditor);
+2 -1
View File
@@ -132,6 +132,7 @@ HTMLEditor::HTMLEditor()
, mPositionedObjectBorderTop(0)
, mGridSize(0)
{
mIsHTMLEditorClass = true;
}
HTMLEditor::~HTMLEditor()
@@ -501,7 +502,7 @@ HTMLEditor::InitRules()
// instantiate the rules for the html editor
mRules = new HTMLEditRules();
}
return mRules->Init(static_cast<TextEditor*>(this));
return mRules->Init(this);
}
NS_IMETHODIMP
+16
View File
@@ -1108,4 +1108,20 @@ private:
} // namespace mozilla
// nsIEditor helper functions.
// Here because of code context.
mozilla::HTMLEditor*
nsIEditor::AsHTMLEditor()
{
return static_cast<mozilla::EditorBase*>(this)->mIsHTMLEditorClass ?
static_cast<mozilla::HTMLEditor*>(this) : nullptr;
}
const mozilla::HTMLEditor*
nsIEditor::AsHTMLEditor() const
{
return static_cast<const mozilla::EditorBase*>(this)->mIsHTMLEditorClass ?
static_cast<const mozilla::HTMLEditor*>(this) : nullptr;
}
#endif // #ifndef mozilla_HTMLEditor_h
+21 -18
View File
@@ -30,24 +30,18 @@ namespace mozilla {
using namespace dom;
#ifdef DEBUG
nsresult
HTMLEditorEventListener::Connect(EditorBase* aEditorBase)
{
nsCOMPtr<nsIHTMLEditor> htmlEditor = do_QueryObject(aEditorBase);
nsCOMPtr<nsIHTMLInlineTableEditor> htmlInlineTableEditor =
do_QueryObject(aEditorBase);
NS_PRECONDITION(htmlEditor && htmlInlineTableEditor,
"Set HTMLEditor or its sub class");
return EditorEventListener::Connect(aEditorBase);
}
#endif
HTMLEditor*
HTMLEditorEventListener::GetHTMLEditor()
{
// mEditor must be HTMLEditor or its subclass.
return static_cast<HTMLEditor*>(mEditorBase);
if (NS_WARN_IF(!aEditorBase)) {
return NS_ERROR_INVALID_ARG;
}
// Guarantee that mEditorBase is always HTMLEditor.
HTMLEditor* htmlEditor = aEditorBase->AsHTMLEditor();
if (NS_WARN_IF(!htmlEditor)) {
return NS_ERROR_INVALID_ARG;
}
return EditorEventListener::Connect(htmlEditor);
}
nsresult
@@ -59,7 +53,8 @@ HTMLEditorEventListener::MouseUp(nsIDOMMouseEvent* aMouseEvent)
// FYI: We need to notify HTML editor of mouseup even if it's consumed
// because HTML editor always needs to release grabbing resizer.
HTMLEditor* htmlEditor = GetHTMLEditor();
HTMLEditor* htmlEditor = mEditorBase->AsHTMLEditor();
MOZ_ASSERT(htmlEditor);
nsCOMPtr<nsIDOMEventTarget> target;
nsresult rv = aMouseEvent->AsEvent()->GetTarget(getter_AddRefs(target));
@@ -85,7 +80,9 @@ HTMLEditorEventListener::MouseDown(nsIDOMMouseEvent* aMouseEvent)
WidgetMouseEvent* mousedownEvent =
aMouseEvent->AsEvent()->WidgetEventPtr()->AsMouseEvent();
HTMLEditor* htmlEditor = GetHTMLEditor();
HTMLEditor* htmlEditor = mEditorBase->AsHTMLEditor();
MOZ_ASSERT(htmlEditor);
// Contenteditable should disregard mousedowns outside it.
// IsAcceptableInputEvent() checks it for a mouse event.
if (!htmlEditor->IsAcceptableInputEvent(mousedownEvent)) {
@@ -221,13 +218,19 @@ HTMLEditorEventListener::MouseDown(nsIDOMMouseEvent* aMouseEvent)
nsresult
HTMLEditorEventListener::MouseClick(nsIDOMMouseEvent* aMouseEvent)
{
if (NS_WARN_IF(DetachedFromEditor())) {
return NS_OK;
}
nsCOMPtr<nsIDOMEventTarget> target;
nsresult rv = aMouseEvent->AsEvent()->GetTarget(getter_AddRefs(target));
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(target, NS_ERROR_NULL_POINTER);
nsCOMPtr<nsIDOMElement> element = do_QueryInterface(target);
GetHTMLEditor()->DoInlineTableEditingAction(element);
HTMLEditor* htmlEditor = mEditorBase->AsHTMLEditor();
MOZ_ASSERT(htmlEditor);
htmlEditor->DoInlineTableEditingAction(element);
return EditorEventListener::MouseClick(aMouseEvent);
}
+1 -5
View File
@@ -25,17 +25,13 @@ public:
{
}
#ifdef DEBUG
// WARNING: You must be use HTMLEditor or its sub class for this class.
// Connect() fails if aEditorBase isn't an HTMLEditor instance.
virtual nsresult Connect(EditorBase* aEditorBase) override;
#endif
protected:
virtual nsresult MouseDown(nsIDOMMouseEvent* aMouseEvent) override;
virtual nsresult MouseUp(nsIDOMMouseEvent* aMouseEvent) override;
virtual nsresult MouseClick(nsIDOMMouseEvent* aMouseEvent) override;
inline HTMLEditor* GetHTMLEditor();
};
} // namespace mozilla
+1
View File
@@ -10,6 +10,7 @@
#include "gfxFontUtils.h"
#include "mozilla/Assertions.h"
#include "mozilla/EditorUtils.h" // AutoEditBatch, AutoRules
#include "mozilla/HTMLEditor.h"
#include "mozilla/mozalloc.h"
#include "mozilla/Preferences.h"
#include "mozilla/TextEditRules.h"
+14
View File
@@ -247,4 +247,18 @@ protected:
} // namespace mozilla
// nsIEditor helper functions.
// Here because of code context.
mozilla::TextEditor*
nsIEditor::AsTextEditor()
{
return static_cast<mozilla::TextEditor*>(this);
}
const mozilla::TextEditor*
nsIEditor::AsTextEditor() const
{
return static_cast<const mozilla::TextEditor*>(this);
}
#endif // #ifndef mozilla_TextEditor_h
+38
View File
@@ -21,6 +21,14 @@ interface nsIEditActionListener;
interface nsIInlineSpellChecker;
interface nsITransferable;
%{C++
namespace mozilla {
class EditorBase;
class HTMLEditor;
class TextEditor;
} // namespace mozilla
%}
[scriptable, uuid(094be624-f0bf-400f-89e2-6a84baab9474)]
interface nsIEditor : nsISupports
{
@@ -564,4 +572,34 @@ interface nsIEditor : nsISupports
* or nsIEditorObserver::CancelEditAction(). Otherwise, false.
*/
[noscript] readonly attribute boolean isInEditAction;
%{C++
/**
* AsEditorBase() returns a pointer to EditorBase class.
*
* In order to avoid circular dependency issues, this method is defined
* in mozilla/EditorBase.h. Consumers need to #include that header.
*/
inline mozilla::EditorBase* AsEditorBase();
inline const mozilla::EditorBase* AsEditorBase() const;
/**
* AsTextEditor() returns a pointer to TextEditor class.
*
* In order to avoid circular dependency issues, this method is defined
* in mozilla/TextEditor.h. Consumers need to #include that header.
*/
inline mozilla::TextEditor* AsTextEditor();
inline const mozilla::TextEditor* AsTextEditor() const;
/**
* AsHTMLEditor() returns a pointer to HTMLEditor class.
*
* In order to avoid circular dependency issues, this method is defined
* in mozilla/HTMLEditor.h. Consumers need to #include that header.
*/
inline mozilla::HTMLEditor* AsHTMLEditor();
inline const mozilla::HTMLEditor* AsHTMLEditor() const;
%}
};
@@ -97,9 +97,6 @@ using namespace mozilla::dom;
#define INLINESPELL_STARTED_TOPIC "inlineSpellChecker-spellCheck-started"
#define INLINESPELL_ENDED_TOPIC "inlineSpellChecker-spellCheck-ended"
static bool ContentIsDescendantOf(nsINode* aPossibleDescendant,
nsINode* aPossibleAncestor);
static const char kMaxSpellCheckSelectionSize[] = "extensions.spellcheck.inline.max-misspellings";
mozInlineSpellStatus::mozInlineSpellStatus(mozInlineSpellChecker* aSpellChecker)
@@ -238,7 +235,7 @@ mozInlineSpellStatus::InitForNavigation(
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsINode> currentAnchor = do_QueryInterface(aOldAnchorNode, &rv);
NS_ENSURE_SUCCESS(rv, rv);
if (root && currentAnchor && ! ContentIsDescendantOf(currentAnchor, root)) {
if (root && currentAnchor && !nsContentUtils::ContentIsShadowIncludingDescendantOf(currentAnchor, root)) {
*aContinue = false;
return NS_OK;
}
@@ -1490,8 +1487,11 @@ nsresult mozInlineSpellChecker::DoSpellCheck(mozInlineSpellWordUtil& aWordUtil,
return NS_OK;
}
aWordUtil.SetEnd(endNode, endOffset);
aWordUtil.SetPosition(beginNode, beginOffset);
nsresult rv = aWordUtil.SetPositionAndEnd(beginNode, beginOffset, endNode, endOffset);
if (NS_FAILED(rv)) {
// Just bail out and don't try to spell-check this
return NS_OK;
}
}
// aWordUtil.SetPosition flushes pending notifications, check editor again.
@@ -1840,24 +1840,6 @@ nsresult mozInlineSpellChecker::SaveCurrentSelectionPosition()
return NS_OK;
}
// This is a copy of nsContentUtils::ContentIsDescendantOf. Another crime
// for XPCOM's rap sheet
bool // static
ContentIsDescendantOf(nsINode* aPossibleDescendant,
nsINode* aPossibleAncestor)
{
NS_PRECONDITION(aPossibleDescendant, "The possible descendant is null!");
NS_PRECONDITION(aPossibleAncestor, "The possible ancestor is null!");
do {
if (aPossibleDescendant == aPossibleAncestor)
return true;
aPossibleDescendant = aPossibleDescendant->GetParentNode();
} while (aPossibleDescendant);
return false;
}
// mozInlineSpellChecker::HandleNavigationEvent
//
// Acts upon mouse clicks and keyboard navigation changes, spell checking
@@ -23,6 +23,8 @@
#include "nsIFrame.h"
#include <algorithm>
#include "mozilla/BinarySearch.h"
#include "mozilla/HTMLEditor.h"
#include "mozilla/dom/ShadowRoot.h"
using namespace mozilla;
@@ -69,8 +71,10 @@ mozInlineSpellWordUtil::Init(nsWeakPtr aWeakEditor)
mDOMDocument = domDoc;
mDocument = do_QueryInterface(domDoc);
// Find the root node for the editor. For contenteditable we'll need something
// cleverer here.
mIsContentEditableOrDesignMode = !!editor->AsHTMLEditor();
// Find the root node for the editor. For contenteditable the mRootNode could
// change to shadow root if the begin and end are inside the shadowDOM.
nsCOMPtr<nsIDOMElement> rootElt;
rv = editor->GetRootElement(getter_AddRefs(rootElt));
NS_ENSURE_SUCCESS(rv, rv);
@@ -154,7 +158,7 @@ FindNextTextNode(nsINode* aNode, int32_t aOffset, nsINode* aRoot)
return checkNode;
}
// mozInlineSpellWordUtil::SetEnd
// mozInlineSpellWordUtil::SetPositionAndEnd
//
// We have two ranges "hard" and "soft". The hard boundary is simply
// the scope of the root node. The soft boundary is that which is set
@@ -172,34 +176,44 @@ FindNextTextNode(nsINode* aNode, int32_t aOffset, nsINode* aRoot)
// position.
nsresult
mozInlineSpellWordUtil::SetEnd(nsINode* aEndNode, int32_t aEndOffset)
mozInlineSpellWordUtil::SetPositionAndEnd(nsINode* aPositionNode,
int32_t aPositionOffset,
nsINode* aEndNode,
int32_t aEndOffset)
{
MOZ_ASSERT(aPositionNode, "Null begin node?");
NS_PRECONDITION(aEndNode, "Null end node?");
NS_ASSERTION(mRootNode, "Not initialized");
// Find a appropriate root if we are dealing with contenteditable nodes which
// are in the shadow DOM. See UXP Issue #3011
if (mIsContentEditableOrDesignMode) {
nsINode* rootNode = aPositionNode->SubtreeRoot();
if (rootNode != aEndNode->SubtreeRoot()) {
return NS_ERROR_FAILURE;
}
if (mozilla::dom::ShadowRoot::FromNode(rootNode)) {
mRootNode = rootNode;
}
}
InvalidateWords();
if (!IsTextNode(aPositionNode)) {
// Start at the start of the first text node after aNode/aOffset.
aPositionNode = FindNextTextNode(aPositionNode, aPositionOffset, mRootNode);
aPositionOffset = 0;
}
mSoftBegin = NodeOffset(aPositionNode, aPositionOffset);
if (!IsTextNode(aEndNode)) {
// End at the start of the first text node after aEndNode/aEndOffset.
aEndNode = FindNextTextNode(aEndNode, aEndOffset, mRootNode);
aEndOffset = 0;
}
mSoftEnd = NodeOffset(aEndNode, aEndOffset);
return NS_OK;
}
nsresult
mozInlineSpellWordUtil::SetPosition(nsINode* aNode, int32_t aOffset)
{
InvalidateWords();
if (!IsTextNode(aNode)) {
// Start at the start of the first text node after aNode/aOffset.
aNode = FindNextTextNode(aNode, aOffset, mRootNode);
aOffset = 0;
}
mSoftBegin = NodeOffset(aNode, aOffset);
nsresult rv = EnsureWords();
if (NS_FAILED(rv)) {
@@ -207,8 +221,10 @@ mozInlineSpellWordUtil::SetPosition(nsINode* aNode, int32_t aOffset)
}
int32_t textOffset = MapDOMPositionToSoftTextOffset(mSoftBegin);
if (textOffset < 0)
if (textOffset < 0) {
return NS_OK;
}
mNextWordIndex = FindRealWordContaining(textOffset, HINT_END, true);
return NS_OK;
}
@@ -29,12 +29,11 @@ class nsINode;
* The basic operation is:
*
* 1. Call Init with the weak pointer to the editor that you're using.
* 2. Call SetEnd to set where you want to stop spellchecking. We'll stop
* at the word boundary after that. If SetEnd is not called, we'll stop
* at the end of the document's root element.
* 3. Call SetPosition to initialize the current position inside the
* previously given range.
* 4. Call GetNextWord over and over until it returns false.
* 2. Call SetPositionAndEnd to to initialize the current position inside the
* previously given range and set where you want to stop spellchecking.
* We'll stop at the word boundary after that. If SetEnd is not called,
* we'll stop at the end of the root element.
* 3. Call GetNextWord over and over until it returns false.
*/
class mozInlineSpellWordUtil
@@ -57,17 +56,22 @@ public:
};
mozInlineSpellWordUtil()
: mRootNode(nullptr),
mSoftBegin(nullptr, 0), mSoftEnd(nullptr, 0),
mNextWordIndex(-1), mSoftTextValid(false) {}
: mIsContentEditableOrDesignMode(false)
, mRootNode(nullptr)
, mSoftBegin(nullptr, 0)
, mSoftEnd(nullptr, 0)
, mNextWordIndex(-1)
, mSoftTextValid(false)
{}
nsresult Init(nsWeakPtr aWeakEditor);
nsresult SetEnd(nsINode* aEndNode, int32_t aEndOffset);
// sets the current position, this should be inside the range. If we are in
// the middle of a word, we'll move to its start.
nsresult SetPosition(nsINode* aNode, int32_t aOffset);
// Sets the current position and end. This should be inside the range.
// If we are in the middle of a word, we'll move to its start.
nsresult SetPositionAndEnd(nsINode* aPositionNode,
int32_t aPositionOffset,
nsINode* aEndNode,
int32_t aEndOffset);
// Given a point inside or immediately following a word, this returns the
// DOM range that exactly encloses that word's characters. The current
@@ -100,7 +104,8 @@ private:
// cached stuff for the editor, set by Init
nsCOMPtr<nsIDOMDocument> mDOMDocument;
nsCOMPtr<nsIDocument> mDocument;
nsCOMPtr<nsIDocument> mDocument;
bool mIsContentEditableOrDesignMode;
// range to check, see SetPosition and SetEnd
nsINode* mRootNode;
@@ -220,7 +220,8 @@ bool MacroExpander::expandMacro(const Macro &macro,
assert(macro.type == Macro::kTypeFunc);
std::vector<MacroArg> args;
args.reserve(macro.parameters.size());
if (!collectMacroArgs(macro, identifier, &args, &replacementLocation))
if (replacements->size() == 0 ||
!collectMacroArgs(macro, identifier, &args, &replacementLocation))
return false;
replaceMacroParams(macro, args, replacements);
Loaded 100 of 192 files, more files were not shown because too many files have changed in this diff. Show more