import changes from `dev' branch of rmottola/Arctic-Fox:

- Bug 1251253 - prevent null pointer dereference of |aContext| in CacheStorageService::DoomStorageEntries. r=mayhemer (35b449c612)
- Bug 1260498 - Make test_rel_preconnect work in e10s mode. r=mcmanus (e6823ce4c4)
- Bug 1016628 - Add prefetch abilities to the predictor. r=mayhemer (53ab180c97)
- Bug 1258482 - FileList should contain only Files, not Directories, r=smaug (ff78125454)
- Bug 1258694 - Implement Directory::GetFiles(), r=smaug (305784524e)
- Bug 1263992 - patch 1 - Remove DirectoryType enum, r=smaug (89e1a59041)
- Bug 1263992 - patch 2 - Support the creation of directories from FileSystemTasks, r=smaug (c569092cef)
- Bug 1243586 - Implement Upgrade-Insecure-Requests HTTP Request Header Field. r=rbarnes (4b8a84c656)
- Bug 1262572 - http 0.9 telemetry. r=hurley (6006881336)
- Bug 587177 - Update all comments before SetOriginalURI to reflect reality, r=mcmanus (b2fedb0728)
- Bug 1261632 - Assert that OnStopRequest is called only once. r=michal (c35b1922b9)
- Bug 1232422 - Convert 5 tests within netwerk/test to use AsyncOpen2 (r=mcmanus) (4af8d43814)
- Bug 831450 - No Range Requests against weak Etag r=mayhemer (9b4a159e1e)
- Bug 1214277 - Avoid bypassing opening a cache entry for possibly intercepted channels; r=mcmanus (c5b0de6990)
- partial apply Bug 1234369 - Convert 25 tests within netwerk/test to use AsyncOpen2 (1b81d5a303)
- Bug 299031 - heuristic cache rule for 410 should be longer r=mayhemer (848834fc31)
- Bug 1121447 - trust cache less for error codes r=mayhemer (0424fec819)
- Bug 1125916 - Check whether loadInfo and loadContext match. r=sicking, r=jduell (6740850922)
- Bug 1258778 - Purge the skia glyph cache when receiving a low memory notice. r=erahm (633c60b0c6)
- Bug 1125916 - Add SEC_FORCE_PRIVATE_BROWSING to LoadInfo. r=sicking, r=jduell (10b5a1cacb)
- Bug 1105556 - test fixes. r=sicking, ckerschb (845d0dbd65)
- Bug 1258481 - Use RegionBuilder for nsRegion IPC. r=jrmuizel (616c279297)
- Bug 1014691 - Fix an include-what-you-use error in TestCompositor.cpp. r=kats (2797f83f1d)
- Bug 1256408 - Add graphics microbenchmarking. r=mstange (49b11b051b)
- Bug 1258481 - Add a RegionBuilder for accumulating rects. r=jrmuizel (acd79192db)
- Track whether or not remote layers have acknowledged compositor changes. (bug 1256517 part 1, r=mattwoodrow) (e3cc77ed41)
- Move compositable field out of individual compositable ops. (bug 1256517 part 2, r=mattwoodrow) (1d4a063df3)
- Bug 1241058: Assure several operations properly operate on the current group target. r=jrmuizel (6119e2b4db)
- Bug 1247700: Avoid crash from invalid fonts. r=bas (c4c2799b94)
- Bug 1242421 - remove useless null check. r=roc@ocallahan.org (44faf6556d)
- Add instrumentation for when content processes fail to acquire D3D11 devices. (bug 1247539, r=milan) (bd9265d78e)
- Make access to gfxWindowsPlatform D3D11 devices thread-safe. (bug 1258174, r=bas) (032e74b163)
- Disable device access on textures created against stale layers. (bug 1256517 part 3, r=nical) (ffcebbdee6)
- Block compositable updates from stale layers. (bug 1256517 part 4, r=mattwoodrow,nical) (fc83339f2d)
- Fix build bustage for bug 1256517 r=broken tree (3952871373)
- Bug 1256678 - Replace DrawTargetCairo::FillGlyphs crashes with other crashes - r=bobowen (b7245ba436)
- Bug 1120485. Log CloseHandle error reason during MessageChannel shutdown failure. r=milan (2f81d9c2aa)
- Bug 1242448 - Ensure the tile pool does not hold textures during shutdown. r=edwin (d31c304258)
- Bug 1258851 - Propagate the isScrollbarContainer layer flag to the compositor. r=mattwoodrow (b9906d7557)
- Bug 1260391: Transfer |CompositableOperation| in |AsyncChildMessageData|, r=dvander (1def34c5f8)
- Bug 1252324 - add DrawTarget API for 3D transforms for use in layers. r=jrmuizel (bc80529422)
- Bug 1255342 - implement DrawTargetCairo::LockBits for Cairo Win32 surfaces. r=sotaro (6f5661691b)
- Bug 1263480 - Don't let cairo go into an error state when DrawSurface is called with an empty destination rectangle. r=lsalzman (4300940101)
- Bug 1251241 - return from DrawTargetCairo::FillGlyphs if |aFont| is ullptr. r=roc (bb92f95ccd)
- Bug 1255320 - Create DrawTarget with DIB as similar DrawTarget r=jrmuizel (03f1da030d)
- Bug 1215265 - Put shutting down gfx ipdl protocols for child processes behind a pref. r=sotaro (aa781b37f9)
- Bug 1262898: Keep the GeckoChildProcessHost alive for the lifetime of the CompositorBridge and ImageBridge parent actors. r=jimm r=nical (dcca3b54e1)
- Bug 1251619: Remove unused gfxPlatform::CreateDrawTargetForUpdateSurface r=mchang (b29565995e)
- Bug 1255973 - Remove redundant overrides from gfxPlatform subclasses. r=jfkthame (d45f8a6640)
- Bug 1259466. Rename layers.offmainthreadcomposition.enabled. r=milan We would rather people not use this pref. (f362da1bd3)
- Bug 881609: Call InitLayersAccelerationPrefs only once. r=nrc (faed10a0d4)
- Bug 1209780. Mark some DrawResult's as unused in layout/svg. r=seth (48192d6b34)
- Bug 1251115 - Fix incorrect rendering result while mask path is not resolvable; r=mstange (a52b478fdf)
- Bug 1228354 - Part1 - Support luminance mask mode. r=mstange r=bas (b03abbe8a6)
- Bug 1228354 - Part2. Add test case for mask-mode. r=heycam (6bea36a70c)
- Bug 1259802: Add type replacement annotations to simplify rust binding generation for nsStyleStruct.h, r=bholley (48c13e62f2)
- Bug 1261754 - Part 1: Improve static assertions for style struct bits. r=dholbert (2ce6d994a5)
- Bug 1261552 - Reimplement default placement-new for style structs. r=heycam (db9d7782e2)
- Bug 1261552 - Introduce StaticPresData and hoist some shared functionality into it. r=heycam (adf2e16b4d)
- Bug 1226627 - Truncate the result in ZoomText/UnZoomText rather than rounding it for better performance. r=roc (f1d1084ba1)
- Bug 1247777 - Part1: parse and compute -webkit-text-fill-color property. r=heycam (fc4161355c)
- Bug 1247777 - Part2: implement -webkit-text-fill-color rendering. r=jfkthame (0f30da9c5b)
- Bug 1247777 - Part3: reftests for -webkit-text-fill-color. r=jfkthame Add this test into web-platform-tests. (02e41db8cc)
- Bug 1043461 - Followup to ensure we still test custom property position when the UA style sheet doesn't have custom properties in it. r=dholbert (48df73d684)
- Bug 1247777 - Part4.1: replace windows-style line endings with unix-style line endings. r=bz (be8ba60960)
- Bug 1247777 - Part4.2: add compatible webkit prefixed properties in CSS properties ordering check test. r=bz (7b78825e14)
- Bug 1261552 - Introduce StyleStructContext, and make all style struct constructors take it. r=heycam (65b3966841)
- Bug 1258017 - Use an nsCOMPtr to hold onto the nsIStyleRule. r=dbaron (e88d7e368f)
- Bug 1258017 - Use a RefPtr to hold onto the parent style context. r=dbaron (6a7289ca43)
- Bug 1258017 - Redesign and simplify rule tree GC. r=dbaron (3bf60a9b04)
- Bug 1253149 - Remove the #ifdef __cplusplus bits from ServoBindings.h. r=SimonSapin (bf2b18a470)
- Bug 1251496 - Forward stylesheet management to RawServoStyleSet. r=heycam (0a3aa90b2d)
- Bug 1260310 - Generalize nsStyleContext to support resolving styles from either nsRuleNode or ServoComputedValues. r=heycam (82b6d5d008)
- Bug 1258017 - Cleanup fixes for trunk. r=me (674a65815a)
- Bug 1236400 part 1: Add internal enum values to represent "display: -webkit-box" & "display: -webkit-inline-box". r=mats (509c94da15)
- Bug 1236400 part 2: Extend NeedsAnonFlexOrGridItem() & related code to wrap all inline-level -webkit-box children in an anonymous flex item. r=mats (dc11b9b09f)
- Bug 1236400 part 3: If webkit prefix support is enabled, skip CSS Parser code that converts "display: -webkit-box" directly to "display: flex". r=mats (e09b459124)
- Bug 1236400 part 4: Add reftests to test how non-block-level content gets wrapped inside a -webkit-box. (no review) (46e4d8cb07)
- Bug 1261754 - Part 2: Make quotes computed values shareable between different structs. r=dholbert (a78e43b706)
- Bug 1261754 - Part 3: Move quotes from nsStyleQuotes to nsStyleList and delete nsStyleQuotes. r=dholbert (fdcd9aaa3f)
- Bug 1209273 - Part 1: Support for adjust-color CSS property. r=dbaron (818a7fe0ff)
- Bug 1209273 - Part 2: Force printing background if color-adjust: exact. r=dbaron (ffd52c0dbc)
- Bug 1261754 - Part 4: Move image-rendering from nsStyleSVG to nsStyleVisibility. r=dholbert (ee8372fb94)
- Bug 1261754 - Part 5: Move text-rendering from nsStyleSVG to nsStyleText. r=dholbert (c13a11313d)
- Bug 1261754 - Part 6: Move vertical-align from nsStyleTextReset to nsStyleDisplay. r=dholbert (d374b3700b)
- Bug 1261754 - Part 7: Move pointer-events from nsStyleVisibility to nsStyleUserInterface. r=dholbert (8693251243)
- Bug 1261754 - Part 8: Move box-shadow from nsStyleBorder to a new nsStyleEffects struct. r=dholbert (8263476827)
- Bug 1261754 - Part 9: Move clip from nsStyleDisplay to nsStyleEffects. r=dholbert (5418597309)
- Bug 1261754 - Part 10: Move mix-blend-mode from nsStyleDisplay to nsStyleEffects. r=dholbert (ebae613929)
- Bug 1261754 - Part 11: Move opacity from nsStyleDisplay to nsStyleEffects. r=dholbert (589292af44)
- Bug 1187851 patch 6 - Make dynamic changes to filter change fixed position containing block for descendants. r=roc (003a3aa6ce)
- Bug 1261754 - Part 12: Move filter from nsStyleSVGReset to nsStyleEffects. r=dholbert (78d87914f9)
- Bug 1259513: Make gfxContext constructor private, use a utility function that can return nullptr. r=bas,lsalzman (43df6e429f)
- Bug 1259785: Do a proper flush when taking a snapshot so our dependent targets and command lists get appropriately cleared. r=jrmuizel (9f7372cce1)
- Bug 1251431 - Part 1: Allow usage of an A8 source pattern to MaskSurface for D2D 1.1 Moz2D backend. r=jwatt (632eb6d2da)
- Bug 1251431 - Part 2: Do not apply the device transform when drawing to an already intermediate surface. r=jwatt (3a24f4a5c6)
- Bug 1251431 - GCC compilation fixup. (2356f0a58c)
- Bug 1238328: Purge stored command lists by calling EndDraw/BeginDraw on a regular basis when they're used. r=jrmuizel (33f47b281f)
- Bug 1246641: Also execute an occasional EndDraw for CommandLists used by non-operator OVER drawing. r=jrmuizel (b3e03ad111)
- Bug 1258168: Push ClearType compatible clipping layers when the last pushed layer was marked as opaque. r=jrmuizel (bd069ad7b6)
- Bug 1264736: Crash sooner if we can't get a valid command list, at least in nightly/aurora. r=bas (fb4bb56815)
- Bug 1255438 - create nsI{Mutable,}Array directly; r=keeler (1b802b23b7)
- Bug 1255438 - fix OS X warning bustage and reopen this CLOSED TREE; r=me (07a05910a6)
- bug 1197314: Remove PR_snprintf calls in security/manager/ssl/ r=keeler (f2271aad87)
- Bug 1258298 - Switch more Scoped.h templates in PSM to UniquePtr equivalents. r=keeler (2ee1a85d8e)
- Bug 1191414 - gather telemetry on usage of <keygen>. r=keeler,r=vladan (150bad38a1)
- Bug 1260644 - Use UniquePLArenaPool to manage PLArenaPools in PSM. r=keeler (9e8ad9c0d4)
- Bug 1247250 - Enable TLS 1.3 anti-downgrade on non-secure fallback. r=keeler (7a950b427a)
- Bug 1215796 - Remove the static fallback whitelist. r=keeler (fa55b5920b)
- bug 1254667 - change certificate verification SHA1 policy to "allow or locally-installed roots" r=jcj (5d0bb9e8b1)
- bug 1245280 - add policy mechanism to optionally enforce BRs for falling back to subject CN r=Cykesiopka,mgoodwin (ecd4f2180a)
- Bug 1254653 - Add telemetry to measure how often we encounter EV certificates r=keeler (9da287b490)
- Bug 1259909 - Obviate char PORT_Free() calls in PSM. r=keeler (b7ba2a47da)
- Bug 1252882 - Add a Content Signature Service r=keeler,r=franziskus,r=Cykesiopka (8b806022a0)
- Bug 1255784 - u2f tests should use SpecialPowers.pushPrefEnv, r=jjones (839a58476f)
- Bug 1244960 - Complete FIDO u2f NSSToken (Part 1). r=keeler, r=baku (3d64aa2b7c)
- Bug 1244960 - FIDO u2f NSSToken (Part 2): Use Attestation Certificates. r=keeler (aee3ffc830)
- Bug 1244960 - FIDO u2f NSSToken (Part 3): Review updates. r=keeler (b2f81c2b72)
- Bug 1244960 - FIDO u2f NSSToken (Part 4): Correct FacetID base algorithm. r=keeler (9e70506580)
- Bug 1244960 - FIDO u2f NSSToken (Part 5): Review updates. r=keeler (62a28f2502)
- Bug 1231643 - Part 1. Create skia-A8-surface for mask composition when backendtype of the source DrawTarget is CG; r=mstange (dd03d86f55)
- Bug 1244598 - Move resource files of w3c-css/masking into ./support subdir. r=dbaron (4c9e789191)
- Bug 1243675 - Part 1. Add mask-image property reftest. r=dbaron (18e5dfa90b)
- Bug 1243675 - Part 2. Add mask-clip property reftest. r=dbaron (ddf834d408)
- Bug 1243675 - Part 3. Add mask-position property reftest. r=dbaron (68cae7c7e6)
- Bug 1243675 - Part 4. Add mask-repeat property reftest. r=dbaron (0a3ed45377)
- Bug 1243675 - Part 5. Add mask-origin property reftest. r=dbaron (f5785145a7)
- Bug 1243675 - Part 6. Add mask-size property reftest. r=dbaron (1ab2040973)
- Bug 1231643 - Part 2. Enable mask-composite reftest; r=dbaron (8c3b863d97)
- Bug 1263622 - Fixed nsNSSComponent.cpp compilation on mingw. r=dkeeler,ted (0e651c0211)
- Bug 1266249 - Remove mHasCachedOutline. r=dbaron (c46459acf2)
- Bug 1235634 - Construct nsNSSShutdownList::singleton lazily on first use r=keeler (1b53753c2e)
- Bug 1262645 - Address misc issues with nsGetUserCertChoice(). r=keeler (ec675be29a)
- Bug 1238001 - Allow TLS info to be updated on renegotiation, r=keeler (a2ec0c8a07)
- Bug 1201437 - Add new WebProgress state flag for user-overridden cert. r=keeler (0b9edbc8d8)
- Bug 1201437 - Make cert override tests check for STATE_CERT_USER_OVERRIDDEN. r=keeler (5246515084)
- bug 1261936 - stop using the subject common name in certificate verification error messages r=Cykesiopka (982cf43a11)
- bug 1230234 - fix a leak in client auth certificate handling r=Cykesiopka (6e83f81218)
- Bug 1260643 - Convert most uses of ScopedCERTCertificate in PSM to UniqueCERTCertificate. r=keeler (806b895c41)
- Bug 1207137 - Set a security state flag when weak crypto override is needed. r=keeler Bug 1254306 - Do not check the fallback limit version for the RC4 fallback. r=keeler (8b5cb7101f)
- Bug 1253010 - part 3 - create all nsIDateTimeFormat instances directly; r=smontagu (c1aa5d1d62)
- Bug 1260310 - Create servo style contexts from ServoStyleSet. r=heycam (05f876eb13)
- Bug 759568 - Part 1. Parse background-clip:text; r=dholbert r=heycam (d013b8fd84)
- Bug 1251995 part 6 - Use struct to pass params for nsTextFrame::PainText* functions. r=jfkthame (3b9c163eab)
- Bug 759568 - Part 2. Render background-clip:text; r=jfkthame (e534e048bf)
- Bug 759568 - Part 4. mochitest for background-clip:text; r=heycom (3e548ebf99)
- Bug 759568 - Part 5. reftest for background-clip:text; r=dbaron (43d2915305)
- Bug 759568 - Part 6. Remove unused nsDisplayList::mVisibleRect; r=jfkthame (960a85de40)
- Bug 1264910 - Simplify pref callback register/unregister in nsLayoutUtils. r=dholbert (f50219f117)
- Bug 1097499 part 1 - Control support of 'text-combine-upright: digits' via a separate pref. r=heycam (37df36e815)
- Bug 1261062 - When constraining the displayport by the max texture size, maintain the relative distribution of the margins. r=dvander (9a9423bdf1)
- Bug 1246290 - Add a pref to allow disabling APZ on documents which have scroll-linked effects. r=botond (781b63c578)
- Bug 1263347 - When checking if displayport changes should schedule a paint, make sure to use the proper displayport. r=mstange (998f59843e)
- Bug 1097499 part 15 - Add reftests for text-combine-upright. r=jfkthame (843bea00bc)
- Bug 1097499 followup - Fix metadata of tests submitted to w3c. DONTBUILD (e671b5b38b)
- Bug 1097499 followup 2 - Fix metadata of tests submitted to w3c. DONTBUILD (abf0895450)
- Bug 1097499 part 2 - Add a macro to simplify usage of nsStyleContext::GetUniqueStyleData. r=heycam (10486f1f24)
- Bug 1097499 part 3 - Add a separate anonbox for text nodes. r=heycam (7dd4347215)
- Bug 1097499 part 4 - Adjust computed value of writing-mode on text frames when text-combine-upright is used. r=heycam (c193f14b27)
- Bug 1097499 part 5 - Layout text combine upright. r=jfkthame (c21422930b)
- Bug 1097499 part 6 - Inherit move direction from parent for horizontal-in-vertical text. r=jfkthame (cf436b8494)
- Bug 1097499 part 7 - Add reverse function of GetFullWidth. r=emk (32d02e7437)
- Bug 1097499 part 8 - Move CountGraphemeClusters to mozilla::unicode. r=emk (e2b8942e53)
- Bug 1156588 - Add crashtest. (237adb0604)
- Bug 1234622. Tweak how nsDocumentViewer::FindContainerView finds the parent presshell. r=bz (d1e76ae2e9)
- Bug 1245978 part 1: Make nsDocumentViewer::CreateStyleSet directly return the thing it creates. r=heycam (ede16260a4)
- Bug 1245978 part 2: Drop redundant 'virtual' keyword from NS_DECL_NSIDOCUMENTVIEWERPRINT macro (which already includes 'override' keyword). r=heycam (42b8962e4f)
- Bug 1183879 - Soften "non-subdocument frame" warning to also allow dummy nsFrames, which exist while subdocument is loading. r=dholbert (6ebcb53421)
- Bug 1259246. Move nsIPresShell::GetRealPrimaryFrameFor to nsLayoutUtils::GetRealPrimaryFrameFor. r=dholbert (d3efd2f03a)
- Bug 645647 part 1 - Don't let empty bullet frames block suppressing white-space in intrinsic size calculations. r=dholbert (2ce0a86bfb)
- Bug 645647 part 2 - Reftests. (496e491990)
- Bug 645647 part 3 - Remove unused trailingTextFrame member. r=dholbert (bd26ea25e6)
- Bug 645647 part 4 - Add an 'm' prefix to some members to follow our naming conventions. r=dholbert (fe3c5240c9)
- Bug 1097499 part 9 - Transform full-width characters to non-full-width correspondents for combined text. r=jfkthame (5b1eafe2a7)
- Bug 1097499 part 10 - Add fwid/hwid/twid/qwid font feature support to gfx. r=jfkthame (682698dd38)
- Bug 1097499 part 11 - Set width variant for text-combined frame. r=jfkthame (937f61e0e9)
- Bug 1097499 part 12 - Handle spacing sensibly for text-combine-upright. r=jfkthame (9ae1ab2941)
- Bug 1220438 - Correct baseline offset computation of text decoration for vertical-rl. r=jfkthame (10ad32d702)
- Bug 1258636 part 1 - Use structs to pass params for decoration-related functions in nsCSSRendering. r=jfkthame (deef7071f1)
- Bug 1258636 part 2 - Use struct to pass params for nsTextFrame::PaintDecorationLine. r=jfkthame (df5bde2547)
- Bug 1229743 part 1 - Simplify text decoration handling code with lambda function and range-based for loop. r=jfkthame (51cd3ea4ca)
- Bug 1229743 part 2 - Fix up decoration rect computation for vertical-rl and sideways-lr. r=jfkthame (0113279f53)
- Bug 1251995 part 7 - Use struct to pass params for nsTextFrame::Paint*Shadow functions. r=jfkthame (e81ba231aa)
- Bug 759568 - Part 3. Render text-selection beneath background image; r=jfkthame (e6757762ff)
- Bug 1097499 part 13 - Draw decoration line properly for text-combine-upright. r=jfkthame (8f4be7f987)
- Bug 1264120. Remove usage of nsAutoPtr from gfx/src. r=jfkthame (6831454d8c)
- Bug 1119619 - Allow font-selection to fall back to an alternative face within the same family if the first-found face was not Regular, to handle cases where some styled faces have a reduced character set. r=m_kato (d8851b2877)
- Bug 1243226 - relax the limit on fontconfig generics. r=heycam, a=me (05df737d0e)
- Bug 1245811 - part 1 (based on patch by Andrew Comminos) - Replace gfxPlatformFontList::FindFamily with FindAndAddFamilies to allow for the possibility of the implementation returning multiple font families (e.g. when fontconfig has 'prefer' aliases). r=karlt (2bef9fafb0)
- Bug 1245811 - part 2 (based on patch by Andrew Comminos) - Let gfxFcPlatformFontList return multiple families for a given name once fontconfig substitutions have been applied. r=karlt (1ffb425a0e)
- Bug 1265452 - Remove use of nsAutoPtr from gfx/thebes. r=jrmuizel (d02c913ad5)
- Bug 1265459 - Replace uses of nsAutoPtr<gfxTextRun> with UniquePtr, and let MakeTextRun and similar methods return a UniquePtr. r=jrmuizel (da32e376b7)
- Bug 1097499 part 14 - Draw emphasis marks properly for text-combine-upright. r=jfkthame (c9115615c6)
- Bug 1097499 part 16 - Enable text-combine-upright by default. r=jfkthame (b616987f95)
- Bug 1261699 - preserve user fontconfig autohint settings in Cairo glyph rendering options. r=jfkthame (3e46dff5ff)
- Bug 1216001 - Fix a typo that eliminated a possible paint optimization. r=xidorn (6a350cadb7)
- Bug 1261568 - part1: take -webkit-text-fill-color into consideration while (d49cf427ab)
- Bug 1261568 - part2.1: update manifest before adding test. r=jgraham Bug 1261568 - part2.2: add reftest. r=jfkthame (ef3c22cfb4)
This commit is contained in:
2024-04-22 16:19:21 +08:00
parent d4cb810b7f
commit c7dc12e90f
652 changed files with 33082 additions and 8638 deletions
+1 -1
View File
@@ -828,7 +828,7 @@ TextAttrsMgr::TextPosValue
TextAttrsMgr::TextPosTextAttr::
GetTextPosValue(nsIFrame* aFrame) const
{
const nsStyleCoord& styleCoord = aFrame->StyleTextReset()->mVerticalAlign;
const nsStyleCoord& styleCoord = aFrame->StyleDisplay()->mVerticalAlign;
switch (styleCoord.GetUnit()) {
case eStyleUnit_Enumerated:
switch (styleCoord.GetIntValue()) {
+1 -1
View File
@@ -901,7 +901,7 @@ RuleCache::ApplyFilter(Accessible* aAccessible, uint16_t* aResult)
if ((nsIAccessibleTraversalRule::PREFILTER_TRANSPARENT & mPreFilter) &&
!(state & states::OPAQUE1)) {
nsIFrame* frame = aAccessible->GetFrame();
if (frame->StyleDisplay()->mOpacity == 0.0f) {
if (frame->StyleEffects()->mOpacity == 0.0f) {
*aResult |= nsIAccessibleTraversalRule::FILTER_IGNORE_SUBTREE;
return NS_OK;
}
+1 -2
View File
@@ -1202,8 +1202,7 @@ Accessible::State()
if (!frame)
return state;
const nsStyleDisplay* display = frame->StyleDisplay();
if (display && display->mOpacity == 1.0f &&
if (frame->StyleEffects()->mOpacity == 1.0f &&
!(state & states::INVISIBLE)) {
state |= states::OPAQUE1;
}
-1
View File
@@ -296,7 +296,6 @@ pref("ui.dragThresholdY", 25);
// Layers Acceleration. We can only have nice things on gonk, because
// they're not maintained anywhere else.
pref("layers.offmainthreadcomposition.enabled", true);
pref("layers.offmainthreadcomposition.async-animations", true);
#ifndef MOZ_WIDGET_GONK
pref("dom.ipc.tabs.disabled", true);
-1
View File
@@ -26,7 +26,6 @@ oopCommandlineHandler.prototype = {
// environment
branch.setBoolPref("dom.ipc.tabs.disabled", false);
branch.setBoolPref("layers.acceleration.disabled", false);
branch.setBoolPref("layers.offmainthreadcomposition.enabled", true);
branch.setBoolPref("layers.offmainthreadcomposition.async-animations", true);
branch.setBoolPref("layers.async-video.enabled", true);
branch.setBoolPref("layers.async-pan-zoom.enabled", true);
+6
View File
@@ -363,6 +363,7 @@ PK11_GetMechanism
PK11_GetMinimumPwdLength
PK11_GetModInfo
PK11_GetNextSafe
PK11_GetNextSymKey
PK11_GetPadMechanism
PK11_GetPrivateKeyNickname
PK11_GetPrivateModulusLen
@@ -371,6 +372,7 @@ PK11_GetSlotInfo
PK11_GetSlotName
PK11_GetSlotPWValues
PK11_GetSlotSeries
PK11_GetSymKeyNickname
PK11_GetTokenInfo
PK11_GetTokenName
PK11_HashBuf
@@ -396,6 +398,7 @@ PK11_KeyGen
PK11_KeyGenWithTemplate
PK11_ListCerts
PK11_ListCertsInSlot
PK11_ListFixedKeysInSlot
PK11_ListPrivateKeysInSlot
PK11_ListPrivKeysInSlot
PK11_LoadPrivKey
@@ -425,9 +428,11 @@ PK11SDR_Decrypt
PK11SDR_Encrypt
PK11_SetPasswordFunc
PK11_SetSlotPWValues
PK11_SetSymKeyNickname
PK11_Sign
PK11_SignatureLen
PK11_SignWithMechanism
PK11_TokenKeyGenWithFlags
PK11_UnwrapPrivKey
PK11_UnwrapSymKey
PK11_UpdateSlotAttribute
@@ -675,6 +680,7 @@ SSL_PeerCertificateChain
SSL_PeerStapledOCSPResponses
SSL_ResetHandshake
SSL_SetCanFalseStartCallback
SSL_SetDowngradeCheckVersion
SSL_SetNextProtoNego
SSL_SetPKCS11PinArg
SSL_SetSockPeerID
+17 -59
View File
@@ -12,7 +12,7 @@
namespace mozilla {
namespace dom {
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(FileList, mFilesOrDirectories, mParent)
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(FileList, mFiles, mParent)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(FileList)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
@@ -29,20 +29,6 @@ FileList::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
return mozilla::dom::FileListBinding::Wrap(aCx, this, aGivenProto);
}
void
FileList::Append(File* aFile)
{
OwningFileOrDirectory* element = mFilesOrDirectories.AppendElement();
element->SetAsFile() = aFile;
}
void
FileList::Append(Directory* aDirectory)
{
OwningFileOrDirectory* element = mFilesOrDirectories.AppendElement();
element->SetAsDirectory() = aDirectory;
}
NS_IMETHODIMP
FileList::GetLength(uint32_t* aLength)
{
@@ -54,75 +40,47 @@ FileList::GetLength(uint32_t* aLength)
NS_IMETHODIMP
FileList::Item(uint32_t aIndex, nsISupports** aValue)
{
if (aIndex >= mFilesOrDirectories.Length()) {
return NS_ERROR_FAILURE;
}
if (mFilesOrDirectories[aIndex].IsFile()) {
nsCOMPtr<nsIDOMBlob> file = mFilesOrDirectories[aIndex].GetAsFile();
file.forget(aValue);
return NS_OK;
}
MOZ_ASSERT(mFilesOrDirectories[aIndex].IsDirectory());
RefPtr<Directory> directory = mFilesOrDirectories[aIndex].GetAsDirectory();
directory.forget(aValue);
nsCOMPtr<nsIDOMBlob> file = Item(aIndex);
file.forget(aValue);
return NS_OK;
}
void
FileList::Item(uint32_t aIndex, Nullable<OwningFileOrDirectory>& aValue,
ErrorResult& aRv) const
File*
FileList::Item(uint32_t aIndex) const
{
if (aIndex >= mFilesOrDirectories.Length()) {
aValue.SetNull();
return;
if (aIndex >= mFiles.Length()) {
return nullptr;
}
aValue.SetValue(mFilesOrDirectories[aIndex]);
return mFiles[aIndex];
}
void
FileList::IndexedGetter(uint32_t aIndex, bool& aFound,
Nullable<OwningFileOrDirectory>& aFileOrDirectory,
ErrorResult& aRv) const
File*
FileList::IndexedGetter(uint32_t aIndex, bool& aFound) const
{
aFound = aIndex < mFilesOrDirectories.Length();
Item(aIndex, aFileOrDirectory, aRv);
aFound = aIndex < mFiles.Length();
return Item(aIndex);
}
void
FileList::ToSequence(Sequence<OwningFileOrDirectory>& aSequence,
FileList::ToSequence(Sequence<RefPtr<File>>& aSequence,
ErrorResult& aRv) const
{
MOZ_ASSERT(aSequence.IsEmpty());
if (mFilesOrDirectories.IsEmpty()) {
if (mFiles.IsEmpty()) {
return;
}
if (!aSequence.SetLength(mFilesOrDirectories.Length(),
if (!aSequence.SetLength(mFiles.Length(),
mozilla::fallible_t())) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return;
}
for (uint32_t i = 0; i < mFilesOrDirectories.Length(); ++i) {
aSequence[i] = mFilesOrDirectories[i];
for (uint32_t i = 0; i < mFiles.Length(); ++i) {
aSequence[i] = mFiles[i];
}
}
bool
FileList::ClonableToDifferentThreadOrProcess() const
{
for (uint32_t i = 0; i < mFilesOrDirectories.Length(); ++i) {
if (mFilesOrDirectories[i].IsDirectory() &&
!mFilesOrDirectories[i].GetAsDirectory()->ClonableToDifferentThreadOrProcess()) {
return false;
}
}
return true;
}
} // namespace dom
} // namespace mozilla
+13 -22
View File
@@ -40,13 +40,16 @@ public:
return mParent;
}
void Append(File* aFile);
void Append(Directory* aDirectory);
bool Append(File* aFile)
{
MOZ_ASSERT(aFile);
return mFiles.AppendElement(aFile, fallible);
}
bool Remove(uint32_t aIndex)
{
if (aIndex < mFilesOrDirectories.Length()) {
mFilesOrDirectories.RemoveElementAt(aIndex);
if (aIndex < mFiles.Length()) {
mFiles.RemoveElementAt(aIndex);
return true;
}
@@ -55,7 +58,7 @@ public:
void Clear()
{
return mFilesOrDirectories.Clear();
return mFiles.Clear();
}
static FileList* FromSupports(nsISupports* aSupports)
@@ -75,34 +78,22 @@ public:
return static_cast<FileList*>(aSupports);
}
const OwningFileOrDirectory& UnsafeItem(uint32_t aIndex) const
{
MOZ_ASSERT(aIndex < Length());
return mFilesOrDirectories[aIndex];
}
File* Item(uint32_t aIndex) const;
void Item(uint32_t aIndex,
Nullable<OwningFileOrDirectory>& aFileOrDirectory,
ErrorResult& aRv) const;
void IndexedGetter(uint32_t aIndex, bool& aFound,
Nullable<OwningFileOrDirectory>& aFileOrDirectory,
ErrorResult& aRv) const;
File* IndexedGetter(uint32_t aIndex, bool& aFound) const;
uint32_t Length() const
{
return mFilesOrDirectories.Length();
return mFiles.Length();
}
void ToSequence(Sequence<OwningFileOrDirectory>& aSequence,
void ToSequence(Sequence<RefPtr<File>>& aSequence,
ErrorResult& aRv) const;
bool ClonableToDifferentThreadOrProcess() const;
private:
~FileList() {}
nsTArray<OwningFileOrDirectory> mFilesOrDirectories;
FallibleTArray<RefPtr<File>> mFiles;
nsCOMPtr<nsISupports> mParent;
};
+44 -105
View File
@@ -712,8 +712,7 @@ WriteBlob(JSStructuredCloneWriter* aWriter,
}
// A directory is serialized as:
// - pair of ints: SCTAG_DOM_DIRECTORY, 0
// - pair of ints: type (eDOMRootDirectory/eDOMNotRootDirectory) - path length
// - pair of ints: SCTAG_DOM_DIRECTORY, path length
// - path as string
bool
WriteDirectory(JSStructuredCloneWriter* aWriter,
@@ -726,36 +725,25 @@ WriteDirectory(JSStructuredCloneWriter* aWriter,
aDirectory->GetFullRealPath(path);
size_t charSize = sizeof(nsString::char_type);
return JS_WriteUint32Pair(aWriter, SCTAG_DOM_DIRECTORY, 0) &&
JS_WriteUint32Pair(aWriter, (uint32_t)aDirectory->Type(),
path.Length()) &&
return JS_WriteUint32Pair(aWriter, SCTAG_DOM_DIRECTORY, path.Length()) &&
JS_WriteBytes(aWriter, path.get(), path.Length() * charSize);
}
JSObject*
ReadDirectory(JSContext* aCx,
JSStructuredCloneReader* aReader,
uint32_t aZero,
uint32_t aPathLength,
StructuredCloneHolder* aHolder)
{
MOZ_ASSERT(aCx);
MOZ_ASSERT(aReader);
MOZ_ASSERT(aHolder);
MOZ_ASSERT(aZero == 0);
uint32_t directoryType, lengthOfString;
if (!JS_ReadUint32Pair(aReader, &directoryType, &lengthOfString)) {
return nullptr;
}
MOZ_ASSERT(directoryType == Directory::eDOMRootDirectory ||
directoryType == Directory::eNotDOMRootDirectory);
nsAutoString path;
path.SetLength(lengthOfString);
path.SetLength(aPathLength);
size_t charSize = sizeof(nsString::char_type);
if (!JS_ReadBytes(aReader, (void*) path.BeginWriting(),
lengthOfString * charSize)) {
aPathLength * charSize)) {
return nullptr;
}
@@ -774,8 +762,7 @@ ReadDirectory(JSContext* aCx,
JS::Rooted<JS::Value> val(aCx);
{
RefPtr<Directory> directory =
Directory::Create(aHolder->ParentDuringRead(), file,
(Directory::DirectoryType) directoryType);
Directory::Create(aHolder->ParentDuringRead(), file);
if (!ToJSValue(aCx, directory, &val)) {
return nullptr;
@@ -799,59 +786,35 @@ ReadFileList(JSContext* aCx,
{
RefPtr<FileList> fileList = new FileList(aHolder->ParentDuringRead());
// |aCount| is the number of Files or Directory for this FileList.
uint32_t zero, index;
// |index| is the index of the first blobImpl.
if (!JS_ReadUint32Pair(aReader, &zero, &index)) {
return nullptr;
}
MOZ_ASSERT(zero == 0);
// |aCount| is the number of BlobImpls to use from the |index|.
for (uint32_t i = 0; i < aCount; ++i) {
uint32_t tagOrDirectoryType, indexOrLengthOfString;
if (!JS_ReadUint32Pair(aReader, &tagOrDirectoryType,
&indexOrLengthOfString)) {
uint32_t pos = index + i;
MOZ_ASSERT(pos < aHolder->BlobImpls().Length());
RefPtr<BlobImpl> blobImpl = aHolder->BlobImpls()[pos];
MOZ_ASSERT(blobImpl->IsFile());
ErrorResult rv;
blobImpl = EnsureBlobForBackgroundManager(blobImpl, nullptr, rv);
if (NS_WARN_IF(rv.Failed())) {
rv.SuppressException();
return nullptr;
}
MOZ_ASSERT(tagOrDirectoryType == SCTAG_DOM_BLOB ||
tagOrDirectoryType == Directory::eDOMRootDirectory ||
tagOrDirectoryType == Directory::eNotDOMRootDirectory);
MOZ_ASSERT(blobImpl);
if (tagOrDirectoryType == SCTAG_DOM_BLOB) {
MOZ_ASSERT(indexOrLengthOfString < aHolder->BlobImpls().Length());
RefPtr<BlobImpl> blobImpl =
aHolder->BlobImpls()[indexOrLengthOfString];
MOZ_ASSERT(blobImpl->IsFile());
ErrorResult rv;
blobImpl = EnsureBlobForBackgroundManager(blobImpl, nullptr, rv);
if (NS_WARN_IF(rv.Failed())) {
rv.SuppressException();
return nullptr;
}
RefPtr<File> file =
File::Create(aHolder->ParentDuringRead(), blobImpl);
MOZ_ASSERT(file);
fileList->Append(file);
continue;
}
nsAutoString path;
path.SetLength(indexOrLengthOfString);
size_t charSize = sizeof(nsString::char_type);
if (!JS_ReadBytes(aReader, (void*) path.BeginWriting(),
indexOrLengthOfString * charSize)) {
RefPtr<File> file = File::Create(aHolder->ParentDuringRead(), blobImpl);
if (!fileList->Append(file)) {
return nullptr;
}
nsCOMPtr<nsIFile> file;
nsresult rv = NS_NewNativeLocalFile(NS_ConvertUTF16toUTF8(path), true,
getter_AddRefs(file));
if (NS_WARN_IF(NS_FAILED(rv))) {
return nullptr;
}
RefPtr<Directory> directory =
Directory::Create(aHolder->ParentDuringRead(), file,
(Directory::DirectoryType) tagOrDirectoryType);
fileList->Append(directory);
}
if (!ToJSValue(aCx, fileList, &val)) {
@@ -864,13 +827,7 @@ ReadFileList(JSContext* aCx,
// The format of the FileList serialization is:
// - pair of ints: SCTAG_DOM_FILELIST, Length of the FileList
// - for each element of the FileList:
// - if it's a blob:
// - pair of ints: SCTAG_DOM_BLOB, index of the BlobImpl in the array
// mBlobImplArray.
// - else:
// - pair of ints: 0/1 is root, string length
// - value string
// - pair of ints: 0, The offset of the BlobImpl array
bool
WriteFileList(JSStructuredCloneWriter* aWriter,
FileList* aFileList,
@@ -880,8 +837,13 @@ WriteFileList(JSStructuredCloneWriter* aWriter,
MOZ_ASSERT(aFileList);
MOZ_ASSERT(aHolder);
// A FileList is serialized writing the X number of elements and the offset
// from mBlobImplArray. The Read will take X elements from mBlobImplArray
// starting from the offset.
if (!JS_WriteUint32Pair(aWriter, SCTAG_DOM_FILELIST,
aFileList->Length())) {
aFileList->Length()) ||
!JS_WriteUint32Pair(aWriter, 0,
aHolder->BlobImpls().Length())) {
return false;
}
@@ -889,39 +851,18 @@ WriteFileList(JSStructuredCloneWriter* aWriter,
nsTArray<RefPtr<BlobImpl>> blobImpls;
for (uint32_t i = 0; i < aFileList->Length(); ++i) {
const OwningFileOrDirectory& data = aFileList->UnsafeItem(i);
if (data.IsFile()) {
RefPtr<BlobImpl> blobImpl =
EnsureBlobForBackgroundManager(data.GetAsFile()->Impl(), nullptr, rv);
if (NS_WARN_IF(rv.Failed())) {
rv.SuppressException();
return false;
}
if (!JS_WriteUint32Pair(aWriter, SCTAG_DOM_BLOB,
aHolder->BlobImpls().Length())) {
return false;
}
aHolder->BlobImpls().AppendElement(blobImpl);
continue;
}
MOZ_ASSERT(data.IsDirectory());
nsAutoString path;
data.GetAsDirectory()->GetFullRealPath(path);
size_t charSize = sizeof(nsString::char_type);
if (!JS_WriteUint32Pair(aWriter,
(uint32_t)data.GetAsDirectory()->Type(),
path.Length()) ||
!JS_WriteBytes(aWriter, path.get(), path.Length() * charSize)) {
RefPtr<BlobImpl> blobImpl =
EnsureBlobForBackgroundManager(aFileList->Item(i)->Impl(), nullptr, rv);
if (NS_WARN_IF(rv.Failed())) {
rv.SuppressException();
return false;
}
MOZ_ASSERT(blobImpl);
blobImpls.AppendElement(blobImpl);
}
aHolder->BlobImpls().AppendElements(blobImpls);
return true;
}
@@ -1137,9 +1078,7 @@ StructuredCloneHolder::CustomWriteHandler(JSContext* aCx,
// See if this is a FileList object.
{
FileList* fileList = nullptr;
if (NS_SUCCEEDED(UNWRAP_OBJECT(FileList, aObj, fileList)) &&
(mSupportedContext == SameProcessSameThread ||
fileList->ClonableToDifferentThreadOrProcess())) {
if (NS_SUCCEEDED(UNWRAP_OBJECT(FileList, aObj, fileList))) {
return WriteFileList(aWriter, fileList, this);
}
}
+2 -24
View File
@@ -72,7 +72,7 @@ var clonableObjects = [
new ImageData(2, 2),
];
function create_fileList_forFile() {
function create_fileList() {
var url = SimpleTest.getTestFileURL("script_postmessages_fileList.js");
var script = SpecialPowers.loadChromeScript(url);
@@ -93,27 +93,6 @@ function create_fileList_forFile() {
script.sendAsyncMessage("file.open");
}
function create_fileList_forDir() {
var url = SimpleTest.getTestFileURL("script_postmessages_fileList.js");
var script = SpecialPowers.loadChromeScript(url);
function onOpened(message) {
var fileList = document.getElementById('fileList');
SpecialPowers.wrap(fileList).mozSetDirectory(message.dir);
// Just a simple test
is(fileList.files.length, 1, "Filelist has 1 element");
ok(fileList.files[0] instanceof Directory, "We have a directory.");
clonableObjects.push(fileList.files);
script.destroy();
next();
}
script.addMessageListener("dir.opened", onOpened);
script.sendAsyncMessage("dir.open");
}
function create_directory() {
if (navigator.userAgent.toLowerCase().indexOf('Android') != -1) {
next();
@@ -548,8 +527,7 @@ function test_messagePort_inWorkers() {
}
var tests = [
create_fileList_forFile,
create_fileList_forDir,
create_fileList,
create_directory,
test_windowToWindow,
+12 -6
View File
@@ -2408,7 +2408,7 @@ CanvasRenderingContext2D::ParseFilter(const nsAString& aString,
return false;
}
aFilterChain = sc->StyleSVGReset()->mFilters;
aFilterChain = sc->StyleEffects()->mFilters;
return true;
}
@@ -3752,7 +3752,7 @@ struct MOZ_STACK_CLASS CanvasBidiProcessor : public nsBidiPresUtils::BidiProcess
}
// current text run
nsAutoPtr<gfxTextRun> mTextRun;
UniquePtr<gfxTextRun> mTextRun;
// pointer to a screen reference context used to measure text and such
RefPtr<DrawTarget> mDrawTarget;
@@ -4739,7 +4739,11 @@ CanvasRenderingContext2D::DrawDirectlyToCanvas(
// the matrix even though this is a temp gfxContext.
AutoRestoreTransform autoRestoreTransform(mTarget);
RefPtr<gfxContext> context = new gfxContext(tempTarget);
RefPtr<gfxContext> context = gfxContext::ForDrawTarget(tempTarget);
if (!context) {
gfxDevCrash(LogReason::InvalidContext) << "Canvas context problem";
return;
}
context->SetMatrix(contextMatrix.
Scale(1.0 / contextScale.width,
1.0 / contextScale.height).
@@ -4936,19 +4940,21 @@ CanvasRenderingContext2D::DrawWindow(nsGlobalWindow& aWindow, double aX,
GlobalAlpha() == 1.0f &&
UsedOperation() == CompositionOp::OP_OVER)
{
thebes = new gfxContext(mTarget);
thebes = gfxContext::ForDrawTarget(mTarget);
MOZ_ASSERT(thebes); // alrady checked the draw target above
thebes->SetMatrix(gfxMatrix(matrix._11, matrix._12, matrix._21,
matrix._22, matrix._31, matrix._32));
} else {
drawDT =
gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(IntSize(ceil(sw), ceil(sh)),
SurfaceFormat::B8G8R8A8);
if (!drawDT) {
if (!drawDT || !drawDT->IsValid()) {
aError.Throw(NS_ERROR_FAILURE);
return;
}
thebes = new gfxContext(drawDT);
thebes = gfxContext::ForDrawTarget(drawDT);
MOZ_ASSERT(thebes); // alrady checked the draw target above
thebes->SetMatrix(gfxMatrix::Scaling(matrix._11, matrix._22));
}
+3 -2
View File
@@ -80,11 +80,12 @@ DocumentRendererChild::RenderDocument(nsIDOMWindow *window,
IntSize(renderSize.width, renderSize.height),
4 * renderSize.width,
SurfaceFormat::B8G8R8A8);
if (!dt) {
if (!dt || !dt->IsValid()) {
gfxWarning() << "DocumentRendererChild::RenderDocument failed to Factory::CreateDrawTargetForData";
return false;
}
RefPtr<gfxContext> ctx = new gfxContext(dt);
RefPtr<gfxContext> ctx = gfxContext::ForDrawTarget(dt);
MOZ_ASSERT(ctx); // already checked the draw target above
ctx->SetMatrix(mozilla::gfx::ThebesMatrix(transform));
nsCOMPtr<nsIPresShell> shell = presContext->PresShell();
+37
View File
@@ -41,6 +41,13 @@ CryptoBuffer::Assign(const SECItem* aItem)
return Assign(aItem->data, aItem->len);
}
uint8_t*
CryptoBuffer::Assign(const InfallibleTArray<uint8_t>& aData)
{
return ReplaceElementsAt(0, Length(), aData.Elements(), aData.Length(),
fallible);
}
uint8_t*
CryptoBuffer::Assign(const ArrayBuffer& aData)
{
@@ -85,6 +92,19 @@ CryptoBuffer::Assign(const OwningArrayBufferViewOrArrayBuffer& aData)
return nullptr;
}
uint8_t*
CryptoBuffer::AppendSECItem(const SECItem* aItem)
{
MOZ_ASSERT(aItem);
return AppendElements(aItem->data, aItem->len, fallible);
}
uint8_t*
CryptoBuffer::AppendSECItem(const SECItem& aItem)
{
return AppendElements(aItem.data, aItem.len, fallible);
}
// Helpers to encode/decode JWK's special flavor of Base64
// * No whitespace
// * No padding
@@ -171,6 +191,23 @@ CryptoBuffer::ToUint8Array(JSContext* aCx) const
return Uint8Array::Create(aCx, Length(), Elements());
}
bool
CryptoBuffer::ToNewUnsignedBuffer(uint8_t** aBuf, uint32_t* aBufLen) const
{
MOZ_ASSERT(aBuf);
MOZ_ASSERT(aBufLen);
uint32_t dataLen = Length();
uint8_t* tmp = reinterpret_cast<uint8_t*>(moz_xmalloc(dataLen));
if (NS_WARN_IF(!tmp)) {
return false;
}
memcpy(tmp, Elements(), dataLen);
*aBuf = tmp;
*aBufLen = dataLen;
return true;
}
// "BigInt" comes from the WebCrypto spec
// ("unsigned long" isn't very "big", of course)
+5
View File
@@ -24,11 +24,15 @@ public:
uint8_t* Assign(const uint8_t* aData, uint32_t aLength);
uint8_t* Assign(const nsACString& aString);
uint8_t* Assign(const SECItem* aItem);
uint8_t* Assign(const InfallibleTArray<uint8_t>& aData);
uint8_t* Assign(const ArrayBuffer& aData);
uint8_t* Assign(const ArrayBufferView& aData);
uint8_t* Assign(const ArrayBufferViewOrArrayBuffer& aData);
uint8_t* Assign(const OwningArrayBufferViewOrArrayBuffer& aData);
uint8_t* AppendSECItem(const SECItem* aItem);
uint8_t* AppendSECItem(const SECItem& aItem);
template<typename T,
JSObject* UnwrapArray(JSObject*),
void GetLengthAndDataAndSharedness(JSObject*, uint32_t*, bool*, T**)>
@@ -43,6 +47,7 @@ public:
nsresult ToJwkBase64(nsString& aBase64);
bool ToSECItem(PLArenaPool* aArena, SECItem* aItem) const;
JSObject* ToUint8Array(JSContext* aCx) const;
bool ToNewUnsignedBuffer(uint8_t** aBuf, uint32_t* aBufLen) const;
bool GetBigIntValue(unsigned long& aRetVal);
};
+3 -3
View File
@@ -880,13 +880,13 @@ DataTransfer::GetFilesAndDirectories(ErrorResult& aRv)
}
}
Sequence<OwningFileOrDirectory> filesAndDirsSeq;
mFileList->ToSequence(filesAndDirsSeq, aRv);
Sequence<RefPtr<File>> filesSeq;
mFileList->ToSequence(filesSeq, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
p->MaybeResolve(filesAndDirsSeq);
p->MaybeResolve(filesSeq);
return p.forget();
}
+3 -5
View File
@@ -119,9 +119,7 @@ CreateDirectoryTaskChild::HandlerCallback()
}
RefPtr<Directory> dir = Directory::Create(mFileSystem->GetParentObject(),
mTargetPath,
Directory::eNotDOMRootDirectory,
mFileSystem);
mTargetPath, mFileSystem);
MOZ_ASSERT(dir);
mPromise->MaybeResolve(dir);
@@ -131,7 +129,7 @@ CreateDirectoryTaskChild::HandlerCallback()
void
CreateDirectoryTaskChild::GetPermissionAccessType(nsCString& aAccess) const
{
aAccess.AssignLiteral(CREATE_DIRECTORY_TASK_PERMISSION);
aAccess.AssignLiteral(DIRECTORY_CREATE_PERMISSION);
}
/**
@@ -216,7 +214,7 @@ CreateDirectoryTaskParent::IOWork()
void
CreateDirectoryTaskParent::GetPermissionAccessType(nsCString& aAccess) const
{
aAccess.AssignLiteral(CREATE_DIRECTORY_TASK_PERMISSION);
aAccess.AssignLiteral(DIRECTORY_CREATE_PERMISSION);
}
} // namespace dom
-2
View File
@@ -11,8 +11,6 @@
#include "nsAutoPtr.h"
#include "mozilla/ErrorResult.h"
#define CREATE_DIRECTORY_TASK_PERMISSION "create"
namespace mozilla {
namespace dom {
+2 -4
View File
@@ -5,8 +5,6 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "CreateFileTask.h"
#include "CreateDirectoryTask.h"
#include "RemoveTask.h"
#include <algorithm>
@@ -27,10 +25,10 @@
#define GET_PERMISSION_ACCESS_TYPE(aAccess) \
if (mReplace) { \
aAccess.AssignLiteral(REMOVE_TASK_PERMISSION); \
aAccess.AssignLiteral(DIRECTORY_WRITE_PERMISSION); \
return; \
} \
aAccess.AssignLiteral(CREATE_DIRECTORY_TASK_PERMISSION);
aAccess.AssignLiteral(DIRECTORY_CREATE_PERMISSION);
namespace mozilla {
namespace dom {
+24 -2
View File
@@ -115,10 +115,32 @@ DeviceStorageFileSystem::GetParentObject() const
}
void
DeviceStorageFileSystem::GetRootName(nsAString& aRetval) const
DeviceStorageFileSystem::GetDirectoryName(nsIFile* aFile, nsAString& aRetval,
ErrorResult& aRv) const
{
AssertIsOnOwningThread();
aRetval = mStorageName;
MOZ_ASSERT(aFile);
nsCOMPtr<nsIFile> rootPath;
aRv = NS_NewLocalFile(LocalOrDeviceStorageRootPath(), false,
getter_AddRefs(rootPath));
if (NS_WARN_IF(aRv.Failed())) {
return;
}
bool equal = false;
aRv = aFile->Equals(rootPath, &equal);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
if (equal) {
aRetval = mStorageName;
return;
}
FileSystemBase::GetDirectoryName(aFile, aRetval, aRv);
NS_WARN_IF(aRv.Failed());
}
bool
+5 -1
View File
@@ -30,6 +30,9 @@ public:
virtual already_AddRefed<FileSystemBase>
Clone() override;
virtual bool
ShouldCreateDirectory() override { return true; }
virtual void
Shutdown() override;
@@ -37,7 +40,8 @@ public:
GetParentObject() const override;
virtual void
GetRootName(nsAString& aRetval) const override;
GetDirectoryName(nsIFile* aFile, nsAString& aRetval,
ErrorResult& aRv) const override;
virtual bool
IsSafeFile(nsIFile* aFile) const override;
+31 -31
View File
@@ -11,6 +11,7 @@
#include "FileSystemPermissionRequest.h"
#include "GetDirectoryListingTask.h"
#include "GetFileOrDirectoryTask.h"
#include "GetFilesTask.h"
#include "RemoveTask.h"
#include "nsCharSeparatedTokenizer.h"
@@ -136,8 +137,7 @@ Directory::GetRoot(FileSystemBase* aFileSystem, ErrorResult& aRv)
}
RefPtr<GetFileOrDirectoryTaskChild> task =
GetFileOrDirectoryTaskChild::Create(aFileSystem, path, eDOMRootDirectory,
true, aRv);
GetFileOrDirectoryTaskChild::Create(aFileSystem, path, true, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
@@ -148,7 +148,7 @@ Directory::GetRoot(FileSystemBase* aFileSystem, ErrorResult& aRv)
/* static */ already_AddRefed<Directory>
Directory::Create(nsISupports* aParent, nsIFile* aFile,
DirectoryType aType, FileSystemBase* aFileSystem)
FileSystemBase* aFileSystem)
{
MOZ_ASSERT(aParent);
MOZ_ASSERT(aFile);
@@ -157,27 +157,17 @@ Directory::Create(nsISupports* aParent, nsIFile* aFile,
bool isDir;
nsresult rv = aFile->IsDirectory(&isDir);
MOZ_ASSERT(NS_SUCCEEDED(rv) && isDir);
if (aType == eNotDOMRootDirectory) {
RefPtr<nsIFile> parent;
rv = aFile->GetParent(getter_AddRefs(parent));
// We must have a parent if this is not the root directory.
MOZ_ASSERT(NS_SUCCEEDED(rv) && parent);
}
#endif
RefPtr<Directory> directory =
new Directory(aParent, aFile, aType, aFileSystem);
RefPtr<Directory> directory = new Directory(aParent, aFile, aFileSystem);
return directory.forget();
}
Directory::Directory(nsISupports* aParent,
nsIFile* aFile,
DirectoryType aType,
FileSystemBase* aFileSystem)
: mParent(aParent)
, mFile(aFile)
, mType(aType)
{
MOZ_ASSERT(aFile);
@@ -212,18 +202,12 @@ Directory::GetName(nsAString& aRetval, ErrorResult& aRv)
{
aRetval.Truncate();
if (mType == eDOMRootDirectory) {
RefPtr<FileSystemBase> fs = GetFileSystem(aRv);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
fs->GetRootName(aRetval);
RefPtr<FileSystemBase> fs = GetFileSystem(aRv);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
aRv = mFile->GetLeafName(aRetval);
NS_WARN_IF(aRv.Failed());
fs->GetDirectoryName(mFile, aRetval, aRv);
}
already_AddRefed<Promise>
@@ -317,8 +301,7 @@ Directory::Get(const nsAString& aPath, ErrorResult& aRv)
}
RefPtr<GetFileOrDirectoryTaskChild> task =
GetFileOrDirectoryTaskChild::Create(fs, realPath, eNotDOMRootDirectory,
false, aRv);
GetFileOrDirectoryTaskChild::Create(fs, realPath, false, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
@@ -408,7 +391,7 @@ Directory::GetPath(nsAString& aRetval, ErrorResult& aRv)
return;
}
fs->GetDOMPath(mFile, mType, mPath, aRv);
fs->GetDOMPath(mFile, mPath, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
@@ -437,7 +420,7 @@ Directory::GetFilesAndDirectories(ErrorResult& aRv)
}
RefPtr<GetDirectoryListingTaskChild> task =
GetDirectoryListingTaskChild::Create(fs, mFile, mType, mFilters, aRv);
GetDirectoryListingTaskChild::Create(fs, mFile, mFilters, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
@@ -446,6 +429,27 @@ Directory::GetFilesAndDirectories(ErrorResult& aRv)
return task->GetPromise();
}
already_AddRefed<Promise>
Directory::GetFiles(bool aRecursiveFlag, ErrorResult& aRv)
{
ErrorResult rv;
RefPtr<FileSystemBase> fs = GetFileSystem(rv);
if (NS_WARN_IF(rv.Failed())) {
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return nullptr;
}
RefPtr<GetFilesTaskChild> task =
GetFilesTaskChild::Create(fs, mFile, aRecursiveFlag, rv);
if (NS_WARN_IF(rv.Failed())) {
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return nullptr;
}
FileSystemPermissionRequest::RequestForTask(task);
return task->GetPromise();
}
void
Directory::SetContentFilters(const nsAString& aFilters)
{
@@ -456,10 +460,6 @@ FileSystemBase*
Directory::GetFileSystem(ErrorResult& aRv)
{
if (!mFileSystem) {
// Any subdir inherits the FileSystem of the parent Directory. If we are
// here it's because we are dealing with the DOM root.
MOZ_ASSERT(mType == eDOMRootDirectory);
nsAutoString path;
aRv = mFile->GetPath(path);
if (NS_WARN_IF(aRv.Failed())) {
+5 -19
View File
@@ -59,20 +59,9 @@ public:
static already_AddRefed<Promise>
GetRoot(FileSystemBase* aFileSystem, ErrorResult& aRv);
enum DirectoryType {
// When a directory is selected using a HTMLInputElement, that will be the
// DOM root directory and its name will be '/'. All the sub directory will
// be called with they real name. We use this enum to mark what we must
// consider the '/' of this DOM filesystem.
eDOMRootDirectory,
// All the sub directories of the '/' will be marked using this other value.
eNotDOMRootDirectory
};
static already_AddRefed<Directory>
Create(nsISupports* aParent, nsIFile* aDirectory,
DirectoryType aType, FileSystemBase* aFileSystem = 0);
FileSystemBase* aFileSystem = 0);
// ========= Begin WebIDL bindings. ===========
@@ -112,6 +101,9 @@ public:
already_AddRefed<Promise>
GetFilesAndDirectories(ErrorResult& aRv);
already_AddRefed<Promise>
GetFiles(bool aRecursiveFlag, ErrorResult& aRv);
// =========== End WebIDL bindings.============
/**
@@ -142,17 +134,12 @@ public:
FileSystemBase*
GetFileSystem(ErrorResult& aRv);
DirectoryType Type() const
{
return mType;
}
bool
ClonableToDifferentThreadOrProcess() const;
private:
Directory(nsISupports* aParent,
nsIFile* aFile, DirectoryType aType,
nsIFile* aFile,
FileSystemBase* aFileSystem = nullptr);
~Directory();
@@ -169,7 +156,6 @@ private:
nsCOMPtr<nsISupports> mParent;
RefPtr<FileSystemBase> mFileSystem;
nsCOMPtr<nsIFile> mFile;
DirectoryType mType;
nsString mFilters;
nsString mPath;
+20 -17
View File
@@ -110,19 +110,26 @@ FileSystemBase::IsSafeDirectory(Directory* aDir) const
return false;
}
void
FileSystemBase::GetDirectoryName(nsIFile* aFile, nsAString& aRetval,
ErrorResult& aRv) const
{
AssertIsOnOwningThread();
MOZ_ASSERT(aFile);
aRv = aFile->GetLeafName(aRetval);
NS_WARN_IF(aRv.Failed());
}
void
FileSystemBase::GetDOMPath(nsIFile* aFile,
Directory::DirectoryType aType,
nsAString& aRetval,
ErrorResult& aRv) const
{
AssertIsOnOwningThread();
MOZ_ASSERT(aFile);
if (aType == Directory::eDOMRootDirectory) {
aRetval.AssignLiteral(FILESYSTEM_DOM_PATH_SEPARATOR_LITERAL);
return;
}
aRetval.Truncate();
nsCOMPtr<nsIFile> fileSystemPath;
aRv = NS_NewNativeLocalFile(NS_ConvertUTF16toUTF8(LocalOrDeviceStorageRootPath()),
@@ -131,8 +138,6 @@ FileSystemBase::GetDOMPath(nsIFile* aFile,
return;
}
MOZ_ASSERT(FileSystemUtils::IsDescendantPath(fileSystemPath, aFile));
nsCOMPtr<nsIFile> path;
aRv = aFile->Clone(getter_AddRefs(path));
if (NS_WARN_IF(aRv.Failed())) {
@@ -142,6 +147,14 @@ FileSystemBase::GetDOMPath(nsIFile* aFile,
nsTArray<nsString> parts;
while (true) {
nsAutoString leafName;
aRv = path->GetLeafName(leafName);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
parts.AppendElement(leafName);
bool equal = false;
aRv = fileSystemPath->Equals(path, &equal);
if (NS_WARN_IF(aRv.Failed())) {
@@ -152,14 +165,6 @@ FileSystemBase::GetDOMPath(nsIFile* aFile,
break;
}
nsAutoString leafName;
aRv = path->GetLeafName(leafName);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
parts.AppendElement(leafName);
nsCOMPtr<nsIFile> parentPath;
aRv = path->GetParent(getter_AddRefs(parentPath));
if (NS_WARN_IF(aRv.Failed())) {
@@ -176,8 +181,6 @@ FileSystemBase::GetDOMPath(nsIFile* aFile,
MOZ_ASSERT(!parts.IsEmpty());
aRetval.Truncate();
for (int32_t i = parts.Length() - 1; i >= 0; --i) {
aRetval.AppendLiteral(FILESYSTEM_DOM_PATH_SEPARATOR_LITERAL);
aRetval.Append(parts[i]);
+6 -7
View File
@@ -37,19 +37,18 @@ public:
virtual already_AddRefed<FileSystemBase>
Clone() = 0;
virtual bool
ShouldCreateDirectory() = 0;
virtual nsISupports*
GetParentObject() const;
/*
* Get the virtual name of the root directory. This name will be exposed to
* the content page.
*/
virtual void
GetRootName(nsAString& aRetval) const = 0;
GetDirectoryName(nsIFile* aFile, nsAString& aRetval,
ErrorResult& aRv) const;
void
GetDOMPath(nsIFile* aFile, Directory::DirectoryType aType,
nsAString& aRetval, ErrorResult& aRv) const;
GetDOMPath(nsIFile* aFile, nsAString& aRetval, ErrorResult& aRv) const;
/*
* Return the local root path of the FileSystem implementation.
@@ -53,6 +53,7 @@ FileSystemRequestParent::Initialize(const FileSystemParams& aParams)
FILESYSTEM_REQUEST_PARENT_DISPATCH_ENTRY(CreateFile)
FILESYSTEM_REQUEST_PARENT_DISPATCH_ENTRY(GetDirectoryListing)
FILESYSTEM_REQUEST_PARENT_DISPATCH_ENTRY(GetFileOrDirectory)
FILESYSTEM_REQUEST_PARENT_DISPATCH_ENTRY(GetFiles)
FILESYSTEM_REQUEST_PARENT_DISPATCH_ENTRY(Remove)
default: {
+4
View File
@@ -20,6 +20,10 @@ class FileSystemBase;
class FileSystemParams;
class PBlobParent;
#define DIRECTORY_READ_PERMISSION "read"
#define DIRECTORY_WRITE_PERMISSION "write"
#define DIRECTORY_CREATE_PERMISSION "create"
/*
* The base class to implement a Task class.
* The file system operations can only be performed in the parent process. In
+5 -15
View File
@@ -18,8 +18,6 @@
#include "nsIFile.h"
#include "nsStringGlue.h"
#define GET_DIRECTORY_LISTING_PERMISSION "read"
namespace mozilla {
namespace dom {
@@ -30,7 +28,6 @@ namespace dom {
/* static */ already_AddRefed<GetDirectoryListingTaskChild>
GetDirectoryListingTaskChild::Create(FileSystemBase* aFileSystem,
nsIFile* aTargetPath,
Directory::DirectoryType aType,
const nsAString& aFilters,
ErrorResult& aRv)
{
@@ -38,7 +35,7 @@ GetDirectoryListingTaskChild::Create(FileSystemBase* aFileSystem,
aFileSystem->AssertIsOnOwningThread();
RefPtr<GetDirectoryListingTaskChild> task =
new GetDirectoryListingTaskChild(aFileSystem, aTargetPath, aType, aFilters);
new GetDirectoryListingTaskChild(aFileSystem, aTargetPath, aFilters);
// aTargetPath can be null. In this case SetError will be called.
@@ -59,12 +56,10 @@ GetDirectoryListingTaskChild::Create(FileSystemBase* aFileSystem,
GetDirectoryListingTaskChild::GetDirectoryListingTaskChild(FileSystemBase* aFileSystem,
nsIFile* aTargetPath,
Directory::DirectoryType aType,
const nsAString& aFilters)
: FileSystemTaskChildBase(aFileSystem)
, mTargetPath(aTargetPath)
, mFilters(aFilters)
, mType(aType)
{
MOZ_ASSERT(aFileSystem);
aFileSystem->AssertIsOnOwningThread();
@@ -95,7 +90,6 @@ GetDirectoryListingTaskChild::GetRequestParams(const nsString& aSerializedDOMPat
}
return FileSystemGetDirectoryListingParams(aSerializedDOMPath, path,
mType == Directory::eDOMRootDirectory,
mFilters);
}
@@ -181,8 +175,7 @@ GetDirectoryListingTaskChild::HandlerCallback()
if (mTargetData[i].mType == Directory::FileOrDirectoryPath::eDirectoryPath) {
RefPtr<Directory> directory =
Directory::Create(mFileSystem->GetParentObject(), path,
Directory::eNotDOMRootDirectory, mFileSystem);
Directory::Create(mFileSystem->GetParentObject(), path, mFileSystem);
MOZ_ASSERT(directory);
// Propogate mFilter onto sub-Directory object:
@@ -206,7 +199,7 @@ GetDirectoryListingTaskChild::HandlerCallback()
void
GetDirectoryListingTaskChild::GetPermissionAccessType(nsCString& aAccess) const
{
aAccess.AssignLiteral(GET_DIRECTORY_LISTING_PERMISSION);
aAccess.AssignLiteral(DIRECTORY_READ_PERMISSION);
}
/**
@@ -232,8 +225,6 @@ GetDirectoryListingTaskParent::Create(FileSystemBase* aFileSystem,
return nullptr;
}
task->mType = aParam.isRoot()
? Directory::eDOMRootDirectory : Directory::eNotDOMRootDirectory;
return task.forget();
}
@@ -293,11 +284,10 @@ GetDirectoryListingTaskParent::IOWork()
}
if (!exists) {
if (mType == Directory::eNotDOMRootDirectory) {
if (!mFileSystem->ShouldCreateDirectory()) {
return NS_ERROR_DOM_FILE_NOT_FOUND_ERR;
}
// If the root directory doesn't exit, create it.
rv = mTargetPath->Create(nsIFile::DIRECTORY_TYPE, 0777);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
@@ -394,7 +384,7 @@ GetDirectoryListingTaskParent::IOWork()
void
GetDirectoryListingTaskParent::GetPermissionAccessType(nsCString& aAccess) const
{
aAccess.AssignLiteral(GET_DIRECTORY_LISTING_PERMISSION);
aAccess.AssignLiteral(DIRECTORY_READ_PERMISSION);
}
} // namespace dom
-4
View File
@@ -23,7 +23,6 @@ public:
static already_AddRefed<GetDirectoryListingTaskChild>
Create(FileSystemBase* aFileSystem,
nsIFile* aTargetPath,
Directory::DirectoryType aType,
const nsAString& aFilters,
ErrorResult& aRv);
@@ -40,7 +39,6 @@ private:
// If aDirectoryOnly is set, we should ensure that the target is a directory.
GetDirectoryListingTaskChild(FileSystemBase* aFileSystem,
nsIFile* aTargetPath,
Directory::DirectoryType aType,
const nsAString& aFilters);
virtual FileSystemParams
@@ -57,7 +55,6 @@ private:
RefPtr<Promise> mPromise;
nsCOMPtr<nsIFile> mTargetPath;
nsString mFilters;
Directory::DirectoryType mType;
// We cannot store File or Directory objects bacause this object is created
// on a different thread and File and Directory are not thread-safe.
@@ -89,7 +86,6 @@ private:
nsCOMPtr<nsIFile> mTargetPath;
nsString mFilters;
Directory::DirectoryType mType;
// We cannot store File or Directory objects bacause this object is created
// on a different thread and File and Directory are not thread-safe.
+5 -21
View File
@@ -17,8 +17,6 @@
#include "nsIFile.h"
#include "nsStringGlue.h"
#define GET_FILE_OR_DIRECTORY_PERMISSION "read"
namespace mozilla {
namespace dom {
@@ -29,7 +27,6 @@ namespace dom {
/* static */ already_AddRefed<GetFileOrDirectoryTaskChild>
GetFileOrDirectoryTaskChild::Create(FileSystemBase* aFileSystem,
nsIFile* aTargetPath,
Directory::DirectoryType aType,
bool aDirectoryOnly,
ErrorResult& aRv)
{
@@ -37,8 +34,7 @@ GetFileOrDirectoryTaskChild::Create(FileSystemBase* aFileSystem,
MOZ_ASSERT(aFileSystem);
RefPtr<GetFileOrDirectoryTaskChild> task =
new GetFileOrDirectoryTaskChild(aFileSystem, aTargetPath, aType,
aDirectoryOnly);
new GetFileOrDirectoryTaskChild(aFileSystem, aTargetPath, aDirectoryOnly);
// aTargetPath can be null. In this case SetError will be called.
@@ -59,12 +55,10 @@ GetFileOrDirectoryTaskChild::Create(FileSystemBase* aFileSystem,
GetFileOrDirectoryTaskChild::GetFileOrDirectoryTaskChild(FileSystemBase* aFileSystem,
nsIFile* aTargetPath,
Directory::DirectoryType aType,
bool aDirectoryOnly)
: FileSystemTaskChildBase(aFileSystem)
, mTargetPath(aTargetPath)
, mIsDirectory(aDirectoryOnly)
, mType(aType)
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
MOZ_ASSERT(aFileSystem);
@@ -94,8 +88,7 @@ GetFileOrDirectoryTaskChild::GetRequestParams(const nsString& aSerializedDOMPath
return FileSystemGetFileOrDirectoryParams();
}
return FileSystemGetFileOrDirectoryParams(aSerializedDOMPath, path,
mType == Directory::eDOMRootDirectory);
return FileSystemGetFileOrDirectoryParams(aSerializedDOMPath, path);
}
void
@@ -153,7 +146,6 @@ GetFileOrDirectoryTaskChild::HandlerCallback()
if (mIsDirectory) {
RefPtr<Directory> dir = Directory::Create(mFileSystem->GetParentObject(),
mTargetPath,
mType,
mFileSystem);
MOZ_ASSERT(dir);
@@ -171,7 +163,7 @@ GetFileOrDirectoryTaskChild::HandlerCallback()
void
GetFileOrDirectoryTaskChild::GetPermissionAccessType(nsCString& aAccess) const
{
aAccess.AssignLiteral(GET_FILE_OR_DIRECTORY_PERMISSION);
aAccess.AssignLiteral(DIRECTORY_READ_PERMISSION);
}
/**
@@ -197,8 +189,6 @@ GetFileOrDirectoryTaskParent::Create(FileSystemBase* aFileSystem,
return nullptr;
}
task->mType = aParam.isRoot()
? Directory::eDOMRootDirectory : Directory::eNotDOMRootDirectory;
return task.forget();
}
@@ -250,11 +240,10 @@ GetFileOrDirectoryTaskParent::IOWork()
}
if (!exists) {
if (mType == Directory::eNotDOMRootDirectory) {
if (!mFileSystem->ShouldCreateDirectory()) {
return NS_ERROR_DOM_FILE_NOT_FOUND_ERR;
}
// If the root directory doesn't exit, create it.
rv = mTargetPath->Create(nsIFile::DIRECTORY_TYPE, 0777);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
@@ -271,11 +260,6 @@ GetFileOrDirectoryTaskParent::IOWork()
return NS_OK;
}
// Check if the root is a directory.
if (mType == Directory::eDOMRootDirectory) {
return NS_ERROR_DOM_FILESYSTEM_TYPE_MISMATCH_ERR;
}
bool isFile;
// Get isFile
rv = mTargetPath->IsFile(&isFile);
@@ -298,7 +282,7 @@ GetFileOrDirectoryTaskParent::IOWork()
void
GetFileOrDirectoryTaskParent::GetPermissionAccessType(nsCString& aAccess) const
{
aAccess.AssignLiteral(GET_FILE_OR_DIRECTORY_PERMISSION);
aAccess.AssignLiteral(DIRECTORY_READ_PERMISSION);
}
} // namespace dom
-4
View File
@@ -23,7 +23,6 @@ public:
static already_AddRefed<GetFileOrDirectoryTaskChild>
Create(FileSystemBase* aFileSystem,
nsIFile* aTargetPath,
Directory::DirectoryType aType,
bool aDirectoryOnly,
ErrorResult& aRv);
@@ -51,7 +50,6 @@ private:
// If aDirectoryOnly is set, we should ensure that the target is a directory.
GetFileOrDirectoryTaskChild(FileSystemBase* aFileSystem,
nsIFile* aTargetPath,
Directory::DirectoryType aType,
bool aDirectoryOnly);
RefPtr<Promise> mPromise;
@@ -59,7 +57,6 @@ private:
// Whether we get a directory.
bool mIsDirectory;
Directory::DirectoryType mType;
};
class GetFileOrDirectoryTaskParent final : public FileSystemTaskParentBase
@@ -90,7 +87,6 @@ private:
// Whether we get a directory.
bool mIsDirectory;
Directory::DirectoryType mType;
};
} // namespace dom
+359
View File
@@ -0,0 +1,359 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "GetFilesTask.h"
#include "HTMLSplitOnSpacesTokenizer.h"
#include "js/Value.h"
#include "mozilla/dom/File.h"
#include "mozilla/dom/FileSystemBase.h"
#include "mozilla/dom/FileSystemUtils.h"
#include "mozilla/dom/PFileSystemParams.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/ipc/BlobChild.h"
#include "mozilla/dom/ipc/BlobParent.h"
#include "nsIFile.h"
#include "nsStringGlue.h"
namespace mozilla {
namespace dom {
/**
* GetFilesTaskChild
*/
/* static */ already_AddRefed<GetFilesTaskChild>
GetFilesTaskChild::Create(FileSystemBase* aFileSystem,
nsIFile* aTargetPath,
bool aRecursiveFlag,
ErrorResult& aRv)
{
MOZ_ASSERT(aFileSystem);
aFileSystem->AssertIsOnOwningThread();
nsCOMPtr<nsIGlobalObject> globalObject =
do_QueryInterface(aFileSystem->GetParentObject());
if (NS_WARN_IF(!globalObject)) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
RefPtr<GetFilesTaskChild> task =
new GetFilesTaskChild(aFileSystem, aTargetPath, aRecursiveFlag);
// aTargetPath can be null. In this case SetError will be called.
task->mPromise = Promise::Create(globalObject, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
return task.forget();
}
GetFilesTaskChild::GetFilesTaskChild(FileSystemBase* aFileSystem,
nsIFile* aTargetPath,
bool aRecursiveFlag)
: FileSystemTaskChildBase(aFileSystem)
, mTargetPath(aTargetPath)
, mRecursiveFlag(aRecursiveFlag)
{
MOZ_ASSERT(aFileSystem);
aFileSystem->AssertIsOnOwningThread();
}
GetFilesTaskChild::~GetFilesTaskChild()
{
mFileSystem->AssertIsOnOwningThread();
}
already_AddRefed<Promise>
GetFilesTaskChild::GetPromise()
{
mFileSystem->AssertIsOnOwningThread();
return RefPtr<Promise>(mPromise).forget();
}
FileSystemParams
GetFilesTaskChild::GetRequestParams(const nsString& aSerializedDOMPath,
ErrorResult& aRv) const
{
mFileSystem->AssertIsOnOwningThread();
nsAutoString path;
aRv = mTargetPath->GetPath(path);
if (NS_WARN_IF(aRv.Failed())) {
return FileSystemGetFilesParams();
}
return FileSystemGetFilesParams(aSerializedDOMPath, path, mRecursiveFlag);
}
void
GetFilesTaskChild::SetSuccessRequestResult(const FileSystemResponseValue& aValue,
ErrorResult& aRv)
{
mFileSystem->AssertIsOnOwningThread();
MOZ_ASSERT(aValue.type() ==
FileSystemResponseValue::TFileSystemFilesResponse);
FileSystemFilesResponse r = aValue;
if (!mTargetData.SetLength(r.data().Length(), mozilla::fallible_t())) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return;
}
for (uint32_t i = 0; i < r.data().Length(); ++i) {
const FileSystemFileResponse& data = r.data()[i];
mTargetData[i] = data.realPath();
}
}
void
GetFilesTaskChild::HandlerCallback()
{
mFileSystem->AssertIsOnOwningThread();
if (mFileSystem->IsShutdown()) {
mPromise = nullptr;
return;
}
if (HasError()) {
mPromise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
mPromise = nullptr;
return;
}
size_t count = mTargetData.Length();
Sequence<RefPtr<File>> listing;
if (!listing.SetLength(count, mozilla::fallible_t())) {
mPromise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
mPromise = nullptr;
return;
}
for (unsigned i = 0; i < count; i++) {
nsCOMPtr<nsIFile> path;
NS_ConvertUTF16toUTF8 fullPath(mTargetData[i]);
nsresult rv = NS_NewNativeLocalFile(fullPath, true, getter_AddRefs(path));
if (NS_WARN_IF(NS_FAILED(rv))) {
mPromise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
mPromise = nullptr;
return;
}
#ifdef DEBUG
nsCOMPtr<nsIFile> rootPath;
rv = NS_NewLocalFile(mFileSystem->LocalOrDeviceStorageRootPath(), false,
getter_AddRefs(rootPath));
if (NS_WARN_IF(NS_FAILED(rv))) {
mPromise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
mPromise = nullptr;
return;
}
MOZ_ASSERT(FileSystemUtils::IsDescendantPath(rootPath, path));
#endif
RefPtr<File> file =
File::CreateFromFile(mFileSystem->GetParentObject(), path);
MOZ_ASSERT(file);
listing[i] = file;
}
mPromise->MaybeResolve(listing);
mPromise = nullptr;
}
void
GetFilesTaskChild::GetPermissionAccessType(nsCString& aAccess) const
{
aAccess.AssignLiteral("read");
}
/**
* GetFilesTaskParent
*/
/* static */ already_AddRefed<GetFilesTaskParent>
GetFilesTaskParent::Create(FileSystemBase* aFileSystem,
const FileSystemGetFilesParams& aParam,
FileSystemRequestParent* aParent,
ErrorResult& aRv)
{
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
AssertIsOnBackgroundThread();
MOZ_ASSERT(aFileSystem);
RefPtr<GetFilesTaskParent> task =
new GetFilesTaskParent(aFileSystem, aParam, aParent);
NS_ConvertUTF16toUTF8 path(aParam.realPath());
aRv = NS_NewNativeLocalFile(path, true, getter_AddRefs(task->mTargetPath));
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
return task.forget();
}
GetFilesTaskParent::GetFilesTaskParent(FileSystemBase* aFileSystem,
const FileSystemGetFilesParams& aParam,
FileSystemRequestParent* aParent)
: FileSystemTaskParentBase(aFileSystem, aParam, aParent)
, mRecursiveFlag(aParam.recursiveFlag())
{
MOZ_ASSERT(XRE_IsParentProcess(), "Only call from parent process!");
AssertIsOnBackgroundThread();
MOZ_ASSERT(aFileSystem);
}
FileSystemResponseValue
GetFilesTaskParent::GetSuccessRequestResult(ErrorResult& aRv) const
{
AssertIsOnBackgroundThread();
InfallibleTArray<PBlobParent*> blobs;
FallibleTArray<FileSystemFileResponse> inputs;
if (!inputs.SetLength(mTargetData.Length(), mozilla::fallible_t())) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
FileSystemFilesResponse response;
return response;
}
for (unsigned i = 0; i < mTargetData.Length(); i++) {
FileSystemFileResponse fileData;
fileData.realPath() = mTargetData[i];
inputs[i] = fileData;
}
FileSystemFilesResponse response;
response.data().SwapElements(inputs);
return response;
}
nsresult
GetFilesTaskParent::IOWork()
{
MOZ_ASSERT(XRE_IsParentProcess(),
"Only call from parent process!");
MOZ_ASSERT(!NS_IsMainThread(), "Only call on I/O thread!");
if (mFileSystem->IsShutdown()) {
return NS_ERROR_FAILURE;
}
bool exists;
nsresult rv = mTargetPath->Exists(&exists);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (!exists) {
return NS_OK;
}
// Get isDirectory.
rv = ExploreDirectory(mTargetPath);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return NS_OK;
}
nsresult
GetFilesTaskParent::ExploreDirectory(nsIFile* aPath)
{
MOZ_ASSERT(XRE_IsParentProcess(),
"Only call from parent process!");
MOZ_ASSERT(!NS_IsMainThread(), "Only call on worker thread!");
MOZ_ASSERT(aPath);
bool isDir;
nsresult rv = aPath->IsDirectory(&isDir);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (!isDir) {
return NS_ERROR_DOM_FILESYSTEM_TYPE_MISMATCH_ERR;
}
nsCOMPtr<nsISimpleEnumerator> entries;
rv = aPath->GetDirectoryEntries(getter_AddRefs(entries));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
for (;;) {
bool hasMore = false;
if (NS_WARN_IF(NS_FAILED(entries->HasMoreElements(&hasMore))) || !hasMore) {
break;
}
nsCOMPtr<nsISupports> supp;
if (NS_WARN_IF(NS_FAILED(entries->GetNext(getter_AddRefs(supp))))) {
break;
}
nsCOMPtr<nsIFile> currFile = do_QueryInterface(supp);
MOZ_ASSERT(currFile);
bool isLink, isSpecial, isFile;
if (NS_WARN_IF(NS_FAILED(currFile->IsSymlink(&isLink)) ||
NS_FAILED(currFile->IsSpecial(&isSpecial))) ||
isLink || isSpecial) {
continue;
}
if (NS_WARN_IF(NS_FAILED(currFile->IsFile(&isFile)) ||
NS_FAILED(currFile->IsDirectory(&isDir))) ||
!(isFile || isDir)) {
continue;
}
if (isFile) {
nsAutoString path;
if (NS_WARN_IF(NS_FAILED(currFile->GetPath(path)))) {
continue;
}
if (!mTargetData.AppendElement(path, fallible)) {
return NS_ERROR_OUT_OF_MEMORY;
}
continue;
}
MOZ_ASSERT(isDir);
if (!mRecursiveFlag) {
continue;
}
// Recursive.
rv = ExploreDirectory(currFile);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
}
return NS_OK;
}
void
GetFilesTaskParent::GetPermissionAccessType(nsCString& aAccess) const
{
aAccess.AssignLiteral(DIRECTORY_READ_PERMISSION);
}
} // namespace dom
} // namespace mozilla
+99
View File
@@ -0,0 +1,99 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_GetFilesTask_h
#define mozilla_dom_GetFilesTask_h
#include "mozilla/dom/Directory.h"
#include "mozilla/dom/FileSystemTaskBase.h"
#include "mozilla/ErrorResult.h"
#include "nsAutoPtr.h"
namespace mozilla {
namespace dom {
class BlobImpl;
class GetFilesTaskChild final : public FileSystemTaskChildBase
{
public:
static already_AddRefed<GetFilesTaskChild>
Create(FileSystemBase* aFileSystem,
nsIFile* aTargetPath,
bool aRecursiveFlag,
ErrorResult& aRv);
virtual
~GetFilesTaskChild();
already_AddRefed<Promise>
GetPromise();
virtual void
GetPermissionAccessType(nsCString& aAccess) const override;
private:
// If aDirectoryOnly is set, we should ensure that the target is a directory.
GetFilesTaskChild(FileSystemBase* aFileSystem,
nsIFile* aTargetPath,
bool aRecursiveFlag);
virtual FileSystemParams
GetRequestParams(const nsString& aSerializedDOMPath,
ErrorResult& aRv) const override;
virtual void
SetSuccessRequestResult(const FileSystemResponseValue& aValue,
ErrorResult& aRv) override;
virtual void
HandlerCallback() override;
RefPtr<Promise> mPromise;
nsCOMPtr<nsIFile> mTargetPath;
bool mRecursiveFlag;
// We store the fullpath of Files.
FallibleTArray<nsString> mTargetData;
};
class GetFilesTaskParent final : public FileSystemTaskParentBase
{
public:
static already_AddRefed<GetFilesTaskParent>
Create(FileSystemBase* aFileSystem,
const FileSystemGetFilesParams& aParam,
FileSystemRequestParent* aParent,
ErrorResult& aRv);
virtual void
GetPermissionAccessType(nsCString& aAccess) const override;
private:
GetFilesTaskParent(FileSystemBase* aFileSystem,
const FileSystemGetFilesParams& aParam,
FileSystemRequestParent* aParent);
virtual FileSystemResponseValue
GetSuccessRequestResult(ErrorResult& aRv) const override;
virtual nsresult
IOWork() override;
nsresult
ExploreDirectory(nsIFile* aPath);
nsCOMPtr<nsIFile> mTargetPath;
bool mRecursiveFlag;
// We store the fullpath of Files.
FallibleTArray<nsString> mTargetData;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_GetFilesTask_h
-7
View File
@@ -62,13 +62,6 @@ OSFileSystem::GetParentObject() const
return mParent;
}
void
OSFileSystem::GetRootName(nsAString& aRetval) const
{
AssertIsOnOwningThread();
aRetval.AssignLiteral(FILESYSTEM_DOM_PATH_SEPARATOR_LITERAL);
}
bool
OSFileSystem::IsSafeFile(nsIFile* aFile) const
{
+14 -4
View File
@@ -25,12 +25,18 @@ public:
virtual already_AddRefed<FileSystemBase>
Clone() override;
virtual bool
ShouldCreateDirectory() override
{
MOZ_CRASH("This should not be called.");
// Because OSFileSystem should not be used when the creation of directories
// is needed. For that we have OSFileSystemParent.
return false;
}
virtual nsISupports*
GetParentObject() const override;
virtual void
GetRootName(nsAString& aRetval) const override;
virtual bool
IsSafeFile(nsIFile* aFile) const override;
@@ -67,6 +73,9 @@ public:
return nullptr;
}
virtual bool
ShouldCreateDirectory() override { return false; }
virtual nsISupports*
GetParentObject() const override
{
@@ -75,7 +84,8 @@ public:
}
virtual void
GetRootName(nsAString& aRetval) const override
GetDirectoryName(nsIFile* aFile, nsAString& aRetval,
ErrorResult& aRv) const override
{
MOZ_CRASH("This should not be called on the PBackground thread.");
}
+9 -2
View File
@@ -31,7 +31,7 @@ struct FileSystemGetDirectoryListingParams
{
nsString filesystem;
nsString realPath;
bool isRoot;
// 'filters' could be an array rather than a semicolon separated string
// (we'd then use InfallibleTArray<nsString> internally), but that is
// wasteful. E10s requires us to pass the filters over as a string anyway,
@@ -44,11 +44,17 @@ struct FileSystemGetDirectoryListingParams
nsString filters;
};
struct FileSystemGetFilesParams
{
nsString filesystem;
nsString realPath;
bool recursiveFlag;
};
struct FileSystemGetFileOrDirectoryParams
{
nsString filesystem;
nsString realPath;
bool isRoot;
};
struct FileSystemRemoveParams
@@ -64,6 +70,7 @@ union FileSystemParams
FileSystemCreateDirectoryParams;
FileSystemCreateFileParams;
FileSystemGetDirectoryListingParams;
FileSystemGetFilesParams;
FileSystemGetFileOrDirectoryParams;
FileSystemRemoveParams;
};
+6
View File
@@ -43,6 +43,11 @@ struct FileSystemDirectoryListingResponse
FileSystemDirectoryListingResponseData[] data;
};
struct FileSystemFilesResponse
{
FileSystemFileResponse[] data;
};
struct FileSystemErrorResponse
{
nsresult error;
@@ -59,6 +64,7 @@ union FileSystemResponseValue
FileSystemDirectoryResponse;
FileSystemDirectoryListingResponse;
FileSystemFileResponse;
FileSystemFilesResponse;
FileSystemErrorResponse;
};
+2 -2
View File
@@ -142,7 +142,7 @@ RemoveTaskChild::HandlerCallback()
void
RemoveTaskChild::GetPermissionAccessType(nsCString& aAccess) const
{
aAccess.AssignLiteral(REMOVE_TASK_PERMISSION);
aAccess.AssignLiteral(DIRECTORY_WRITE_PERMISSION);
}
/**
@@ -252,7 +252,7 @@ RemoveTaskParent::IOWork()
void
RemoveTaskParent::GetPermissionAccessType(nsCString& aAccess) const
{
aAccess.AssignLiteral(REMOVE_TASK_PERMISSION);
aAccess.AssignLiteral(DIRECTORY_WRITE_PERMISSION);
}
} // namespace dom
-2
View File
@@ -11,8 +11,6 @@
#include "nsAutoPtr.h"
#include "mozilla/ErrorResult.h"
#define REMOVE_TASK_PERMISSION "write"
namespace mozilla {
namespace dom {
+1
View File
@@ -28,6 +28,7 @@ UNIFIED_SOURCES += [
'FileSystemUtils.cpp',
'GetDirectoryListingTask.cpp',
'GetFileOrDirectoryTask.cpp',
'GetFilesTask.cpp',
'OSFileSystem.cpp',
'RemoveTask.cpp',
]
@@ -0,0 +1,74 @@
function test_basic(aDirectory, aNext) {
ok(aDirectory, "Directory exists.");
ok(aDirectory instanceof Directory, "We have a directory.");
is(aDirectory.path, '/' + aDirectory.name, "directory.path must be '/'+name");
aNext();
}
function test_getFilesAndDirectories(aDirectory, aRecursive, aNext) {
function checkSubDir(dir) {
return dir.getFilesAndDirectories().then(
function(data) {
for (var i = 0; i < data.length; ++i) {
ok (data[i] instanceof File || data[i] instanceof Directory, "Just Files or Directories");
if (data[i] instanceof Directory) {
isnot(data[i].name, '/', "Subdirectory should be called with the leafname");
isnot(data[i].path, '/', "Subdirectory path should be called with the leafname");
isnot(data[i].path, dir.path, "Subdirectory path should contain the parent path.");
is(data[i].path, dir.path + '/' + data[i].name, "Subdirectory path should be called parentdir.path + '/' + leafname");
}
}
}
);
}
aDirectory.getFilesAndDirectories().then(
function(data) {
ok(data.length, "We should have some data.");
var promises = [];
for (var i = 0; i < data.length; ++i) {
ok (data[i] instanceof File || data[i] instanceof Directory, "Just Files or Directories: " + data[i].name);
if (data[i] instanceof Directory) {
isnot(data[i].name, '/', "Subdirectory should be called with the leafname");
is(data[i].path, aDirectory.path + '/' + data[i].name, "Subdirectory path should be called parentdir.path + '/' + leafname");
if (aRecursive) {
promises.push(checkSubDir(data[i]));
}
}
}
return Promise.all(promises);
},
function() {
ok(false, "Something when wrong");
}
).then(aNext);
}
function test_getFiles(aDirectory, aRecursive, aNext) {
aDirectory.getFiles(aRecursive).then(
function(data) {
for (var i = 0; i < data.length; ++i) {
ok (data[i] instanceof File, "File: " + data[i].name);
}
},
function() {
ok(false, "Something when wrong");
}
).then(aNext);
}
function test_getFiles_recursiveComparison(aDirectory, aNext) {
aDirectory.getFiles(true).then(function(data) {
is(data.length, 2, "Only 2 files for this test.");
ok(data[0].name == 'foo.txt' || data[0].name == 'bar.txt', "First filename matches");
ok(data[1].name == 'foo.txt' || data[1].name == 'bar.txt', "Second filename matches");
}).then(function() {
return aDirectory.getFiles(false);
}).then(function(data) {
is(data.length, 1, "Only 1 file for this test.");
ok(data[0].name == 'foo.txt' || data[0].name == 'bar.txt', "First filename matches");
}).catch(function() {
ok(false, "Something when wrong");
}).then(aNext);
}
+1
View File
@@ -1,5 +1,6 @@
[DEFAULT]
support-files =
filesystem_commons.js
script_fileList.js
worker_basic.js
+58 -13
View File
@@ -1,22 +1,67 @@
var { classes: Cc, interfaces: Ci, utils: Cu } = Components;
Cu.importGlobalProperties(["File"]);
addMessageListener("dir.open", function (e) {
var testFile = Cc["@mozilla.org/file/directory_service;1"]
.getService(Ci.nsIDirectoryService)
.QueryInterface(Ci.nsIProperties)
.get(e.path == 'root' ? 'ProfD' : e.path, Ci.nsIFile);
function createProfDFile() {
return Cc["@mozilla.org/file/directory_service;1"]
.getService(Ci.nsIDirectoryService)
.QueryInterface(Ci.nsIProperties)
.get('ProfD', Ci.nsIFile);
}
function createRootFile() {
var testFile = createProfDFile();
// Let's go back to the root of the FileSystem
if (e.path == 'root') {
while (true) {
var parent = testFile.parent;
if (!parent) {
break;
}
testFile = parent;
while (true) {
var parent = testFile.parent;
if (!parent) {
break;
}
testFile = parent;
}
return testFile;
}
function createTestFile() {
var tmpFile = Cc["@mozilla.org/file/directory_service;1"]
.getService(Ci.nsIDirectoryService)
.QueryInterface(Ci.nsIProperties)
.get('TmpD', Ci.nsIFile)
tmpFile.append('dir-test');
tmpFile.createUnique(Components.interfaces.nsIFile.DIRECTORY_TYPE, 0o700);
var file1 = tmpFile.clone();
file1.append('foo.txt');
file1.create(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0o600);
var dir = tmpFile.clone();
dir.append('subdir');
dir.create(Components.interfaces.nsIFile.DIRECTORY_TYPE, 0o700);
var file2 = dir.clone();
file2.append('bar.txt');
file2.create(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0o600);
return tmpFile;
}
addMessageListener("dir.open", function (e) {
var testFile;
switch (e.path) {
case 'ProfD':
testFile = createProfDFile();
break;
case 'root':
testFile = createRootFile();
break;
case 'test':
testFile = createTestFile();
break;
}
sendAsyncMessage("dir.opened", {
+19 -61
View File
@@ -3,6 +3,7 @@
<head>
<title>Test for Directory API</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="filesystem_commons.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
@@ -20,77 +21,34 @@ function create_fileList(aPath) {
var fileList = document.getElementById('fileList');
SpecialPowers.wrap(fileList).mozSetDirectory(message.dir);
// Just a simple test
is(fileList.files.length, 1, "Filelist has 1 element");
ok(fileList.files[0] instanceof Directory, "We have a directory.");
fileList.getFilesAndDirectories().then(function(array) {
is(array.length, 1, "We want just 1 directory.");
ok(array[0] instanceof Directory, "We want just 1 directory.");
directory = fileList.files[0];
script.destroy();
next();
directory = array[0];
script.destroy();
next();
});
}
script.addMessageListener("dir.opened", onOpened);
script.sendAsyncMessage("dir.open", { path: aPath });
}
function test_basic() {
ok(directory, "Directory exists.");
ok(directory instanceof Directory, "We have a directory.");
is(directory.name, '/', "directory.name must be '/'");
is(directory.path, '/', "directory.path must be '/'");
next();
}
function checkSubDir(dir) {
return dir.getFilesAndDirectories().then(
function(data) {
for (var i = 0; i < data.length; ++i) {
ok (data[i] instanceof File || data[i] instanceof Directory, "Just Files or Directories");
if (data[i] instanceof Directory) {
isnot(data[i].name, '/', "Subdirectory should be called with the leafname: " + data[i].name);
isnot(data[i].path, '/', "Subdirectory path should be called with the leafname:" + data[i].path);
isnot(data[i].path, dir.path, "Subdirectory path should contain the parent path.");
is(data[i].path,dir.path + '/' + data[i].name, "Subdirectory path should be called parentdir.path + '/' + leafname");
}
}
}
);
}
function getFilesAndDirectories(aRecursive) {
directory.getFilesAndDirectories().then(
function(data) {
ok(data.length, "We should have some data.");
var promises = [];
for (var i = 0; i < data.length; ++i) {
ok (data[i] instanceof File || data[i] instanceof Directory, "Just Files or Directories");
if (data[i] instanceof Directory) {
isnot(data[i].name, '/', "Subdirectory should be called with the leafname");
is(data[i].path, '/' + data[i].name, "Subdirectory path should be called '/' + leafname");
if (aRecursive) {
promises.push(checkSubDir(data[i]));
}
}
}
return Promise.all(promises);
},
function() {
ok(false, "Something when wrong");
}
).then(next);
}
var tests = [
function() { create_fileList('ProfD') },
test_basic,
function() { getFilesAndDirectories(true) },
function() { test_basic(directory, next); },
function() { test_getFilesAndDirectories(directory, true, next); },
function() { test_getFiles(directory, false, next); },
function() { test_getFiles(directory, true, next); },
function() { create_fileList('root') },
test_basic,
function() { getFilesAndDirectories(false) },
function() { create_fileList('test') },
function() { test_getFiles_recursiveComparison(directory, next); },
function() { create_fileList('root'); },
function() { test_basic(directory, next); },
function() { test_getFilesAndDirectories(directory, false, next); },
function() { test_getFiles(directory, false, next); },
];
function next() {
+12 -16
View File
@@ -17,11 +17,6 @@ function create_fileList() {
function onOpened(message) {
var fileList = document.getElementById('fileList');
SpecialPowers.wrap(fileList).mozSetDirectory(message.dir);
// Just a simple test
is(fileList.files.length, 1, "Filelist has 1 element");
ok(fileList.files[0] instanceof Directory, "We have a directory.");
script.destroy();
next();
}
@@ -32,20 +27,21 @@ function create_fileList() {
function test_worker() {
var fileList = document.getElementById('fileList');
fileList.getFilesAndDirectories().then(function(array) {
var worker = new Worker('worker_basic.js');
worker.onmessage = function(e) {
if (e.data.type == 'finish') {
next();
return;
}
var worker = new Worker('worker_basic.js');
worker.onmessage = function(e) {
if (e.data.type == 'finish') {
next();
return;
if (e.data.type == 'test') {
ok(e.data.test, e.data.message);
}
}
if (e.data.type == 'test') {
ok(e.data.test, e.data.message);
}
}
worker.postMessage(fileList.files);
worker.postMessage(array[0]);
});
}
var tests = [
+21 -38
View File
@@ -1,3 +1,5 @@
importScripts('filesystem_commons.js');
function finish() {
postMessage({ type: 'finish' });
}
@@ -14,45 +16,26 @@ function isnot(a, b, msg) {
ok(a != b, msg);
}
function checkSubDir(dir) {
return dir.getFilesAndDirectories().then(
function(data) {
for (var i = 0; i < data.length; ++i) {
ok (data[i] instanceof File || data[i] instanceof Directory, "Just Files or Directories");
if (data[i] instanceof Directory) {
isnot(data[i].name, '/', "Subdirectory should be called with the leafname");
isnot(data[i].path, '/', "Subdirectory path should be called with the leafname");
isnot(data[i].path, dir.path, "Subdirectory path should contain the parent path.");
is(data[i].path,dir.path + '/' + data[i].name, "Subdirectory path should be called parentdir.path + '/' + leafname");
}
}
}
);
var tests = [
function() { test_basic(directory, next); },
function() { test_getFilesAndDirectories(directory, true, next); },
function() { test_getFiles(directory, false, next); },
function() { test_getFiles(directory, true, next); },
];
function next() {
if (!tests.length) {
finish();
return;
}
var test = tests.shift();
test();
}
var directory;
onmessage = function(e) {
var fileList = e.data;
ok(fileList instanceof FileList, "This is a fileList.");
is(fileList.length, 1, "We want just 1 element.");
ok(fileList[0] instanceof Directory, "This is a directory.");
fileList[0].getFilesAndDirectories().then(
function(data) {
ok(data.length, "We should have some data.");
var promises = [];
for (var i = 0; i < data.length; ++i) {
ok (data[i] instanceof File || data[i] instanceof Directory, "Just Files or Directories");
if (data[i] instanceof Directory) {
isnot(data[i].name, '/', "Subdirectory should be called with the leafname");
is(data[i].path, '/' + data[i].name, "Subdirectory path should be called '/' + leafname");
promises.push(checkSubDir(data[i]));
}
}
return Promise.all(promises);
},
function() {
ok(false, "Something when wrong");
}
).then(finish);
directory = e.data;
next();
}
+3 -8
View File
@@ -272,8 +272,7 @@ class HTMLInputElementState final : public nsISupports
continue;
}
RefPtr<Directory> directory = Directory::Create(aWindow, file,
Directory::eDOMRootDirectory);
RefPtr<Directory> directory = Directory::Create(aWindow, file);
MOZ_ASSERT(directory);
OwningFileOrDirectory* element = aResult.AppendElement();
@@ -2323,8 +2322,7 @@ HTMLInputElement::MozSetDirectory(const nsAString& aDirectoryPath,
return;
}
RefPtr<Directory> directory = Directory::Create(window, file,
Directory::eDOMRootDirectory);
RefPtr<Directory> directory = Directory::Create(window, file);
MOZ_ASSERT(directory);
nsTArray<OwningFileOrDirectory> array;
@@ -2574,7 +2572,7 @@ HTMLInputElement::SetFiles(nsIDOMFileList* aFiles,
aFiles->GetLength(&listLength);
for (uint32_t i = 0; i < listLength; i++) {
OwningFileOrDirectory* element = mFilesOrDirectories.AppendElement();
*element = files->UnsafeItem(i);
element->SetAsFile() = files->Item(i);
}
}
@@ -2690,9 +2688,6 @@ HTMLInputElement::UpdateFileList()
for (uint32_t i = 0; i < array.Length(); ++i) {
if (array[i].IsFile()) {
mFileList->Append(array[i].GetAsFile());
} else {
MOZ_ASSERT(array[i].IsDirectory());
mFileList->Append(array[i].GetAsDirectory());
}
}
}
+1 -1
View File
@@ -493,7 +493,7 @@ HTMLTableCellElement::MapAttributesIntoRule(const nsMappedAttributes* aAttribute
}
}
}
if (aData->mSIDs & NS_STYLE_INHERIT_BIT(TextReset)) {
if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Display)) {
nsCSSValue* verticalAlign = aData->ValueForVerticalAlign();
if (verticalAlign->GetUnit() == eCSSUnit_Null) {
// valign: enum
+1 -1
View File
@@ -111,7 +111,7 @@ HTMLTableColElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes
textAlign->SetIntValue(value->GetEnumValue(), eCSSUnit_Enumerated);
}
}
if (aData->mSIDs & NS_STYLE_INHERIT_BIT(TextReset)) {
if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Display)) {
nsCSSValue* verticalAlign = aData->ValueForVerticalAlign();
if (verticalAlign->GetUnit() == eCSSUnit_Null) {
// valign: enum
+1 -1
View File
@@ -286,7 +286,7 @@ HTMLTableRowElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes
textAlign->SetIntValue(value->GetEnumValue(), eCSSUnit_Enumerated);
}
}
if (aData->mSIDs & NS_STYLE_INHERIT_BIT(TextReset)) {
if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Display)) {
nsCSSValue* verticalAlign = aData->ValueForVerticalAlign();
if (verticalAlign->GetUnit() == eCSSUnit_Null) {
// valign: enum
+1 -1
View File
@@ -187,7 +187,7 @@ HTMLTableSectionElement::MapAttributesIntoRule(const nsMappedAttributes* aAttrib
textAlign->SetIntValue(value->GetEnumValue(), eCSSUnit_Enumerated);
}
}
if (aData->mSIDs & NS_STYLE_INHERIT_BIT(TextReset)) {
if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Display)) {
nsCSSValue* verticalAlign = aData->ValueForVerticalAlign();
if (verticalAlign->GetUnit() == eCSSUnit_Null) {
// valign: enum
+16 -21
View File
@@ -1437,32 +1437,27 @@ void
nsGenericHTMLElement::MapImageAlignAttributeInto(const nsMappedAttributes* aAttributes,
nsRuleData* aRuleData)
{
if (aRuleData->mSIDs & (NS_STYLE_INHERIT_BIT(Display) |
NS_STYLE_INHERIT_BIT(TextReset))) {
if (aRuleData->mSIDs & NS_STYLE_INHERIT_BIT(Display)) {
const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::align);
if (value && value->Type() == nsAttrValue::eEnum) {
int32_t align = value->GetEnumValue();
if (aRuleData->mSIDs & NS_STYLE_INHERIT_BIT(Display)) {
nsCSSValue* cssFloat = aRuleData->ValueForFloat();
if (cssFloat->GetUnit() == eCSSUnit_Null) {
if (align == NS_STYLE_TEXT_ALIGN_LEFT) {
cssFloat->SetIntValue(NS_STYLE_FLOAT_LEFT, eCSSUnit_Enumerated);
} else if (align == NS_STYLE_TEXT_ALIGN_RIGHT) {
cssFloat->SetIntValue(NS_STYLE_FLOAT_RIGHT, eCSSUnit_Enumerated);
}
nsCSSValue* cssFloat = aRuleData->ValueForFloat();
if (cssFloat->GetUnit() == eCSSUnit_Null) {
if (align == NS_STYLE_TEXT_ALIGN_LEFT) {
cssFloat->SetIntValue(NS_STYLE_FLOAT_LEFT, eCSSUnit_Enumerated);
} else if (align == NS_STYLE_TEXT_ALIGN_RIGHT) {
cssFloat->SetIntValue(NS_STYLE_FLOAT_RIGHT, eCSSUnit_Enumerated);
}
}
if (aRuleData->mSIDs & NS_STYLE_INHERIT_BIT(TextReset)) {
nsCSSValue* verticalAlign = aRuleData->ValueForVerticalAlign();
if (verticalAlign->GetUnit() == eCSSUnit_Null) {
switch (align) {
case NS_STYLE_TEXT_ALIGN_LEFT:
case NS_STYLE_TEXT_ALIGN_RIGHT:
break;
default:
verticalAlign->SetIntValue(align, eCSSUnit_Enumerated);
break;
}
nsCSSValue* verticalAlign = aRuleData->ValueForVerticalAlign();
if (verticalAlign->GetUnit() == eCSSUnit_Null) {
switch (align) {
case NS_STYLE_TEXT_ALIGN_LEFT:
case NS_STYLE_TEXT_ALIGN_RIGHT:
break;
default:
verticalAlign->SetIntValue(align, eCSSUnit_Enumerated);
break;
}
}
}
+92 -14
View File
@@ -135,6 +135,7 @@
#include "nsIMemoryReporter.h"
#include "nsIMozBrowserFrame.h"
#include "nsIMutable.h"
#include "nsINSSU2FToken.h"
#include "nsIObserverService.h"
#include "nsIPresShell.h"
#include "nsIRemoteWindowContext.h"
@@ -1985,14 +1986,6 @@ ContentParent::RecvDeallocateLayerTreeId(const uint64_t& aId)
namespace {
void
DelayedDeleteSubprocess(GeckoChildProcessHost* aSubprocess)
{
XRE_GetIOMessageLoop()
->PostTask(FROM_HERE,
new DeleteTask<GeckoChildProcessHost>(aSubprocess));
}
// This runnable only exists to delegate ownership of the
// ContentParent to this runnable, until it's deleted by the event
// system.
@@ -2124,10 +2117,10 @@ ContentParent::ActorDestroy(ActorDestroyReason why)
}
mIdleListeners.Clear();
MessageLoop::current()->
PostTask(FROM_HERE,
NewRunnableFunction(DelayedDeleteSubprocess, mSubprocess));
mSubprocess = nullptr;
if (mSubprocess) {
mSubprocess->DissociateActor();
mSubprocess = nullptr;
}
// IPDL rules require actors to live on past ActorDestroy, but it
// may be that the kungFuDeathGrip above is the last reference to
@@ -3335,7 +3328,7 @@ PCompositorBridgeParent*
ContentParent::AllocPCompositorBridgeParent(mozilla::ipc::Transport* aTransport,
base::ProcessId aOtherProcess)
{
return CompositorBridgeParent::Create(aTransport, aOtherProcess);
return CompositorBridgeParent::Create(aTransport, aOtherProcess, mSubprocess);
}
gfx::PVRManagerParent*
@@ -3349,7 +3342,7 @@ PImageBridgeParent*
ContentParent::AllocPImageBridgeParent(mozilla::ipc::Transport* aTransport,
base::ProcessId aOtherProcess)
{
return ImageBridgeParent::Create(aTransport, aOtherProcess);
return ImageBridgeParent::Create(aTransport, aOtherProcess, mSubprocess);
}
PBackgroundParent*
@@ -4229,6 +4222,91 @@ ContentParent::RecvSetURITitle(const URIParams& uri,
return true;
}
bool
ContentParent::RecvNSSU2FTokenIsCompatibleVersion(const nsString& aVersion,
bool* aIsCompatible)
{
MOZ_ASSERT(aIsCompatible);
nsCOMPtr<nsINSSU2FToken> nssToken(do_GetService(NS_NSSU2FTOKEN_CONTRACTID));
if (NS_WARN_IF(!nssToken)) {
return false;
}
nsresult rv = nssToken->IsCompatibleVersion(aVersion, aIsCompatible);
return NS_SUCCEEDED(rv);
}
bool
ContentParent::RecvNSSU2FTokenIsRegistered(nsTArray<uint8_t>&& aKeyHandle,
bool* aIsValidKeyHandle)
{
MOZ_ASSERT(aIsValidKeyHandle);
nsCOMPtr<nsINSSU2FToken> nssToken(do_GetService(NS_NSSU2FTOKEN_CONTRACTID));
if (NS_WARN_IF(!nssToken)) {
return false;
}
nsresult rv = nssToken->IsRegistered(aKeyHandle.Elements(), aKeyHandle.Length(),
aIsValidKeyHandle);
return NS_SUCCEEDED(rv);
}
bool
ContentParent::RecvNSSU2FTokenRegister(nsTArray<uint8_t>&& aApplication,
nsTArray<uint8_t>&& aChallenge,
nsTArray<uint8_t>* aRegistration)
{
MOZ_ASSERT(aRegistration);
nsCOMPtr<nsINSSU2FToken> nssToken(do_GetService(NS_NSSU2FTOKEN_CONTRACTID));
if (NS_WARN_IF(!nssToken)) {
return false;
}
uint8_t* buffer;
uint32_t bufferlen;
nsresult rv = nssToken->Register(aApplication.Elements(), aApplication.Length(),
aChallenge.Elements(), aChallenge.Length(),
&buffer, &bufferlen);
if (NS_WARN_IF(NS_FAILED(rv))) {
return false;
}
MOZ_ASSERT(buffer);
aRegistration->ReplaceElementsAt(0, aRegistration->Length(), buffer, bufferlen);
free(buffer);
return NS_SUCCEEDED(rv);
}
bool
ContentParent::RecvNSSU2FTokenSign(nsTArray<uint8_t>&& aApplication,
nsTArray<uint8_t>&& aChallenge,
nsTArray<uint8_t>&& aKeyHandle,
nsTArray<uint8_t>* aSignature)
{
MOZ_ASSERT(aSignature);
nsCOMPtr<nsINSSU2FToken> nssToken(do_GetService(NS_NSSU2FTOKEN_CONTRACTID));
if (NS_WARN_IF(!nssToken)) {
return false;
}
uint8_t* buffer;
uint32_t bufferlen;
nsresult rv = nssToken->Sign(aApplication.Elements(), aApplication.Length(),
aChallenge.Elements(), aChallenge.Length(),
aKeyHandle.Elements(), aKeyHandle.Length(),
&buffer, &bufferlen);
if (NS_WARN_IF(NS_FAILED(rv))) {
return false;
}
MOZ_ASSERT(buffer);
aSignature->ReplaceElementsAt(0, aSignature->Length(), buffer, bufferlen);
free(buffer);
return NS_SUCCEEDED(rv);
}
bool
ContentParent::RecvGetSystemMemory(const uint64_t& aGetterId)
{
+15
View File
@@ -740,6 +740,21 @@ private:
virtual bool
DeallocPCrashReporterParent(PCrashReporterParent* crashreporter) override;
virtual bool RecvNSSU2FTokenIsCompatibleVersion(const nsString& aVersion,
bool* aIsCompatible) override;
virtual bool RecvNSSU2FTokenIsRegistered(nsTArray<uint8_t>&& aKeyHandle,
bool* aIsValidKeyHandle) override;
virtual bool RecvNSSU2FTokenRegister(nsTArray<uint8_t>&& aApplication,
nsTArray<uint8_t>&& aChallenge,
nsTArray<uint8_t>* aRegistration) override;
virtual bool RecvNSSU2FTokenSign(nsTArray<uint8_t>&& aApplication,
nsTArray<uint8_t>&& aChallenge,
nsTArray<uint8_t>&& aKeyHandle,
nsTArray<uint8_t>* aSignature) override;
virtual bool RecvIsSecureURI(const uint32_t& aType, const URIParams& aURI,
const uint32_t& aFlags, bool* aIsSecureURI) override;
+44
View File
@@ -757,6 +757,50 @@ parent:
sync PCrashReporter(NativeThreadId tid, uint32_t processType);
/**
* Is this token compatible with the provided version?
*
* |version| The offered version to test
* Returns |True| if the offered version is compatible
*/
sync NSSU2FTokenIsCompatibleVersion(nsString version)
returns (bool result);
/**
* Return whether the provided KeyHandle belongs to this Token
*
* |keyHandle| Key Handle to evaluate.
* Returns |True| if the Key Handle is ours.
*/
sync NSSU2FTokenIsRegistered(uint8_t[] keyHandle)
returns (bool isValidKeyHandle);
/**
* Generates a public/private keypair for the provided application
* and challenge, returning the pubkey, challenge response, and
* key handle in the registration data.
*
* |application| The FIDO Application data to associate with the key.
* |challenge| The Challenge to satisfy in the response.
* |registration| An array containing the pubkey, challenge response,
* and key handle.
*/
sync NSSU2FTokenRegister(uint8_t[] application, uint8_t[] challenge)
returns (uint8_t[] registration);
/**
* Creates a signature over the "param" arguments using the private key
* provided in the key handle argument.
*
* |application| The FIDO Application data to associate with the key.
* |challenge| The Challenge to satisfy in the response.
* |keyHandle| The Key Handle opaque object to use.
* |signature| The resulting signature.
*/
sync NSSU2FTokenSign(uint8_t[] application, uint8_t[] challenge,
uint8_t[] keyHandle)
returns (uint8_t[] signature);
async GetSystemMemory(uint64_t getterId);
sync IsSecureURI(uint32_t type, URIParams uri, uint32_t flags)
@@ -285,10 +285,11 @@ MediaEngineTabVideoSource::Draw() {
size,
stride,
SurfaceFormat::B8G8R8X8);
if (!dt) {
if (!dt || !dt->IsValid()) {
return;
}
RefPtr<gfxContext> context = new gfxContext(dt);
RefPtr<gfxContext> context = gfxContext::ForDrawTarget(dt);
MOZ_ASSERT(context); // already checked the draw target above
context->SetMatrix(context->CurrentMatrix().Scale((((float) size.width)/mViewportWidth),
(((float) size.height)/mViewportHeight)));
-172
View File
@@ -1,172 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "NSSToken.h"
#include "nsNSSComponent.h"
#include "pk11pub.h"
namespace mozilla {
namespace dom {
const nsString NSSToken::mVersion = NS_LITERAL_STRING("U2F_V2");
const uint32_t kParamLen = 32;
const uint32_t kPublicKeyLen = 65;
const uint32_t kSignedDataLen = (2 * kParamLen) + 1 + 4;
NSSToken::NSSToken()
: mInitialized(false)
, mMutex("NSSToken::mMutex")
{}
NSSToken::~NSSToken()
{
nsNSSShutDownPreventionLock locker;
if (isAlreadyShutDown()) {
return;
}
destructorSafeDestroyNSSReference();
shutdown(calledFromObject);
}
void
NSSToken::virtualDestroyNSSReference()
{
destructorSafeDestroyNSSReference();
}
void
NSSToken::destructorSafeDestroyNSSReference()
{
mSlot = nullptr;
}
nsresult
NSSToken::Init()
{
MOZ_ASSERT(!mInitialized);
if (mInitialized) {
return NS_OK;
}
nsNSSShutDownPreventionLock locker;
if (isAlreadyShutDown()) {
return NS_ERROR_NOT_AVAILABLE;
}
MutexAutoLock lock(mMutex);
if (!EnsureNSSInitializedChromeOrContent()) {
return NS_ERROR_FAILURE;
}
mSlot = PK11_GetInternalSlot();
if (!mSlot.get()) {
return NS_ERROR_FAILURE;
}
mInitialized = true;
return NS_OK;
}
bool
NSSToken::IsCompatibleVersion(const nsString& aVersionParam) const
{
MOZ_ASSERT(mInitialized);
return mVersion == aVersionParam;
}
/*
* IsRegistered determines if the provided key handle is usable by this token.
*/
bool
NSSToken::IsRegistered(const CryptoBuffer& aKeyHandle) const
{
MOZ_ASSERT(mInitialized);
return false;
}
/*
* A U2F Register operation causes a new key pair to be generated by the token.
* The token then returns the public key of the key pair, and a handle to the
* private key. The input parameters are used only for attestation, which this
* token does not provide. (We'll see how that works!)
*
* The format of the return registration data is as follows:
*
* Bytes Value
* 1 0x05
* 65 public key
* 1 key handle length
* * key handle
* * attestation certificate (omitted for now)
* * attestation signature (omitted for now)
*
*/
nsresult
NSSToken::Register(const CryptoBuffer& /* aChallengeParam */,
const CryptoBuffer& /* aApplicationParam */,
CryptoBuffer& aRegistrationData)
{
MOZ_ASSERT(mInitialized);
nsNSSShutDownPreventionLock locker;
if (isAlreadyShutDown()) {
return NS_ERROR_NOT_AVAILABLE;
}
MutexAutoLock lock(mMutex);
if (!mInitialized) {
return NS_ERROR_NOT_INITIALIZED;
}
return NS_OK;
}
/*
* A U2F Sign operation creates a signature over the "param" arguments (plus
* some other stuff) using the private key indicated in the key handle argument.
*
* The format of the signed data is as follows:
*
* 32 Application parameter
* 1 User presence (0x01)
* 4 Counter
* 32 Challenge parameter
*
* The format of the signature data is as follows:
*
* 1 User presence
* 4 Counter
* * Signature
*
*/
nsresult
NSSToken::Sign(const CryptoBuffer& aApplicationParam,
const CryptoBuffer& aChallengeParam,
const CryptoBuffer& aKeyHandle,
CryptoBuffer& aSignatureData)
{
MOZ_ASSERT(mInitialized);
nsNSSShutDownPreventionLock locker;
if (isAlreadyShutDown()) {
return NS_ERROR_NOT_AVAILABLE;
}
MutexAutoLock lock(mMutex);
if (!mInitialized) {
return NS_ERROR_NOT_INITIALIZED;
}
return NS_OK;
}
} // namespace dom
} // namespace mozilla
-57
View File
@@ -1,57 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_NSSToken_h
#define mozilla_dom_NSSToken_h
#include "mozilla/dom/CryptoBuffer.h"
#include "mozilla/Mutex.h"
#include "nsNSSShutDown.h"
#include "ScopedNSSTypes.h"
namespace mozilla {
namespace dom {
// NSSToken will support FIDO U2F operations using NSS for the crypto layer.
// This is a stub. It will be implemented in bug 1244960.
class NSSToken final : public nsNSSShutDownObject
{
public:
NSSToken();
~NSSToken();
nsresult Init();
bool IsCompatibleVersion(const nsString& aVersionParam) const;
bool IsRegistered(const CryptoBuffer& aKeyHandle) const;
nsresult Register(const CryptoBuffer& aApplicationParam,
const CryptoBuffer& aChallengeParam,
CryptoBuffer& aRegistrationData);
nsresult Sign(const CryptoBuffer& aApplicationParam,
const CryptoBuffer& aChallengeParam,
const CryptoBuffer& aKeyHandle,
CryptoBuffer& aSignatureData);
// For nsNSSShutDownObject
virtual void virtualDestroyNSSReference() override;
void destructorSafeDestroyNSSReference();
private:
bool mInitialized;
ScopedPK11SlotInfo mSlot;
mozilla::Mutex mMutex;
static const nsString mVersion;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_NSSToken_h
+196 -64
View File
@@ -4,16 +4,21 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "hasht.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/CryptoBuffer.h"
#include "mozilla/dom/U2F.h"
#include "mozilla/dom/U2FBinding.h"
#include "mozilla/Preferences.h"
#include "nsContentUtils.h"
#include "nsIEffectiveTLDService.h"
#include "nsURLParsers.h"
#include "nsNetCID.h"
#include "nsNSSComponent.h"
#include "nsURLParsers.h"
#include "pk11pub.h"
using mozilla::dom::ContentChild;
namespace mozilla {
namespace dom {
@@ -29,14 +34,14 @@ enum class ErrorCode {
TIMEOUT = 5
};
#define PREF_U2F_SOFTTOKEN_ENABLED "security.webauth.u2f.softtoken"
#define PREF_U2F_USBTOKEN_ENABLED "security.webauth.u2f.usbtoken"
#define PREF_U2F_SOFTTOKEN_ENABLED "security.webauth.u2f_enable_softtoken"
#define PREF_U2F_USBTOKEN_ENABLED "security.webauth.u2f_enable_usbtoken"
const nsString
U2F::FinishEnrollment = NS_LITERAL_STRING("navigator.id.finishEnrollment");
const nsString U2F::FinishEnrollment =
NS_LITERAL_STRING("navigator.id.finishEnrollment");
const nsString
U2F::GetAssertion = NS_LITERAL_STRING("navigator.id.getAssertion");
const nsString U2F::GetAssertion =
NS_LITERAL_STRING("navigator.id.getAssertion");
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(U2F)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
@@ -48,6 +53,8 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(U2F)
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(U2F, mParent)
static mozilla::LazyLogModule gU2FLog("fido_u2f");
U2F::U2F()
{}
@@ -88,12 +95,17 @@ U2F::Init(nsPIDOMWindow* aParent, ErrorResult& aRv)
}
if (!EnsureNSSInitializedChromeOrContent()) {
MOZ_LOG(gU2FLog, LogLevel::Debug, ("Failed to get NSS context for U2F"));
aRv.Throw(NS_ERROR_FAILURE);
return;
}
aRv = mSoftToken.Init();
if (NS_WARN_IF(aRv.Failed())) {
return;
if (XRE_IsParentProcess()) {
mNSSToken = do_GetService(NS_NSSU2FTOKEN_CONTRACTID);
if (NS_WARN_IF(!mNSSToken)) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}
}
aRv = mUSBToken.Init();
@@ -102,6 +114,111 @@ U2F::Init(nsPIDOMWindow* aParent, ErrorResult& aRv)
}
}
nsresult
U2F::NSSTokenIsCompatible(const nsString& aVersionString, bool* aIsCompatible)
{
MOZ_ASSERT(aIsCompatible);
if (XRE_IsParentProcess()) {
MOZ_ASSERT(mNSSToken);
return mNSSToken->IsCompatibleVersion(aVersionString, aIsCompatible);
}
ContentChild* cc = ContentChild::GetSingleton();
MOZ_ASSERT(cc);
if (!cc->SendNSSU2FTokenIsCompatibleVersion(aVersionString, aIsCompatible)) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
nsresult
U2F::NSSTokenIsRegistered(CryptoBuffer& aKeyHandle, bool* aIsRegistered)
{
MOZ_ASSERT(aIsRegistered);
if (XRE_IsParentProcess()) {
MOZ_ASSERT(mNSSToken);
return mNSSToken->IsRegistered(aKeyHandle.Elements(), aKeyHandle.Length(),
aIsRegistered);
}
ContentChild* cc = ContentChild::GetSingleton();
MOZ_ASSERT(cc);
if (!cc->SendNSSU2FTokenIsRegistered(aKeyHandle, aIsRegistered)) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
nsresult
U2F::NSSTokenRegister(CryptoBuffer& aApplication, CryptoBuffer& aChallenge,
CryptoBuffer& aRegistrationData)
{
if (XRE_IsParentProcess()) {
MOZ_ASSERT(mNSSToken);
uint8_t* buffer;
uint32_t bufferlen;
nsresult rv;
rv = mNSSToken->Register(aApplication.Elements(), aApplication.Length(),
aChallenge.Elements(), aChallenge.Length(),
&buffer, &bufferlen);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
MOZ_ASSERT(buffer);
aRegistrationData.Assign(buffer, bufferlen);
free(buffer);
return NS_OK;
}
nsTArray<uint8_t> registrationBuffer;
ContentChild* cc = ContentChild::GetSingleton();
MOZ_ASSERT(cc);
if (!cc->SendNSSU2FTokenRegister(aApplication, aChallenge,
&registrationBuffer)) {
return NS_ERROR_FAILURE;
}
aRegistrationData.Assign(registrationBuffer);
return NS_OK;
}
nsresult
U2F::NSSTokenSign(CryptoBuffer& aKeyHandle, CryptoBuffer& aApplication,
CryptoBuffer& aChallenge, CryptoBuffer& aSignatureData)
{
if (XRE_IsParentProcess()) {
MOZ_ASSERT(mNSSToken);
uint8_t* buffer;
uint32_t bufferlen;
nsresult rv = mNSSToken->Sign(aApplication.Elements(), aApplication.Length(),
aChallenge.Elements(), aChallenge.Length(),
aKeyHandle.Elements(), aKeyHandle.Length(),
&buffer, &bufferlen);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
MOZ_ASSERT(buffer);
aSignatureData.Assign(buffer, bufferlen);
free(buffer);
return NS_OK;
}
nsTArray<uint8_t> signatureBuffer;
ContentChild* cc = ContentChild::GetSingleton();
MOZ_ASSERT(cc);
if (!cc->SendNSSU2FTokenSign(aApplication, aChallenge, aKeyHandle,
&signatureBuffer)) {
return NS_ERROR_FAILURE;
}
aSignatureData.Assign(signatureBuffer);
return NS_OK;
}
nsresult
U2F::AssembleClientData(const nsAString& aTyp,
const nsAString& aChallenge,
@@ -189,24 +306,6 @@ U2F::ValidAppID(/* in/out */ nsString& aAppId) const
return true;
}
nsAutoCString appIdTld;
nsAutoCString facetTld;
rv = tldService->GetBaseDomainFromHost(appIdAuth, 0, appIdTld);
if (NS_WARN_IF(NS_FAILED(rv))) {
return false;
}
rv = tldService->GetBaseDomainFromHost(facetAuth, 0, facetTld);
if (NS_WARN_IF(NS_FAILED(rv))) {
return false;
}
// If this AppID's registered domain matches the Facet's, accept
if (!facetTld.IsEmpty() && !appIdTld.IsEmpty() &&
(facetTld == appIdTld)) {
return true;
}
// TODO(Bug 1244959) Implement the remaining algorithm.
return false;
}
@@ -258,7 +357,7 @@ U2F::Register(const nsAString& aAppId,
for (size_t i = 0; i < aRegisteredKeys.Length(); ++i) {
RegisteredKey request(aRegisteredKeys[i]);
// Check for equired attributes
// Check for required attributes
if (!(request.mKeyHandle.WasPassed() &&
request.mVersion.WasPassed())) {
continue;
@@ -282,6 +381,9 @@ U2F::Register(const nsAString& aAppId,
// We ignore mTransports, as it is intended to be used for sorting the
// available devices by preference, but is not an exclusion factor.
bool isCompatible = false;
bool isRegistered = false;
// Determine if the provided keyHandle is registered at any device. If so,
// then we'll return DEVICE_INELIGIBLE to signify we're already registered.
if (usbTokenEnabled &&
@@ -291,13 +393,26 @@ U2F::Register(const nsAString& aAppId,
ErrorCode::DEVICE_INELIGIBLE);
return;
}
if (softTokenEnabled) {
rv = NSSTokenIsCompatible(request.mVersion.Value(), &isCompatible);
if (NS_FAILED(rv)) {
SendError<U2FRegisterCallback, RegisterResponse>(aCallback,
ErrorCode::OTHER_ERROR);
return;
}
if (softTokenEnabled &&
mSoftToken.IsCompatibleVersion(request.mVersion.Value()) &&
mSoftToken.IsRegistered(keyHandle)) {
SendError<U2FRegisterCallback, RegisterResponse>(aCallback,
ErrorCode::DEVICE_INELIGIBLE);
return;
rv = NSSTokenIsRegistered(keyHandle, &isRegistered);
if (NS_FAILED(rv)) {
SendError<U2FRegisterCallback, RegisterResponse>(aCallback,
ErrorCode::OTHER_ERROR);
return;
}
if (isCompatible && isRegistered) {
SendError<U2FRegisterCallback, RegisterResponse>(aCallback,
ErrorCode::DEVICE_INELIGIBLE);
return;
}
}
}
@@ -353,28 +468,31 @@ U2F::Register(const nsAString& aAppId,
// Get the registration data from the token
CryptoBuffer registrationData;
bool registerSuccess = false;
if (usbTokenEnabled &&
mUSBToken.IsCompatibleVersion(request.mVersion.Value())) {
rv = mUSBToken.Register(opt_aTimeoutSeconds, challengeParam,
appParam, registrationData);
if (NS_WARN_IF(NS_FAILED(rv))) {
SendError<U2FRegisterCallback, RegisterResponse>(aCallback,
ErrorCode::OTHER_ERROR);
return;
}
registerSuccess = true;
bool isCompatible = false;
if (usbTokenEnabled) {
// TODO: Implement in Bug 1245527
SendError<U2FRegisterCallback, RegisterResponse>(aCallback,
ErrorCode::OTHER_ERROR);
return;
}
if (!registerSuccess && softTokenEnabled &&
mSoftToken.IsCompatibleVersion(request.mVersion.Value())) {
rv = mSoftToken.Register(challengeParam, appParam, registrationData);
if (NS_WARN_IF(NS_FAILED(rv))) {
if (!registerSuccess && softTokenEnabled) {
rv = NSSTokenIsCompatible(request.mVersion.Value(), &isCompatible);
if (NS_FAILED(rv)) {
SendError<U2FRegisterCallback, RegisterResponse>(aCallback,
ErrorCode::OTHER_ERROR);
return;
}
registerSuccess = true;
if (isCompatible) {
rv = NSSTokenRegister(appParam, challengeParam, registrationData);
if (NS_FAILED(rv)) {
SendError<U2FRegisterCallback, RegisterResponse>(aCallback,
ErrorCode::OTHER_ERROR);
return;
}
registerSuccess = true;
}
}
if (!registerSuccess) {
@@ -521,25 +639,39 @@ U2F::Sign(const nsAString& aAppId,
if (usbTokenEnabled &&
mUSBToken.IsCompatibleVersion(request.mVersion.Value())) {
rv = mUSBToken.Sign(opt_aTimeoutSeconds, appParam, challengeParam,
keyHandle, signatureData);
if (NS_WARN_IF(NS_FAILED(rv))) {
SendError<U2FSignCallback, SignResponse>(aCallback,
ErrorCode::OTHER_ERROR);
return;
}
signSuccess = true;
// TODO: Implement in Bug 1245527
SendError<U2FSignCallback, SignResponse>(aCallback,
ErrorCode::OTHER_ERROR);
return;
}
if (!signSuccess && softTokenEnabled &&
mSoftToken.IsCompatibleVersion(request.mVersion.Value())) {
rv = mSoftToken.Sign(appParam, challengeParam, keyHandle, signatureData);
if (NS_WARN_IF(NS_FAILED(rv))) {
if (!signSuccess && softTokenEnabled) {
bool isCompatible = false;
bool isRegistered = false;
rv = NSSTokenIsCompatible(request.mVersion.Value(), &isCompatible);
if (NS_FAILED(rv)) {
SendError<U2FSignCallback, SignResponse>(aCallback,
ErrorCode::OTHER_ERROR);
return;
}
signSuccess = true;
rv = NSSTokenIsRegistered(keyHandle, &isRegistered);
if (NS_FAILED(rv)) {
SendError<U2FSignCallback, SignResponse>(aCallback,
ErrorCode::OTHER_ERROR);
return;
}
if (isCompatible && isRegistered) {
rv = NSSTokenSign(keyHandle, appParam, challengeParam, signatureData);
if (NS_FAILED(rv)) {
SendError<U2FSignCallback, SignResponse>(aCallback,
ErrorCode::OTHER_ERROR);
return;
}
signSuccess = true;
}
}
if (!signSuccess) {
+17 -2
View File
@@ -13,10 +13,11 @@
#include "mozilla/dom/Nullable.h"
#include "mozilla/ErrorResult.h"
#include "nsCycleCollectionParticipant.h"
#include "nsINSSU2FToken.h"
#include "nsNSSShutDown.h"
#include "nsPIDOMWindow.h"
#include "nsWrapperCache.h"
#include "NSSToken.h"
#include "USBToken.h"
namespace mozilla {
@@ -78,8 +79,8 @@ public:
private:
nsCOMPtr<nsPIDOMWindow> mParent;
nsString mOrigin;
NSSToken mSoftToken;
USBToken mUSBToken;
nsCOMPtr<nsINSSU2FToken> mNSSToken;
static const nsString FinishEnrollment;
static const nsString GetAssertion;
@@ -98,6 +99,20 @@ private:
// for a description of the algorithm.
bool
ValidAppID(/* in/out */ nsString& aAppId) const;
nsresult
NSSTokenIsCompatible(const nsString& versionString, bool* isCompatible);
nsresult
NSSTokenIsRegistered(CryptoBuffer& keyHandle, bool* isRegistered);
nsresult
NSSTokenRegister(CryptoBuffer& application, CryptoBuffer& challenge,
CryptoBuffer& registrationData);
nsresult
NSSTokenSign(CryptoBuffer& keyHandle, CryptoBuffer& application,
CryptoBuffer& challenge, CryptoBuffer& signatureData);
};
} // namespace dom
+2 -2
View File
@@ -5,17 +5,17 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
EXPORTS.mozilla.dom += [
'NSSToken.h',
'U2F.h',
'USBToken.h',
]
UNIFIED_SOURCES += [
'NSSToken.cpp',
'U2F.cpp',
'USBToken.cpp',
]
include('/ipc/chromium/chromium-config.mozbuild')
FINAL_LIBRARY = 'xul'
LOCAL_INCLUDES += [
+27
View File
@@ -0,0 +1,27 @@
<!DOCTYPE html>
<meta charset=utf-8>
<head>
<title>Test for FIDO Universal Second Factor No Token</title>
<script src="u2futil.js"></script>
</head>
<body>
<script class="testbody" type="text/javascript">
var challenge = new Uint8Array(16);
window.crypto.getRandomValues(challenge);
var regRequest = {
version: "U2F_V2",
challenge: bytesToBase64UrlSafe(challenge),
};
u2f.register(window.location.origin, [regRequest], [], function (regResponse) {
parent.postMessage(regResponse.errorCode, '*');
});
</script>
</body>
</html>
+6
View File
@@ -1,8 +1,10 @@
[DEFAULT]
support-files =
frame_no_token.html
u2futil.js
test_frame_appid_facet.html
test_frame_register.html
test_frame_register_sign.html
test_frame_appid_facet_remoteload.html
test_frame_appid_facet_insecure.html
test_frame_appid_facet_subdomain.html
@@ -13,6 +15,10 @@ support-files =
facet/facetList-no_overlap^headers^
facet/facetList-invalid_format
facet/facetList-invalid_format^headers^
pkijs/common.js
pkijs/asn1.js
pkijs/x509_schema.js
pkijs/x509_simpl.js
[test_util_methods.html]
[test_no_token.html]
+30
View File
@@ -0,0 +1,30 @@
Copyright (c) 2014, GMO GlobalSign
Copyright (c) 2015, Peculiar Ventures
All rights reserved.
Author 2014-2015, Yury Strozhevsky
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
* Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+1
View File
@@ -0,0 +1 @@
PKIjs and ASN1js are from https://pkijs.org/ and https://asn1js.org/.
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+34 -36
View File
@@ -9,9 +9,6 @@
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1231681">Mozilla Bug 1231681</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<div id="framediv">
<iframe id="testing_frame"></iframe>
@@ -19,48 +16,49 @@
<pre id="log"></pre>
<script class="testbody" type="text/javascript">
SpecialPowers.setBoolPref("security.webauth.u2f", true);
SpecialPowers.setBoolPref("security.webauth.u2f.softtoken", true);
var testList = [
"https://example.com/tests/dom/u2f/tests/test_frame_register.html",
"http://mochi.test:8888/tests/dom/u2f/tests/test_frame_appid_facet_insecure.html",
"https://example.com/tests/dom/u2f/tests/test_frame_appid_facet.html",
"https://example.com/tests/dom/u2f/tests/test_frame_appid_facet_remoteload.html",
"https://test1.example.com/tests/dom/u2f/tests/test_frame_appid_facet_subdomain.html"
];
SpecialPowers.pushPrefEnv({"set": [["security.webauth.u2f", true],
["security.webauth.u2f_enable_softtoken", true]]},
function() {
var testList = [
"https://example.com/tests/dom/u2f/tests/test_frame_register.html",
"https://example.com/tests/dom/u2f/tests/test_frame_register_sign.html",
"http://mochi.test:8888/tests/dom/u2f/tests/test_frame_appid_facet_insecure.html",
"https://example.com/tests/dom/u2f/tests/test_frame_appid_facet.html",
"https://example.com/tests/dom/u2f/tests/test_frame_appid_facet_remoteload.html",
"https://test1.example.com/tests/dom/u2f/tests/test_frame_appid_facet_subdomain.html"
];
function log(msg) {
document.getElementById("log").textContent += "\n" + msg;
}
function nextTest() {
if (testList.length < 1) {
SimpleTest.finish();
return;
function log(msg) {
document.getElementById("log").textContent += "\n" + msg;
}
document.getElementById('testing_frame').src = testList.shift();
}
function nextTest() {
if (testList.length < 1) {
SimpleTest.finish();
return;
}
// listen for a messages from the mixed content test harness
function receiveMessage(event) {
if ("test" in event.data) {
var summary = event.data.test + ": " + event.data.msg;
log(event.data.status + ": " + summary);
ok(event.data.status, summary);
} else if ("done" in event.data) {
nextTest();
document.getElementById('testing_frame').src = testList.shift();
}
}
// listen for a messages from the mixed content test harness
function receiveMessage(event) {
if ("test" in event.data) {
var summary = event.data.test + ": " + event.data.msg;
log(event.data.status + ": " + summary);
ok(event.data.status, summary);
} else if ("done" in event.data) {
nextTest();
}
}
window.addEventListener("message", receiveMessage, false);
nextTest();
});
SimpleTest.waitForExplicitFinish();
window.addEventListener("message", receiveMessage, false);
nextTest();
</script>
</body>
-11
View File
@@ -8,9 +8,6 @@
<script class="testbody" type="text/javascript">
"use strict";
SpecialPowers.setBoolPref("security.webauth.u2f", true);
SpecialPowers.setBoolPref("security.webauth.u2f.softtoken", true);
local_is(window.location.origin, "https://example.com", "Is loaded correctly");
var version = "U2F_V2";
@@ -54,14 +51,6 @@ u2f.register(window.location.origin + "/otherAppId", [{
local_is(res.errorCode, 0, "Direct window origin should work");
});
// eTLD+1 check
u2f.register("https://test1.example.com/appId", [{
version: version,
challenge: bytesToBase64UrlSafe(challenge),
}], [], function(res){
local_is(res.errorCode, 0, "Subdomain AppID should work");
});
local_finished();
</script>
@@ -8,9 +8,6 @@
<script class="testbody" type="text/javascript">
"use strict";
SpecialPowers.setBoolPref("security.webauth.u2f", true);
SpecialPowers.setBoolPref("security.webauth.u2f.softtoken", true);
local_is(window.location.origin, "http://mochi.test:8888", "Is loaded correctly");
var version = "U2F_V2";
@@ -8,9 +8,6 @@
<script class="testbody" type="text/javascript">
"use strict";
SpecialPowers.setBoolPref("security.webauth.u2f", true);
SpecialPowers.setBoolPref("security.webauth.u2f.softtoken", true);
var version = "U2F_V2";
var challenge = new Uint8Array(16);
@@ -8,30 +8,52 @@
<script class="testbody" type="text/javascript">
"use strict";
SpecialPowers.setBoolPref("security.webauth.u2f", true);
SpecialPowers.setBoolPref("security.webauth.u2f.softtoken", true);
var version = "U2F_V2";
var challenge = new Uint8Array(16);
local_is(window.location.origin, "https://test1.example.com", "Is loaded correctly");
// eTLD+1 check
u2f.register("https://example.com/appId", [{
// same domain check
u2f.register("https://test1.example.com/appId", [{
version: version,
challenge: bytesToBase64UrlSafe(challenge),
}], [], function(res){
local_is(res.errorCode, 0, "AppID should work from a subdomain");
local_is(res.errorCode, 0, "AppID should work from a different path of this domain");
step2();
});
u2f.register("https://example.net/appId", [{
version: version,
challenge: bytesToBase64UrlSafe(challenge),
}], [], function(res){
local_isnot(res.errorCode, 0, "AppID should not work from other domains");
});
function step2() {
// same domain check, but wrong scheme
u2f.register("http://test1.example.com/appId", [{
version: version,
challenge: bytesToBase64UrlSafe(challenge),
}], [], function(res){
local_isnot(res.errorCode, 0, "AppID should not work when using a different scheme");
step3();
});
}
local_finished();
function step3() {
// eTLD+1 subdomain check
u2f.register("https://example.com/appId", [{
version: version,
challenge: bytesToBase64UrlSafe(challenge),
}], [], function(res){
local_isnot(res.errorCode, 0, "AppID should not work from another subdomain in this registered domain");
step4();
});
}
function step4() {
// other domain check
u2f.register("https://mochi.test:8888/appId", [{
version: version,
challenge: bytesToBase64UrlSafe(challenge),
}], [], function(res){
local_isnot(res.errorCode, 0, "AppID should not work from other domains");
local_finished();
});
}
</script>
</body>
-3
View File
@@ -8,9 +8,6 @@
<script class="testbody" type="text/javascript">
"use strict";
SpecialPowers.setBoolPref("security.webauth.u2f", true);
SpecialPowers.setBoolPref("security.webauth.u2f.softtoken", true);
var version = "U2F_V2";
var challenge = new Uint8Array(16);
+201
View File
@@ -0,0 +1,201 @@
<!DOCTYPE html>
<meta charset=utf-8>
<head>
<script type="text/javascript" src="u2futil.js"></script>
<script type="text/javascript" src="pkijs/common.js"></script>
<script type="text/javascript" src="pkijs/asn1.js"></script>
<script type="text/javascript" src="pkijs/x509_schema.js"></script>
<script type="text/javascript" src="pkijs/x509_simpl.js"></script>
</head>
<body>
<p>Register and Sign Test for FIDO Universal Second Factor</p>
<script class="testbody" type="text/javascript">
"use strict";
var state = {
// Raw messages
regRequest: null,
regResponse: null,
regKey: null,
signChallenge: null,
signResponse: null,
// Parsed values
publicKey: null,
keyHandle: null,
// Constants
version: "U2F_V2",
appId: window.location.origin,
};
SpecialPowers.pushPrefEnv({"set": [["security.webauth.u2f", true],
["security.webauth.u2f_enable_softtoken", true]]},
function() {
local_isnot(window.u2f, undefined, "U2F API endpoint must exist");
local_isnot(window.u2f.register, undefined, "U2F Register API endpoint must exist");
local_isnot(window.u2f.sign, undefined, "U2F Sign API endpoint must exist");
testRegistering();
function testRegistering() {
var challenge = new Uint8Array(16);
window.crypto.getRandomValues(challenge);
state.regRequest = {
version: state.version,
challenge: bytesToBase64UrlSafe(challenge),
};
u2f.register(state.appId, [state.regRequest], [], function(regResponse) {
state.regResponse = regResponse;
local_is(regResponse.errorCode, 0, "The registration did not error");
local_isnot(regResponse.registrationData, undefined, "The registration did not provide registration data");
if (regResponse.errorCode > 0) {
local_finished();
return;
}
// Parse the response data from the U2F token
var registrationData = base64ToBytesUrlSafe(regResponse.registrationData);
local_is(registrationData[0], 0x05, "Reserved byte is correct")
state.publicKeyBytes = registrationData.slice(1, 66);
var keyHandleLength = registrationData[66];
state.keyHandleBytes = registrationData.slice(67, 67 + keyHandleLength);
state.keyHandle = bytesToBase64UrlSafe(state.keyHandleBytes);
state.attestation = registrationData.slice(67 + keyHandleLength);
local_is(state.attestation[0], 0x30, "Attestation Certificate has correct starting byte");
var asn1 = org.pkijs.fromBER(state.attestation.buffer);
console.log(asn1);
state.attestationCert = new org.pkijs.simpl.CERT({ schema: asn1.result });
console.log(state.attestationCert);
state.attestationSig = state.attestation.slice(asn1.offset);
local_is(state.attestationCert.subject.types_and_values[0].value.value_block.value, "Firefox U2F Soft Token", "Expected Subject");
local_is(state.attestationCert.issuer.types_and_values[0].value.value_block.value, "Firefox U2F Soft Token", "Expected Issuer");
local_is(state.attestationCert.notAfter.value - state.attestationCert.notBefore.value, 1000*60*60*48, "Valid 48 hours (in millis)");
// Verify that the clientData from the U2F token makes sense
var clientDataJSON = "";
base64ToBytesUrlSafe(regResponse.clientData).map(x => clientDataJSON += String.fromCharCode(x));
var clientData = JSON.parse(clientDataJSON);
local_is(clientData.typ, "navigator.id.finishEnrollment", "Data type matches");
local_is(clientData.challenge, state.regRequest.challenge, "Register challenge matches");
local_is(clientData.origin, window.location.origin, "Origins are the same");
// Verify the signature from the attestation certificate
deriveAppAndChallengeParam(state.appId, string2buffer(clientDataJSON))
.then(function(params){
state.appParam = params.appParam;
state.challengeParam = params.challengeParam;
return state.attestationCert.getPublicKey();
}).then(function(attestationPublicKey) {
var signedData = assembleRegistrationSignedData(state.appParam, state.challengeParam, state.keyHandleBytes, state.publicKeyBytes);
return verifySignature(attestationPublicKey, signedData, state.attestationSig);
}).then(function(verified) {
console.log("No error verifying signature");
local_ok(verified, "Attestation Certificate signature verified")
// Import the public key of the U2F token into WebCrypto
return importPublicKey(state.publicKeyBytes)
}).then(function(key) {
state.publicKey = key;
local_ok(true, "Imported public key")
// Ensure the attestation certificate is properly self-signed
return state.attestationCert.verify()
}).then(function(){
local_ok(true, "Attestation Certificate verification successful");
// Continue test
testReRegister()
}).catch(function(err){
console.log(err);
local_ok(false, "Attestation Certificate verification failed");
local_finished();
});
});
}
function testReRegister() {
state.regKey = {
version: state.version,
keyHandle: state.keyHandle,
};
// Test that we don't re-register if we provide regKey as an
// "already known" key handle. The U2F module should recognize regKey
// as being usable and, thus, give back errorCode 4.
u2f.register(state.appId, [state.regRequest], [state.regKey], function(regResponse) {
// Since we attempted to register with state.regKey as a known key, expect
// ineligible (=4).
local_is(regResponse.errorCode, 4, "The re-registration should show device ineligible");
local_is(regResponse.registrationData, undefined, "The re-registration did not provide registration data");
// Continue test
testSigning();
});
}
function testSigning() {
var challenge = new Uint8Array(16);
window.crypto.getRandomValues(challenge);
state.signChallenge = bytesToBase64UrlSafe(challenge);
// Now try to sign the signature challenge
u2f.sign(state.appId, state.signChallenge, [state.regKey], function(signResponse) {
state.signResponse = signResponse;
// Make sure this signature op worked, bailing early if it failed.
local_is(signResponse.errorCode, 0, "The signing did not error");
local_isnot(signResponse.clientData, undefined, "The signing did not provide client data");
if (signResponse.errorCode > 0) {
local_finished();
return;
}
// Decode the clientData that was returned from the module
var clientDataJSON = "";
base64ToBytesUrlSafe(signResponse.clientData).map(x => clientDataJSON += String.fromCharCode(x));
var clientData = JSON.parse(clientDataJSON);
local_is(clientData.typ, "navigator.id.getAssertion", "Data type matches");
local_is(clientData.challenge, state.signChallenge, "Sign challenge matches");
local_is(clientData.origin, window.location.origin, "Origins are the same");
// Parse the signature data
var signatureData = base64ToBytesUrlSafe(signResponse.signatureData);
if (signatureData[0] != 0x01) {
throw "User presence byte not set";
}
var presenceAndCounter = signatureData.slice(0,5);
var signatureValue = signatureData.slice(5);
// Assemble the signed data and verify the signature
deriveAppAndChallengeParam(state.appId, string2buffer(clientDataJSON))
.then(function(params){
return assembleSignedData(params.appParam, presenceAndCounter, params.challengeParam);
})
.then(function(signedData) {
return verifySignature(state.publicKey, signedData, signatureValue);
})
.then(function(verified) {
console.log("No error verifying signing signature");
local_ok(verified, "Signing signature verified")
local_finished();
})
.catch(function(err) {
console.log(err);
local_ok(false, "Signing signature invalid");
local_finished();
});
});
}
});
</script>
</body>
</html>
+16 -18
View File
@@ -8,31 +8,29 @@
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1231681">Mozilla Bug 1231681</a>
<p id="display"></p>
<div id="content" style="display: none">
<div id="framediv">
<iframe id="testing_frame"></iframe>
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
SimpleTest.waitForExplicitFinish();
SpecialPowers.setBoolPref("security.webauth.u2f", true);
SpecialPowers.setBoolPref("security.webauth.u2f.softtoken", false);
SpecialPowers.setBoolPref("security.webauth.u2f.usbtoken", false);
var challenge = new Uint8Array(16);
window.crypto.getRandomValues(challenge);
SpecialPowers.pushPrefEnv({"set": [["security.webauth.u2f", true],
["security.webauth.u2f_enable_softtoken", false],
["security.webauth.u2f_enable_usbtoken", false]]},
function() {
onmessage = function(event) {
//event.data is the response.errorCode
isnot(event.data, 0, "The registration should be rejected.");
SimpleTest.finish();
}
var regRequest = {
version: "U2F_V2",
challenge: bytesToBase64UrlSafe(challenge),
};
u2f.register(window.location.origin, [regRequest], [], function (regResponse) {
isnot(regResponse.errorCode, 0, "The registration should be rejected.");
SimpleTest.finish();
document.getElementById('testing_frame').src = 'frame_no_token.html';
});
</script>
</pre>
</body>
</html>
+37 -33
View File
@@ -13,42 +13,46 @@
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
SimpleTest.waitForExplicitFinish();
SpecialPowers.setBoolPref("security.webauth.u2f", true);
SpecialPowers.setBoolPref("security.webauth.u2f.softtoken", true);
SpecialPowers.setBoolPref("security.webauth.u2f.usbtoken", false);
// Example from:
// https://fidoalliance.org/specs/fido-u2f-v1.0-nfc-bt-amendment-20150514/fido-u2f-raw-message-formats.html
//
// Run this example from the console to check that the u2futil methods work
var pubKey = hexDecode("04d368f1b665bade3c33a20f1e429c7750d5033660c019119d29aa4ba7abc04aa7c80a46bbe11ca8cb5674d74f31f8a903f6bad105fb6ab74aefef4db8b0025e1d");
var appId = "https://gstatic.com/securitykey/a/example.com";
var clientData = string2buffer('{"typ":"navigator.id.getAssertion","challenge":"opsXqUifDriAAmWclinfbS0e-USY0CgyJHe_Otd7z8o","cid_pubkey":{"kty":"EC","crv":"P-256","x":"HzQwlfXX7Q4S5MtCCnZUNBw3RMzPO9tOyWjBqRl4tJ8","y":"XVguGFLIZx1fXg3wNqfdbn75hi4-_7-BxhMljw42Ht4"},"origin":"http://example.com"}');
var presenceAndCounter = hexDecode("0100000001");
var signature = hexDecode("304402204b5f0cd17534cedd8c34ee09570ef542a353df4436030ce43d406de870b847780220267bb998fac9b7266eb60e7cb0b5eabdfd5ba9614f53c7b22272ec10047a923f");
SpecialPowers.pushPrefEnv({"set": [["security.webauth.u2f", true],
["security.webauth.u2f_enable_softtoken", true],
["security.webauth.u2f_enable_usbtoken", false]]},
function() {
// Example from:
// https://fidoalliance.org/specs/fido-u2f-v1.0-nfc-bt-amendment-20150514/fido-u2f-raw-message-formats.html
//
// Run this example from the console to check that the u2futil methods work
var pubKey = hexDecode("04d368f1b665bade3c33a20f1e429c7750d5033660c019119d29aa4ba7abc04aa7c80a46bbe11ca8cb5674d74f31f8a903f6bad105fb6ab74aefef4db8b0025e1d");
var appId = "https://gstatic.com/securitykey/a/example.com";
var clientData = string2buffer('{"typ":"navigator.id.getAssertion","challenge":"opsXqUifDriAAmWclinfbS0e-USY0CgyJHe_Otd7z8o","cid_pubkey":{"kty":"EC","crv":"P-256","x":"HzQwlfXX7Q4S5MtCCnZUNBw3RMzPO9tOyWjBqRl4tJ8","y":"XVguGFLIZx1fXg3wNqfdbn75hi4-_7-BxhMljw42Ht4"},"origin":"http://example.com"}');
var presenceAndCounter = hexDecode("0100000001");
var signature = hexDecode("304402204b5f0cd17534cedd8c34ee09570ef542a353df4436030ce43d406de870b847780220267bb998fac9b7266eb60e7cb0b5eabdfd5ba9614f53c7b22272ec10047a923f");
// Import the key
// Assemble the client data
// Verify
Promise.all([
importPublicKey(pubKey),
assembleSignedData(appId, presenceAndCounter, clientData)
])
.then(function(results) {
var importedKey = results[0];
var signedData = new Uint8Array(results[1]);
return verifySignature(importedKey, signedData, signature);
})
.then(function(verified) {
console.log("verified:", verified);
ok(true, "Utility methods work")
SimpleTest.finish();
})
.catch(function(err) {
console.log("error:", err);
ok(false, "Utility methods failed")
SimpleTest.finish();
// Import the key
// Assemble the client data
// Verify
Promise.all([
importPublicKey(pubKey),
deriveAppAndChallengeParam(appId, clientData)
])
.then(function(results) {
var importedKey = results[0];
var params = results[1];
var signedData = new Uint8Array(assembleSignedData(params.appParam, presenceAndCounter, params.challengeParam));
return verifySignature(importedKey, signedData, signature);
})
.then(function(verified) {
console.log("verified:", verified);
ok(true, "Utility methods work")
SimpleTest.finish();
})
.catch(function(err) {
console.log("error:", err);
ok(false, "Utility methods failed")
SimpleTest.finish();
});
});
</script>
+24 -10
View File
@@ -98,24 +98,38 @@ function importPublicKey(keyBytes) {
return crypto.subtle.importKey("jwk", jwk, {name: "ECDSA", namedCurve: "P-256"}, true, ["verify"])
}
function assembleSignedData(appId, presenceAndCounter, clientData) {
function deriveAppAndChallengeParam(appId, clientData) {
var appIdBuf = string2buffer(appId);
return Promise.all([
crypto.subtle.digest("SHA-256", appIdBuf),
crypto.subtle.digest("SHA-256", clientData)
])
.then(function(digests) {
var appParam = new Uint8Array(digests[0]);
var clientParam = new Uint8Array(digests[1]);
var signedData = new Uint8Array(32 + 1 + 4 + 32);
appParam.map((x, i) => signedData[0 + i] = x);
presenceAndCounter.map((x, i) => signedData[32 + i] = x);
clientParam.map((x, i) => signedData[37 + i] = x);
return signedData;
return {
appParam: new Uint8Array(digests[0]),
challengeParam: new Uint8Array(digests[1]),
};
});
}
function assembleSignedData(appParam, presenceAndCounter, challengeParam) {
var signedData = new Uint8Array(32 + 1 + 4 + 32);
appParam.map((x, i) => signedData[0 + i] = x);
presenceAndCounter.map((x, i) => signedData[32 + i] = x);
challengeParam.map((x, i) => signedData[37 + i] = x);
return signedData;
}
function assembleRegistrationSignedData(appParam, challengeParam, keyHandle, pubKey) {
var signedData = new Uint8Array(1 + 32 + 32 + keyHandle.length + 65);
signedData[0] = 0x00;
appParam.map((x, i) => signedData[1 + i] = x);
challengeParam.map((x, i) => signedData[33 + i] = x);
keyHandle.map((x, i) => signedData[65 + i] = x);
pubKey.map((x, i) => signedData[65 + keyHandle.length + i] = x);
return signedData;
}
function verifySignature(key, data, derSig) {
if (derSig.byteLength < 70) {
console.log("bad sig: " + hexEncode(derSig))
@@ -141,4 +155,4 @@ function verifySignature(key, data, derSig) {
var alg = {name: "ECDSA", hash: "SHA-256"};
return crypto.subtle.verify(alg, key, sig, data);
}
}
+3
View File
@@ -114,6 +114,9 @@ partial interface Directory {
*/
[Throws]
Promise<sequence<(File or Directory)>> getFilesAndDirectories();
[Throws]
Promise<sequence<File>> getFiles(optional boolean recursiveFlag = false);
};
enum CreateIfExistsMode { "replace", "fail" };
+1 -3
View File
@@ -11,8 +11,6 @@
*/
interface FileList {
[Throws]
getter (File or Directory)? item(unsigned long index);
getter File? item(unsigned long index);
readonly attribute unsigned long length;
};
+3 -4
View File
@@ -49,7 +49,6 @@
#include "rdf.h"
#include "nsContentUtils.h"
#include "nsIDateTimeFormat.h"
#include "nsDateTimeFormatCID.h"
#include "nsIScriptableDateFormat.h"
#include "nsICollation.h"
#include "nsCollationCID.h"
@@ -103,9 +102,9 @@ nsXULContentUtils::Init()
#undef XUL_RESOURCE
#undef XUL_LITERAL
rv = CallCreateInstance(NS_DATETIMEFORMAT_CONTRACTID, &gFormat);
if (NS_FAILED(rv)) {
return rv;
gFormat = nsIDateTimeFormat::Create().take();
if (!gFormat) {
return NS_ERROR_FAILURE;
}
return NS_OK;
+2 -2
View File
@@ -1187,7 +1187,7 @@ DefaultTooltipTextProvider::GetNodeText(nsIDOMNode* aNode, char16_t** aText,
NS_ENSURE_SUCCESS(rv, rv);
} else {
FileList* fl = static_cast<FileList*>(fileList.get());
fl->UnsafeItem(0).GetAsFile()->GetName(outText);
fl->Item(0)->GetName(outText);
// For UX and performance (jank) reasons we cap the number of
// files that we list in the tooltip to 20 plus a "and xxx more"
@@ -1196,7 +1196,7 @@ DefaultTooltipTextProvider::GetNodeText(nsIDOMNode* aNode, char16_t** aText,
uint32_t count = std::min(listLength, TRUNCATED_FILE_COUNT);
for (uint32_t i = 1; i < count; ++i) {
nsString fileName;
fl->UnsafeItem(i).GetAsFile()->GetName(fileName);
fl->Item(i)->GetName(fileName);
outText.Append(NS_LITERAL_STRING("\n"));
outText.Append(fileName);
}
+9
View File
@@ -955,6 +955,15 @@ public:
Point aOffset,
const DrawOptions &aOptions = DrawOptions()) = 0;
/**
* Draw aSurface using the 3D transform aMatrix. The DrawTarget's transform
* and clip are applied after the 3D transform.
*
* If the transform fails (i.e. because aMatrix is singular), false is returned and nothing is drawn.
*/
virtual bool Draw3DTransformedSurface(SourceSurface* aSurface,
const Matrix4x4& aMatrix);
/**
* Push a clip to the DrawTarget.
*
+287 -14
View File
@@ -39,6 +39,9 @@
#include "cairo-win32.h"
#endif
#define PIXMAN_DONT_DEFINE_STDINT
#include "pixman.h"
#include <algorithm>
// 2^23
@@ -614,7 +617,8 @@ DrawTargetCairo::~DrawTargetCairo()
bool
DrawTargetCairo::IsValid() const
{
return mSurface && !cairo_surface_status(mSurface);
return mSurface && !cairo_surface_status(mSurface) &&
mContext && !cairo_surface_status(cairo_get_group_target(mContext));
}
DrawTargetType
@@ -717,10 +721,19 @@ DrawTargetCairo::LockBits(uint8_t** aData, IntSize* aSize,
int32_t* aStride, SurfaceFormat* aFormat,
IntPoint* aOrigin)
{
cairo_surface_t* surf = cairo_get_group_target(mContext);
cairo_surface_t* target = cairo_get_group_target(mContext);
cairo_surface_t* surf = target;
#ifdef CAIRO_HAS_WIN32_SURFACE
if (cairo_surface_get_type(surf) == CAIRO_SURFACE_TYPE_WIN32) {
cairo_surface_t* imgsurf = cairo_win32_surface_get_image(surf);
if (imgsurf) {
surf = imgsurf;
}
}
#endif
if (cairo_surface_get_type(surf) == CAIRO_SURFACE_TYPE_IMAGE) {
PointDouble offset;
cairo_surface_get_device_offset(surf, &offset.x, &offset.y);
cairo_surface_get_device_offset(target, &offset.x, &offset.y);
// verify the device offset can be converted to integers suitable for a bounds rect
IntPoint origin(int32_t(-offset.x), int32_t(-offset.y));
if (-PointDouble(origin) != offset ||
@@ -752,6 +765,14 @@ DrawTargetCairo::ReleaseBits(uint8_t* aData)
MOZ_ASSERT(mLockedBits == aData);
mLockedBits = nullptr;
cairo_surface_t* surf = cairo_get_group_target(mContext);
#ifdef CAIRO_HAS_WIN32_SURFACE
if (cairo_surface_get_type(surf) == CAIRO_SURFACE_TYPE_WIN32) {
cairo_surface_t* imgsurf = cairo_win32_surface_get_image(surf);
if (imgsurf) {
cairo_surface_mark_dirty(imgsurf);
}
}
#endif
cairo_surface_mark_dirty(surf);
}
@@ -808,12 +829,12 @@ DrawTargetCairo::DrawSurface(SourceSurface *aSurface,
const DrawSurfaceOptions &aSurfOptions,
const DrawOptions &aOptions)
{
if (mTransformSingular) {
if (mTransformSingular || aDest.IsEmpty()) {
return;
}
if (!IsValid() || !aSurface) {
gfxCriticalNote << "DrawSurface with bad surface " << cairo_surface_status(mSurface);
gfxCriticalNote << "DrawSurface with bad surface " << cairo_surface_status(cairo_get_group_target(mContext));
return;
}
@@ -1267,7 +1288,7 @@ DrawTargetCairo::SetPermitSubpixelAA(bool aPermitSubpixelAA)
{
DrawTarget::SetPermitSubpixelAA(aPermitSubpixelAA);
#ifdef MOZ_TREE_CAIRO
cairo_surface_set_subpixel_antialiasing(mSurface,
cairo_surface_set_subpixel_antialiasing(cairo_get_group_target(mContext),
aPermitSubpixelAA ? CAIRO_SUBPIXEL_ANTIALIASING_ENABLED : CAIRO_SUBPIXEL_ANTIALIASING_DISABLED);
#endif
}
@@ -1284,7 +1305,12 @@ DrawTargetCairo::FillGlyphs(ScaledFont *aFont,
}
if (!IsValid()) {
gfxDebug() << "FillGlyphs bad surface " << cairo_surface_status(mSurface);
gfxDebug() << "FillGlyphs bad surface " << cairo_surface_status(cairo_get_group_target(mContext));
return;
}
if (!aFont) {
gfxDevCrash(LogReason::InvalidFont) << "Invalid scaled font";
return;
}
@@ -1322,8 +1348,8 @@ DrawTargetCairo::FillGlyphs(ScaledFont *aFont,
cairo_show_glyphs(mContext, &glyphs[0], aBuffer.mNumGlyphs);
if (mSurface && cairo_surface_status(mSurface)) {
gfxDebug() << "Ending FillGlyphs with a bad surface " << cairo_surface_status(mSurface);
if (cairo_surface_status(cairo_get_group_target(mContext))) {
gfxDebug() << "Ending FillGlyphs with a bad surface " << cairo_surface_status(cairo_get_group_target(mContext));
}
}
@@ -1736,16 +1762,25 @@ DrawTargetCairo::CreateSourceSurfaceFromNativeSurface(const NativeSurface &aSurf
already_AddRefed<DrawTarget>
DrawTargetCairo::CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFormat) const
{
if (cairo_surface_status(mSurface)) {
if (cairo_surface_status(cairo_get_group_target(mContext))) {
RefPtr<DrawTargetCairo> target = new DrawTargetCairo();
if (target->Init(aSize, aFormat)) {
return target.forget();
}
}
cairo_surface_t* similar = cairo_surface_create_similar(mSurface,
GfxFormatToCairoContent(aFormat),
aSize.width, aSize.height);
cairo_surface_t* similar;
#ifdef CAIRO_HAS_WIN32_SURFACE
if (cairo_surface_get_type(mSurface) == CAIRO_SURFACE_TYPE_WIN32) {
similar = cairo_win32_surface_create_with_dib(GfxFormatToCairoFormat(aFormat),
aSize.width, aSize.height);
} else
#endif
{
similar = cairo_surface_create_similar(mSurface,
GfxFormatToCairoContent(aFormat),
aSize.width, aSize.height);
}
if (!cairo_surface_status(similar)) {
RefPtr<DrawTargetCairo> target = new DrawTargetCairo();
@@ -1754,7 +1789,7 @@ DrawTargetCairo::CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFo
}
}
gfxCriticalError(CriticalLog::DefaultOptions(Factory::ReasonableSurfaceSize(aSize))) << "Failed to create similar cairo surface! Size: " << aSize << " Status: " << cairo_surface_status(similar) << cairo_surface_status(mSurface) << " format " << (int)aFormat;
gfxCriticalError(CriticalLog::DefaultOptions(Factory::ReasonableSurfaceSize(aSize))) << "Failed to create similar cairo surface! Size: " << aSize << " Status: " << cairo_surface_status(similar) << cairo_surface_status(cairo_get_group_target(mContext)) << " format " << (int)aFormat;
return nullptr;
}
@@ -1840,6 +1875,244 @@ DrawTargetCairo::CreateShadowDrawTarget(const IntSize &aSize, SurfaceFormat aFor
return nullptr;
}
static inline pixman_format_code_t
GfxFormatToPixmanFormat(SurfaceFormat aFormat)
{
switch (aFormat) {
case SurfaceFormat::A8R8G8B8_UINT32:
return PIXMAN_a8r8g8b8;
case SurfaceFormat::X8R8G8B8_UINT32:
return PIXMAN_x8r8g8b8;
case SurfaceFormat::R5G6B5_UINT16:
return PIXMAN_r5g6b5;
case SurfaceFormat::A8:
return PIXMAN_a8;
default:
// Allow both BGRA and ARGB formats to be passed through unmodified,
// even though even though we are actually rendering to A8R8G8B8_UINT32.
if (aFormat == SurfaceFormat::B8G8R8A8 ||
aFormat == SurfaceFormat::A8R8G8B8) {
return PIXMAN_a8r8g8b8;
}
return (pixman_format_code_t)0;
}
}
static inline bool
GfxMatrixToPixmanTransform(const Matrix4x4 &aMatrix, pixman_transform* aResult)
{
pixman_f_transform fTransform = {{
{ aMatrix._11, aMatrix._21, aMatrix._41 },
{ aMatrix._12, aMatrix._22, aMatrix._42 },
{ aMatrix._14, aMatrix._24, aMatrix._44 }
}};
return pixman_transform_from_pixman_f_transform(aResult, &fTransform);
}
#ifndef USE_SKIA
bool
DrawTarget::Draw3DTransformedSurface(SourceSurface* aSurface, const Matrix4x4& aMatrix)
{
// Composite the 3D transform with the DT's transform.
Matrix4x4 fullMat = aMatrix * Matrix4x4::From2D(mTransform);
// Transform the surface bounds and clip to this DT.
IntRect xformBounds =
RoundedOut(
fullMat.TransformAndClipBounds(Rect(Point(0, 0), Size(aSurface->GetSize())),
Rect(Point(0, 0), Size(GetSize()))));
if (xformBounds.IsEmpty()) {
return true;
}
// Offset the matrix by the transformed origin.
fullMat.PostTranslate(-xformBounds.x, -xformBounds.y, 0);
// Invert the matrix into a pattern matrix for pixman.
if (!fullMat.Invert()) {
return false;
}
pixman_transform xform;
if (!GfxMatrixToPixmanTransform(fullMat, &xform)) {
return false;
}
// Read in the source data.
RefPtr<DataSourceSurface> srcSurf = aSurface->GetDataSurface();
pixman_format_code_t srcFormat = GfxFormatToPixmanFormat(srcSurf->GetFormat());
if (!srcFormat) {
return false;
}
DataSourceSurface::ScopedMap srcMap(srcSurf, DataSourceSurface::READ);
if (!srcMap.IsMapped()) {
return false;
}
// Set up an intermediate destination surface only the size of the transformed bounds.
// Try to pass through the source's format unmodified in both the BGRA and ARGB cases.
RefPtr<DataSourceSurface> dstSurf =
Factory::CreateDataSourceSurface(xformBounds.Size(),
srcFormat == PIXMAN_a8r8g8b8 ?
srcSurf->GetFormat() : SurfaceFormat::A8R8G8B8_UINT32);
if (!dstSurf) {
return false;
}
// Wrap the surfaces in pixman images and do the transform.
pixman_image_t* dst =
pixman_image_create_bits(PIXMAN_a8r8g8b8,
xformBounds.width, xformBounds.height,
(uint32_t*)dstSurf->GetData(), dstSurf->Stride());
pixman_image_t* src =
pixman_image_create_bits(srcFormat,
srcSurf->GetSize().width, srcSurf->GetSize().height,
(uint32_t*)srcMap.GetData(), srcMap.GetStride());
MOZ_ASSERT(src && dst, "Failed to create pixman images?");
pixman_image_set_filter(src, PIXMAN_FILTER_BILINEAR, nullptr, 0);
pixman_image_set_transform(src, &xform);
pixman_image_composite32(PIXMAN_OP_SRC,
src, nullptr, dst,
0, 0, 0, 0, 0, 0,
xformBounds.width, xformBounds.height);
pixman_image_unref(dst);
pixman_image_unref(src);
// Temporarily reset the DT's transform, since it has already been composed above.
Matrix origTransform = mTransform;
SetTransform(Matrix());
// Draw the transformed surface within the transformed bounds.
DrawSurface(dstSurf, Rect(xformBounds), Rect(Point(0, 0), Size(xformBounds.Size())));
SetTransform(origTransform);
return true;
}
#endif
#ifdef CAIRO_HAS_XLIB_SURFACE
static bool gXRenderInitialized = false;
static bool gXRenderHasTransform = false;
static bool
SupportsXRender(cairo_surface_t* surface)
{
if (!surface ||
cairo_surface_get_type(surface) != CAIRO_SURFACE_TYPE_XLIB ||
!cairo_xlib_surface_get_xrender_format(surface)) {
return false;
}
if (gXRenderInitialized) {
return true;
}
gXRenderInitialized = true;
cairo_device_t* device = cairo_surface_get_device(surface);
if (cairo_device_acquire(device) != CAIRO_STATUS_SUCCESS) {
return false;
}
Display* display = cairo_xlib_surface_get_display(surface);
int major, minor;
if (XRenderQueryVersion(display, &major, &minor)) {
if (major > 0 || (major == 0 && minor >= 6)) {
gXRenderHasTransform = true;
}
}
cairo_device_release(device);
return true;
}
#endif
bool
DrawTargetCairo::Draw3DTransformedSurface(SourceSurface* aSurface, const Matrix4x4& aMatrix)
{
#if CAIRO_HAS_XLIB_SURFACE
cairo_surface_t* srcSurf =
aSurface->GetType() == SurfaceType::CAIRO ?
static_cast<SourceSurfaceCairo*>(aSurface)->GetSurface() : nullptr;
if (!SupportsXRender(srcSurf) || !gXRenderHasTransform) {
return DrawTarget::Draw3DTransformedSurface(aSurface, aMatrix);
}
Matrix4x4 fullMat = aMatrix * Matrix4x4::From2D(mTransform);
IntRect xformBounds =
RoundedOut(
fullMat.TransformAndClipBounds(Rect(Point(0, 0), Size(aSurface->GetSize())),
Rect(Point(0, 0), Size(GetSize()))));
if (xformBounds.IsEmpty()) {
return true;
}
fullMat.PostTranslate(-xformBounds.x, -xformBounds.y, 0);
if (!fullMat.Invert()) {
return false;
}
pixman_transform xform;
if (!GfxMatrixToPixmanTransform(fullMat, &xform)) {
return false;
}
cairo_surface_t* xformSurf =
cairo_surface_create_similar(srcSurf, CAIRO_CONTENT_COLOR_ALPHA,
xformBounds.width, xformBounds.height);
if (!SupportsXRender(xformSurf)) {
cairo_surface_destroy(xformSurf);
return false;
}
cairo_device_t* device = cairo_surface_get_device(xformSurf);
if (cairo_device_acquire(device) != CAIRO_STATUS_SUCCESS) {
cairo_surface_destroy(xformSurf);
return false;
}
Display* display = cairo_xlib_surface_get_display(xformSurf);
Picture srcPict = XRenderCreatePicture(display,
cairo_xlib_surface_get_drawable(srcSurf),
cairo_xlib_surface_get_xrender_format(srcSurf),
0, nullptr);
XRenderSetPictureFilter(display, srcPict, FilterBilinear, nullptr, 0);
XRenderSetPictureTransform(display, srcPict, (XTransform*)&xform);
Picture dstPict = XRenderCreatePicture(display,
cairo_xlib_surface_get_drawable(xformSurf),
cairo_xlib_surface_get_xrender_format(xformSurf),
0, nullptr);
XRenderComposite(display, PictOpSrc,
srcPict, None, dstPict,
0, 0, 0, 0, 0, 0,
xformBounds.width, xformBounds.height);
XRenderFreePicture(display, srcPict);
XRenderFreePicture(display, dstPict);
cairo_device_release(device);
cairo_surface_mark_dirty(xformSurf);
AutoPrepareForDrawing(this, mContext);
cairo_identity_matrix(mContext);
cairo_set_operator(mContext, CAIRO_OPERATOR_OVER);
cairo_set_antialias(mContext, CAIRO_ANTIALIAS_DEFAULT);
cairo_set_source_surface(mContext, xformSurf, xformBounds.x, xformBounds.y);
cairo_new_path(mContext);
cairo_rectangle(mContext, xformBounds.x, xformBounds.y, xformBounds.width, xformBounds.height);
cairo_fill(mContext);
cairo_surface_destroy(xformSurf);
return true;
#else
return DrawTarget::Draw3DTransformedSurface(aSurface, aMatrix);
#endif
}
bool
DrawTargetCairo::Init(cairo_surface_t* aSurface, const IntSize& aSize, SurfaceFormat* aFormat)
{
+3
View File
@@ -134,6 +134,9 @@ public:
Point aOffset,
const DrawOptions &aOptions = DrawOptions()) override;
virtual bool Draw3DTransformedSurface(SourceSurface* aSurface,
const Matrix4x4& aMatrix) override;
virtual void PushClip(const Path *aPath) override;
virtual void PushClipRect(const Rect &aRect) override;
virtual void PopClip() override;
+94 -20
View File
@@ -40,6 +40,7 @@ ID2D1Factory1 *D2DFactory1()
DrawTargetD2D1::DrawTargetD2D1()
: mPushedLayers(1)
, mUsedCommandListsSincePurge(0)
{
}
@@ -87,7 +88,7 @@ DrawTargetD2D1::Snapshot()
}
PopAllClips();
mDC->Flush();
Flush();
mSnapshot = new SourceSurfaceD2D1(mBitmap, mDC, mFormat, mSize, this);
@@ -95,10 +96,28 @@ DrawTargetD2D1::Snapshot()
return snapshot.forget();
}
// Command lists are kept around by device contexts until EndDraw is called,
// this can cause issues with memory usage (see bug 1238328). EndDraw/BeginDraw
// are expensive though, especially relatively when little work is done, so
// we try to reduce the amount of times we execute these purges.
static const uint32_t kPushedLayersBeforePurge = 25;
void
DrawTargetD2D1::Flush()
{
mDC->Flush();
if ((mUsedCommandListsSincePurge >= kPushedLayersBeforePurge) &&
mPushedLayers.size() == 1) {
// It's important to pop all clips as otherwise layers can forget about
// their clip when doing an EndDraw. When we have layers pushed we cannot
// easily pop all underlying clips to delay the purge until we have no
// layers pushed.
PopAllClips();
mUsedCommandListsSincePurge = 0;
mDC->EndDraw();
mDC->BeginDraw();
} else {
mDC->Flush();
}
// We no longer depend on any target.
for (TargetSet::iterator iter = mDependingOnTargets.begin();
@@ -263,6 +282,7 @@ DrawTargetD2D1::ClearRect(const Rect &aRect)
}
RefPtr<ID2D1CommandList> list;
mUsedCommandListsSincePurge++;
mDC->CreateCommandList(getter_AddRefs(list));
mDC->SetTarget(list);
@@ -791,6 +811,8 @@ DrawTargetD2D1::PushLayer(bool aOpaque, Float aOpacity, SourceSurface* aMask,
mPushedLayers.push_back(pushedLayer);
mDC->SetTarget(CurrentTarget());
mUsedCommandListsSincePurge++;
}
void
@@ -1071,7 +1093,7 @@ DrawTargetD2D1::factory()
getter_AddRefs(factory));
if (FAILED(hr) || !factory) {
gfxWarning() << "Failed to create Direct2D factory.";
gfxCriticalNote << "Failed to create a D2D1 content device: " << hexa(hr);
return nullptr;
}
@@ -1149,12 +1171,24 @@ DrawTargetD2D1::MarkChanged()
}
}
bool
DrawTargetD2D1::ShouldClipTemporarySurfaceDrawing(CompositionOp aOp,
const Pattern& aPattern,
bool aClipIsComplex)
{
bool patternSupported = IsPatternSupportedByD2D(aPattern);
return patternSupported && !CurrentLayer().mIsOpaque && D2DSupportsCompositeMode(aOp) &&
IsOperatorBoundByMask(aOp) && aClipIsComplex;
}
void
DrawTargetD2D1::PrepareForDrawing(CompositionOp aOp, const Pattern &aPattern)
{
MarkChanged();
if (D2DSupportsPrimitiveBlendMode(aOp) && IsPatternSupportedByD2D(aPattern)) {
bool patternSupported = IsPatternSupportedByD2D(aPattern);
if (D2DSupportsPrimitiveBlendMode(aOp) && patternSupported) {
// It's important to do this before FlushTransformToDC! As this will cause
// the transform to become dirty.
PushAllClips();
@@ -1167,12 +1201,24 @@ DrawTargetD2D1::PrepareForDrawing(CompositionOp aOp, const Pattern &aPattern)
return;
}
PopAllClips();
mDC->CreateCommandList(getter_AddRefs(mCommandList));
HRESULT result = mDC->CreateCommandList(getter_AddRefs(mCommandList));
mDC->SetTarget(mCommandList);
mUsedCommandListsSincePurge++;
// This is where we should have a valid command list. If we don't, something is
// wrong, and it's likely an OOM.
if (!mCommandList) {
gfxDevCrash(LogReason::InvalidCommandList) << "Invalid D2D1.1 command list on creation " << mUsedCommandListsSincePurge << ", " << gfx::hexa(result);
}
D2D1_RECT_F rect;
bool isAligned;
bool clipIsComplex = CurrentLayer().mPushedClips.size() && !GetDeviceSpaceClipRect(rect, isAligned);
if (ShouldClipTemporarySurfaceDrawing(aOp, aPattern, clipIsComplex)) {
PushClipsToDC(mDC);
}
PushAllClips();
FlushTransformToDC();
}
@@ -1187,9 +1233,19 @@ DrawTargetD2D1::FinalizeDrawing(CompositionOp aOp, const Pattern &aPattern)
return;
}
PopAllClips();
D2D1_RECT_F rect;
bool isAligned;
bool clipIsComplex = CurrentLayer().mPushedClips.size() && !GetDeviceSpaceClipRect(rect, isAligned);
if (ShouldClipTemporarySurfaceDrawing(aOp, aPattern, clipIsComplex)) {
PopClipsFromDC(mDC);
}
mDC->SetTarget(CurrentTarget());
if (!mCommandList) {
gfxDevCrash(LogReason::InvalidCommandList) << "Invalid D21.1 command list on finalize";
return;
}
mCommandList->Close();
RefPtr<ID2D1CommandList> source = mCommandList;
@@ -1200,17 +1256,12 @@ DrawTargetD2D1::FinalizeDrawing(CompositionOp aOp, const Pattern &aPattern)
if (patternSupported) {
if (D2DSupportsCompositeMode(aOp)) {
D2D1_RECT_F rect;
bool isAligned;
RefPtr<ID2D1Image> tmpImage;
bool clipIsComplex = CurrentLayer().mPushedClips.size() && !GetDeviceSpaceClipRect(rect, isAligned);
if (clipIsComplex) {
PopAllClips();
if (!IsOperatorBoundByMask(aOp)) {
tmpImage = GetImageForLayerContent();
}
} else {
PushAllClips();
}
mDC->DrawImage(source, D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR, D2DCompositionMode(aOp));
@@ -1241,8 +1292,6 @@ DrawTargetD2D1::FinalizeDrawing(CompositionOp aOp, const Pattern &aPattern)
blendEffect->SetInput(1, source);
blendEffect->SetValue(D2D1_BLEND_PROP_MODE, D2DBlendMode(aOp));
PushAllClips();
mDC->DrawImage(blendEffect, D2D1_INTERPOLATION_MODE_NEAREST_NEIGHBOR, D2D1_COMPOSITE_MODE_BOUNDED_SOURCE_COPY);
return;
}
@@ -1253,8 +1302,6 @@ DrawTargetD2D1::FinalizeDrawing(CompositionOp aOp, const Pattern &aPattern)
return;
}
PushAllClips();
RefPtr<ID2D1Effect> radialGradientEffect;
HRESULT hr = mDC->CreateEffect(CLSID_RadialGradientEffect, getter_AddRefs(radialGradientEffect));
@@ -1337,6 +1384,8 @@ DrawTargetD2D1::GetImageForLayerContent()
tmpBitmap->CopyFromBitmap(nullptr, mBitmap, nullptr);
return tmpBitmap.forget();
} else {
PopAllClips();
RefPtr<ID2D1CommandList> list = CurrentLayer().mCurrentList;
mDC->CreateCommandList(getter_AddRefs(CurrentLayer().mCurrentList));
mDC->SetTarget(CurrentTarget());
@@ -1345,6 +1394,8 @@ DrawTargetD2D1::GetImageForLayerContent()
DCCommandSink sink(mDC);
list->Stream(&sink);
PushAllClips();
return list.forget();
}
}
@@ -1607,6 +1658,29 @@ DrawTargetD2D1::CreateBrushForPattern(const Pattern &aPattern, Float aAlpha)
RefPtr<ID2D1Image> image = GetImageForSurface(pat->mSurface, mat, pat->mExtendMode, !pat->mSamplingRect.IsEmpty() ? &pat->mSamplingRect : nullptr);
if (pat->mSurface->GetFormat() == SurfaceFormat::A8) {
// See bug 1251431, at least FillOpacityMask does not appear to allow a source bitmapbrush
// with source format A8. This creates a BGRA surface with the same alpha values that
// the A8 surface has.
RefPtr<ID2D1Bitmap> bitmap;
image->QueryInterface((ID2D1Bitmap**)getter_AddRefs(bitmap));
if (bitmap) {
RefPtr<ID2D1Image> oldTarget;
RefPtr<ID2D1Bitmap1> tmpBitmap;
mDC->CreateBitmap(D2D1::SizeU(pat->mSurface->GetSize().width, pat->mSurface->GetSize().height), nullptr, 0,
D2D1::BitmapProperties1(D2D1_BITMAP_OPTIONS_TARGET, D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED)),
getter_AddRefs(tmpBitmap));
mDC->GetTarget(getter_AddRefs(oldTarget));
mDC->SetTarget(tmpBitmap);
RefPtr<ID2D1SolidColorBrush> brush;
mDC->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::White), getter_AddRefs(brush));
mDC->FillOpacityMask(bitmap, brush);
mDC->SetTarget(oldTarget);
image = tmpBitmap;
}
}
if (!image) {
return CreateTransparentBlackBrush();
}
@@ -1740,7 +1814,7 @@ DrawTargetD2D1::PushD2DLayer(ID2D1DeviceContext *aDC, ID2D1Geometry *aGeometry,
{
D2D1_LAYER_OPTIONS1 options = D2D1_LAYER_OPTIONS1_NONE;
if (aDC->GetPixelFormat().alphaMode == D2D1_ALPHA_MODE_IGNORE || aForceIgnoreAlpha) {
if (CurrentLayer().mIsOpaque || aForceIgnoreAlpha) {
options = D2D1_LAYER_OPTIONS1_IGNORE_ALPHA | D2D1_LAYER_OPTIONS1_INITIALIZE_FROM_BACKGROUND;
}
+3
View File
@@ -164,6 +164,7 @@ private:
// This function will mark the surface as changing, and make sure any
// copy-on-write snapshots are notified.
void MarkChanged();
bool ShouldClipTemporarySurfaceDrawing(CompositionOp aOp, const Pattern& aPattern, bool aClipIsComplex);
void PrepareForDrawing(CompositionOp aOp, const Pattern &aPattern);
void FinalizeDrawing(CompositionOp aOp, const Pattern &aPattern);
void FlushTransformToDC() {
@@ -266,6 +267,8 @@ private:
// A list of targets which have this object in their mDependentTargets set
TargetSet mDependingOnTargets;
uint32_t mUsedCommandListsSincePurge;
static ID2D1Factory1 *mFactory;
static IDWriteFactory *mDWriteFactory;
};
+4
View File
@@ -389,6 +389,10 @@ DrawTargetRecording::FillGlyphs(ScaledFont *aFont,
{
EnsurePatternDependenciesStored(aPattern);
if (aFont->GetType() != FontType::DWRITE && aFont->GetType() != FontType::GDI) {
gfxDevCrash(LogReason::GetFontFileDataFailed) << "Unexpected ScaledFont type " << (int)aFont->GetType();
}
if (!aFont->GetUserData(reinterpret_cast<UserDataKey*>(mRecorder.get()))) {
// TODO support font in b2g recordings
#ifndef MOZ_WIDGET_GONK
+96
View File
@@ -669,6 +669,102 @@ DrawTargetSkia::MaskSurface(const Pattern &aSource,
mCanvas->drawBitmap(bitmap, aOffset.x, aOffset.y, &paint.mPaint);
}
bool
DrawTarget::Draw3DTransformedSurface(SourceSurface* aSurface, const Matrix4x4& aMatrix)
{
// Composite the 3D transform with the DT's transform.
Matrix4x4 fullMat = aMatrix * Matrix4x4::From2D(mTransform);
if (fullMat.IsSingular()) {
return false;
}
// Transform the surface bounds and clip to this DT.
IntRect xformBounds =
RoundedOut(
fullMat.TransformAndClipBounds(Rect(Point(0, 0), Size(aSurface->GetSize())),
Rect(Point(0, 0), Size(GetSize()))));
if (xformBounds.IsEmpty()) {
return true;
}
// Offset the matrix by the transformed origin.
fullMat.PostTranslate(-xformBounds.x, -xformBounds.y, 0);
// Read in the source data.
SkBitmap srcBitmap = GetBitmapForSurface(aSurface);
// Set up an intermediate destination surface only the size of the transformed bounds.
// Try to pass through the source's format unmodified in both the BGRA and ARGB cases.
RefPtr<DataSourceSurface> dstSurf =
Factory::CreateDataSourceSurface(xformBounds.Size(),
srcBitmap.alphaType() == kPremul_SkAlphaType ?
aSurface->GetFormat() : SurfaceFormat::A8R8G8B8_UINT32,
true);
if (!dstSurf) {
return false;
}
SkAutoTUnref<SkCanvas> dstCanvas(
SkCanvas::NewRasterDirect(
SkImageInfo::Make(xformBounds.width, xformBounds.height,
srcBitmap.alphaType() == kPremul_SkAlphaType ?
srcBitmap.colorType() : kBGRA_8888_SkColorType,
kPremul_SkAlphaType),
dstSurf->GetData(), dstSurf->Stride()));
if (!dstCanvas) {
return false;
}
// Do the transform.
SkPaint paint;
paint.setAntiAlias(true);
paint.setFilterQuality(kLow_SkFilterQuality);
paint.setXfermodeMode(SkXfermode::kSrc_Mode);
SkMatrix xform;
GfxMatrixToSkiaMatrix(fullMat, xform);
dstCanvas->setMatrix(xform);
dstCanvas->drawBitmap(srcBitmap, 0, 0, &paint);
dstCanvas->flush();
// Temporarily reset the DT's transform, since it has already been composed above.
Matrix origTransform = mTransform;
SetTransform(Matrix());
// Draw the transformed surface within the transformed bounds.
DrawSurface(dstSurf, Rect(xformBounds), Rect(Point(0, 0), Size(xformBounds.Size())));
SetTransform(origTransform);
return true;
}
bool
DrawTargetSkia::Draw3DTransformedSurface(SourceSurface* aSurface, const Matrix4x4& aMatrix)
{
if (aMatrix.IsSingular()) {
return false;
}
MarkChanged();
SkBitmap bitmap = GetBitmapForSurface(aSurface);
mCanvas->save();
SkPaint paint;
paint.setAntiAlias(true);
paint.setFilterQuality(kLow_SkFilterQuality);
SkMatrix xform;
GfxMatrixToSkiaMatrix(aMatrix, xform);
mCanvas->concat(xform);
mCanvas->drawBitmap(bitmap, 0, 0, &paint);
mCanvas->restore();
return true;
}
already_AddRefed<SourceSurface>
DrawTargetSkia::CreateSourceSurfaceFromData(unsigned char *aData,
const IntSize &aSize,
+2
View File
@@ -86,6 +86,8 @@ public:
SourceSurface *aMask,
Point aOffset,
const DrawOptions &aOptions = DrawOptions()) override;
virtual bool Draw3DTransformedSurface(SourceSurface* aSurface,
const Matrix4x4& aMatrix) override;
virtual void PushClip(const Path *aPath) override;
virtual void PushClipRect(const Rect& aRect) override;
virtual void PopClip() override;
+8
View File
@@ -105,6 +105,14 @@ GfxMatrixToSkiaMatrix(const Matrix& mat, SkMatrix& retval)
0, 0, SK_Scalar1);
}
static inline void
GfxMatrixToSkiaMatrix(const Matrix4x4& aMatrix, SkMatrix& aResult)
{
aResult.setAll(SkFloatToScalar(aMatrix._11), SkFloatToScalar(aMatrix._21), SkFloatToScalar(aMatrix._41),
SkFloatToScalar(aMatrix._12), SkFloatToScalar(aMatrix._22), SkFloatToScalar(aMatrix._42),
SkFloatToScalar(aMatrix._14), SkFloatToScalar(aMatrix._24), SkFloatToScalar(aMatrix._44));
}
static inline SkPaint::Cap
CapStyleToSkiaCap(CapStyle aCap)
{
+7
View File
@@ -131,6 +131,13 @@ enum class LogReason : int {
InvalidRect,
CannotDraw3D, // 20
IncompatibleBasicTexturedEffect,
InvalidFont,
PAllocTextureBackendMismatch,
GetFontFileDataFailed,
MessageChannelCloseFailure,
TextureAliveAfterShutdown,
InvalidContext,
InvalidCommandList,
// End
MustBeLessThanThis = 101,
};
+6 -4
View File
@@ -116,7 +116,7 @@ SFNTData::Create(const uint8_t *aFontData, uint32_t aDataLength)
// Check to see if this is a font collection.
if (aDataLength < sizeof(TTCHeader)) {
gfxWarning() << "Font data too short.";
gfxDevCrash(LogReason::GetFontFileDataFailed) << "Font data too short: length = " << aDataLength;
return nullptr;
}
@@ -124,7 +124,7 @@ SFNTData::Create(const uint8_t *aFontData, uint32_t aDataLength)
if (ttcHeader->ttcTag == TRUETYPE_TAG('t', 't', 'c', 'f')) {
uint32_t numFonts = ttcHeader->numFonts;
if (aDataLength < sizeof(TTCHeader) + (numFonts * sizeof(BigEndianUint32))) {
gfxWarning() << "Font data too short to contain full TTC Header.";
gfxDevCrash(LogReason::GetFontFileDataFailed) << "Font data too short to contain full TTC Header: numFonts = " << numFonts << "; length = " << aDataLength;
return nullptr;
}
@@ -134,6 +134,7 @@ SFNTData::Create(const uint8_t *aFontData, uint32_t aDataLength)
const BigEndianUint32* endOfOffsets = offset + numFonts;
while (offset != endOfOffsets) {
if (!sfntData->AddFont(aFontData, aDataLength, *offset)) {
gfxDevCrash(LogReason::GetFontFileDataFailed) << "Failed to add font data from TTC";
return nullptr;
}
++offset;
@@ -144,6 +145,7 @@ SFNTData::Create(const uint8_t *aFontData, uint32_t aDataLength)
UniquePtr<SFNTData> sfntData(new SFNTData);
if (!sfntData->AddFont(aFontData, aDataLength, 0)) {
gfxDevCrash(LogReason::GetFontFileDataFailed) << "Failed to add single font data";
return nullptr;
}
@@ -223,7 +225,7 @@ SFNTData::AddFont(const uint8_t *aFontData, uint32_t aDataLength,
{
uint32_t remainingLength = aDataLength - aOffset;
if (remainingLength < sizeof(OffsetTable)) {
gfxWarning() << "Font data too short to contain OffsetTable " << aOffset;
gfxCriticalError() << "Font data too short to contain OffsetTable: offset = " << aOffset << "; length = " << aDataLength;
return false;
}
@@ -231,7 +233,7 @@ SFNTData::AddFont(const uint8_t *aFontData, uint32_t aDataLength,
reinterpret_cast<const OffsetTable*>(aFontData + aOffset);
if (remainingLength <
sizeof(OffsetTable) + (offsetTable->numTables * sizeof(TableDirEntry))) {
gfxWarning() << "Font data too short to contain tables.";
gfxCriticalError() << "Font data too short to contain tables. numTables = " << offsetTable->numTables << "; offset = " << aOffset << "; length = " << aDataLength;
return false;
}
+4 -2
View File
@@ -40,6 +40,7 @@ ScaledFontWin::GetFontFileData(FontFileDataOutput aDataCallback, void *aBaton)
table = 0;
tableSize = ::GetFontData(dc.GetDC(), table, 0, nullptr, 0);
if (tableSize == GDI_ERROR) {
gfxDevCrash(LogReason::GetFontFileDataFailed) << "Failed to get font data from GDI";
return false;
}
}
@@ -49,6 +50,7 @@ ScaledFontWin::GetFontFileData(FontFileDataOutput aDataCallback, void *aBaton)
uint32_t sizeGot =
::GetFontData(dc.GetDC(), table, 0, fontData.get(), tableSize);
if (sizeGot != tableSize) {
gfxDevCrash(LogReason::GetFontFileDataFailed) << "GDI did not return enough data for font: wanted " << tableSize << ", got " << sizeGot;
return false;
}
@@ -58,7 +60,7 @@ ScaledFontWin::GetFontFileData(FontFileDataOutput aDataCallback, void *aBaton)
UniquePtr<SFNTData> sfntData = SFNTData::Create(fontData.get(),
tableSize);
if (!sfntData) {
gfxWarning() << "Failed to create SFNTData for GetFontFileData.";
gfxDevCrash(LogReason::GetFontFileDataFailed) << "Failed to create SFNTData for GetFontFileData.";
return false;
}
@@ -66,7 +68,7 @@ ScaledFontWin::GetFontFileData(FontFileDataOutput aDataCallback, void *aBaton)
// both 16 bit.
if (!sfntData->GetIndexForU16Name(
reinterpret_cast<char16_t*>(mLogFont.lfFaceName), &index)) {
gfxWarning() << "Failed to get index for face name.";
gfxDevCrash(LogReason::GetFontFileDataFailed) << "Failed to get index for face name.";
return false;
}
}
+1 -1
View File
@@ -163,7 +163,7 @@ GetAndInitDisplayForAccelANGLE(GLLibraryEGL& egl)
// D3D11 ANGLE only works with OMTC; there's a bug in the non-OMTC layer
// manager, and it's pointless to try to fix it. We also don't try
// D3D11 ANGLE if the layer manager is prefering D3D9 (hrm, do we care?)
if (gfxPrefs::LayersOffMainThreadCompositionEnabled() &&
if (!gfxPrefs::LayersOffMainThreadCompositionForceDisabled() &&
!gfxPrefs::LayersPreferD3D9())
{
if (gfxPrefs::WebGLANGLEForceD3D11())
+11 -2
View File
@@ -209,7 +209,11 @@ public:
}
}
ID3D11Device* device = gfxWindowsPlatform::GetPlatform()->GetD3D11Device();
RefPtr<ID3D11Device> device;
if (!gfxWindowsPlatform::GetPlatform()->GetD3D11Device(&device)) {
return;
}
device->GetImmediateContext(getter_AddRefs(mDeviceContext));
mTexture->GetDesc(&mDesc);
@@ -260,8 +264,13 @@ bool
SharedSurface_ANGLEShareHandle::ReadbackBySharedHandle(gfx::DataSourceSurface* out_surface)
{
MOZ_ASSERT(out_surface);
RefPtr<ID3D11Device> device;
if (!gfxWindowsPlatform::GetPlatform()->GetD3D11Device(&device)) {
return false;
}
RefPtr<ID3D11Texture2D> tex;
ID3D11Device* device = gfxWindowsPlatform::GetPlatform()->GetD3D11Device();
HRESULT hr = device->OpenSharedResource(mShareHandle,
__uuidof(ID3D11Texture2D),
(void**)(ID3D11Texture2D**)getter_AddRefs(tex));
+20 -15
View File
@@ -7,25 +7,25 @@
#ifndef __GFXMESSAGEUTILS_H__
#define __GFXMESSAGEUTILS_H__
#include "FilterSupport.h"
#include "FrameMetrics.h"
#include "ImageTypes.h"
#include "RegionBuilder.h"
#include "base/process_util.h"
#include "chrome/common/ipc_message_utils.h"
#include "ipc/IPCMessageUtils.h"
#include <stdint.h>
#include "mozilla/gfx/Matrix.h"
#include "gfxPoint.h"
#include "gfxRect.h"
#include "gfxTypes.h"
#include "ipc/IPCMessageUtils.h"
#include "mozilla/gfx/Matrix.h"
#include "mozilla/layers/AsyncDragMetrics.h"
#include "mozilla/layers/CompositorTypes.h"
#include "mozilla/layers/GeckoContentController.h"
#include "mozilla/layers/LayersTypes.h"
#include "nsRect.h"
#include "nsRegion.h"
#include "gfxTypes.h"
#include "mozilla/layers/AsyncDragMetrics.h"
#include "mozilla/layers/LayersTypes.h"
#include "mozilla/layers/CompositorTypes.h"
#include "ImageTypes.h"
#include "FrameMetrics.h"
#include "FilterSupport.h"
#include "mozilla/layers/GeckoContentController.h"
#include <stdint.h>
#ifdef _MSC_VER
#pragma warning( disable : 4800 )
@@ -367,6 +367,7 @@ struct RegionParamTraits
static void Write(Message* msg, const paramType& param)
{
for (auto iter = param.RectIter(); !iter.Done(); iter.Next()) {
const Rect& r = iter.Get();
MOZ_RELEASE_ASSERT(!r.IsEmpty());
@@ -379,12 +380,16 @@ struct RegionParamTraits
static bool Read(const Message* msg, void** iter, paramType* result)
{
RegionBuilder<Region> builder;
Rect rect;
while (ReadParam(msg, iter, &rect)) {
if (rect.IsEmpty())
if (rect.IsEmpty()) {
*result = builder.ToRegion();
return true;
result->Or(*result, rect);
}
builder.Or(rect);
}
return false;
}
};
+12
View File
@@ -398,6 +398,18 @@ Compositor::ComputeBackdropCopyRect(const gfx::Rect& aRect,
return result;
}
void
Compositor::SetInvalid()
{
mParent = nullptr;
}
bool
Compositor::IsValid() const
{
return !mParent;
}
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
void
Compositor::SetDispAcquireFence(Layer* aLayer, nsIWidget* aWidget)
+5
View File
@@ -518,6 +518,11 @@ public:
return mCompositeUntilTime;
}
// A stale Compositor has no CompositorBridgeParent; it will not process
// frames and should not be used.
void SetInvalid();
bool IsValid() const;
protected:
void DrawDiagnosticsInternal(DiagnosticFlags aFlags,
const gfx::Rect& aVisibleRect,
+4 -1
View File
@@ -63,9 +63,12 @@ enum class TextureFlags : uint32_t {
IMMEDIATE_UPLOAD = 1 << 10,
// The texture is part of a component-alpha pair
COMPONENT_ALPHA = 1 << 11,
// The texture is being allocated for a compositor that no longer exists.
// This flag is only used in the parent process.
INVALID_COMPOSITOR = 1 << 12,
// OR union of all valid bits
ALL_BITS = (1 << 12) - 1,
ALL_BITS = (1 << 13) - 1,
// the default flags
DEFAULT = NO_FLAGS
};

Some files were not shown because too many files have changed in this diff Show More