mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 14:30:27 +00:00
c7dc12e90f
- 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)
3442 lines
102 KiB
C++
3442 lines
102 KiB
C++
/* -*- 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 "mozilla/ArrayUtils.h"
|
|
#include "mozilla/EventDispatcher.h"
|
|
#include "mozilla/EventListenerManager.h"
|
|
#include "mozilla/EventStateManager.h"
|
|
#include "mozilla/EventStates.h"
|
|
#include "mozilla/MouseEvents.h"
|
|
#include "mozilla/Likely.h"
|
|
|
|
#include "nscore.h"
|
|
#include "nsGenericHTMLElement.h"
|
|
#include "nsAttrValueInlines.h"
|
|
#include "nsCOMPtr.h"
|
|
#include "nsIAtom.h"
|
|
#include "nsQueryObject.h"
|
|
#include "nsIContentInlines.h"
|
|
#include "nsIContentViewer.h"
|
|
#include "mozilla/css/Declaration.h"
|
|
#include "nsIDocument.h"
|
|
#include "nsIDocumentEncoder.h"
|
|
#include "nsIDOMHTMLDocument.h"
|
|
#include "nsIDOMAttr.h"
|
|
#include "nsIDOMDocumentFragment.h"
|
|
#include "nsIDOMHTMLElement.h"
|
|
#include "nsIDOMHTMLMenuElement.h"
|
|
#include "nsIDOMElementCSSInlineStyle.h"
|
|
#include "nsIDOMWindow.h"
|
|
#include "nsIDOMDocument.h"
|
|
#include "nsMappedAttributes.h"
|
|
#include "nsHTMLStyleSheet.h"
|
|
#include "nsIHTMLDocument.h"
|
|
#include "nsPIDOMWindow.h"
|
|
#include "nsIURL.h"
|
|
#include "nsEscape.h"
|
|
#include "nsIFrameInlines.h"
|
|
#include "nsIScrollableFrame.h"
|
|
#include "nsView.h"
|
|
#include "nsViewManager.h"
|
|
#include "nsIWidget.h"
|
|
#include "nsRange.h"
|
|
#include "nsIPresShell.h"
|
|
#include "nsPresContext.h"
|
|
#include "nsIDocShell.h"
|
|
#include "nsNameSpaceManager.h"
|
|
#include "nsError.h"
|
|
#include "nsScriptLoader.h"
|
|
#include "nsRuleData.h"
|
|
#include "nsIPrincipal.h"
|
|
#include "nsContainerFrame.h"
|
|
#include "nsStyleUtil.h"
|
|
|
|
#include "nsPresState.h"
|
|
#include "nsILayoutHistoryState.h"
|
|
|
|
#include "nsHTMLParts.h"
|
|
#include "nsContentUtils.h"
|
|
#include "mozilla/dom/DirectionalityUtils.h"
|
|
#include "nsString.h"
|
|
#include "nsUnicharUtils.h"
|
|
#include "nsGkAtoms.h"
|
|
#include "nsIDOMEvent.h"
|
|
#include "nsDOMCSSDeclaration.h"
|
|
#include "nsITextControlFrame.h"
|
|
#include "nsIForm.h"
|
|
#include "nsIFormControl.h"
|
|
#include "nsIDOMHTMLFormElement.h"
|
|
#include "mozilla/dom/HTMLFormElement.h"
|
|
#include "nsFocusManager.h"
|
|
#include "nsAttrValueOrString.h"
|
|
|
|
#include "mozilla/InternalMutationEvent.h"
|
|
#include "nsDOMStringMap.h"
|
|
|
|
#include "nsIEditor.h"
|
|
#include "nsIEditorIMESupport.h"
|
|
#include "nsLayoutUtils.h"
|
|
#include "mozAutoDocUpdate.h"
|
|
#include "nsHtml5Module.h"
|
|
#include "nsITextControlElement.h"
|
|
#include "mozilla/dom/Element.h"
|
|
#include "HTMLFieldSetElement.h"
|
|
#include "nsTextNode.h"
|
|
#include "HTMLBRElement.h"
|
|
#include "HTMLMenuElement.h"
|
|
#include "nsDOMMutationObserver.h"
|
|
#include "mozilla/Preferences.h"
|
|
#include "mozilla/dom/FromParser.h"
|
|
#include "mozilla/dom/Link.h"
|
|
#include "mozilla/dom/UndoManager.h"
|
|
#include "mozilla/BloomFilter.h"
|
|
|
|
#include "HTMLPropertiesCollection.h"
|
|
#include "nsVariant.h"
|
|
#include "nsDOMTokenList.h"
|
|
#include "nsThreadUtils.h"
|
|
#include "nsTextFragment.h"
|
|
#include "mozilla/dom/BindingUtils.h"
|
|
#include "mozilla/dom/TouchEvent.h"
|
|
#include "mozilla/ErrorResult.h"
|
|
#include "nsHTMLDocument.h"
|
|
#include "nsGlobalWindow.h"
|
|
#include "mozilla/dom/HTMLBodyElement.h"
|
|
#include "imgIContainer.h"
|
|
#include "nsComputedDOMStyle.h"
|
|
#include "mozilla/StyleSetHandle.h"
|
|
#include "mozilla/StyleSetHandleInlines.h"
|
|
|
|
using namespace mozilla;
|
|
using namespace mozilla::dom;
|
|
|
|
/**
|
|
* nsAutoFocusEvent is used to dispatch a focus event when a
|
|
* nsGenericHTMLFormElement is binded to the tree with the autofocus attribute
|
|
* enabled.
|
|
*/
|
|
class nsAutoFocusEvent : public nsRunnable
|
|
{
|
|
public:
|
|
explicit nsAutoFocusEvent(nsGenericHTMLFormElement* aElement) : mElement(aElement) {}
|
|
|
|
NS_IMETHOD Run() {
|
|
nsFocusManager* fm = nsFocusManager::GetFocusManager();
|
|
if (!fm) {
|
|
return NS_ERROR_NULL_POINTER;
|
|
}
|
|
|
|
nsIDocument* document = mElement->OwnerDoc();
|
|
|
|
nsPIDOMWindow* window = document->GetWindow();
|
|
if (!window) {
|
|
return NS_OK;
|
|
}
|
|
|
|
// Trying to found the top window (equivalent to window.top).
|
|
if (nsCOMPtr<nsPIDOMWindow> top = window->GetTop()) {
|
|
window = top;
|
|
}
|
|
|
|
if (window->GetFocusedNode()) {
|
|
return NS_OK;
|
|
}
|
|
|
|
nsCOMPtr<nsIDocument> topDoc = window->GetExtantDoc();
|
|
if (topDoc && topDoc->GetReadyStateEnum() == nsIDocument::READYSTATE_COMPLETE) {
|
|
return NS_OK;
|
|
}
|
|
|
|
// If something is focused in the same document, ignore autofocus.
|
|
if (!fm->GetFocusedContent() ||
|
|
fm->GetFocusedContent()->OwnerDoc() != document) {
|
|
mozilla::ErrorResult rv;
|
|
mElement->Focus(rv);
|
|
return rv.StealNSResult();
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
private:
|
|
// NOTE: nsGenericHTMLFormElement is saved as a nsGenericHTMLElement
|
|
// because AddRef/Release are ambiguous with nsGenericHTMLFormElement
|
|
// and Focus() is declared (and defined) in nsGenericHTMLElement class.
|
|
RefPtr<nsGenericHTMLElement> mElement;
|
|
};
|
|
|
|
class nsGenericHTMLElementTearoff : public nsIDOMElementCSSInlineStyle
|
|
{
|
|
virtual ~nsGenericHTMLElementTearoff()
|
|
{
|
|
}
|
|
|
|
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
|
|
|
explicit nsGenericHTMLElementTearoff(nsGenericHTMLElement* aElement)
|
|
: mElement(aElement)
|
|
{
|
|
}
|
|
|
|
NS_IMETHOD GetStyle(nsIDOMCSSStyleDeclaration** aStyle) override
|
|
{
|
|
NS_ADDREF(*aStyle = mElement->Style());
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsGenericHTMLElementTearoff,
|
|
nsIDOMElementCSSInlineStyle)
|
|
|
|
private:
|
|
RefPtr<nsGenericHTMLElement> mElement;
|
|
};
|
|
|
|
NS_IMPL_CYCLE_COLLECTION(nsGenericHTMLElementTearoff, mElement)
|
|
|
|
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsGenericHTMLElementTearoff)
|
|
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsGenericHTMLElementTearoff)
|
|
|
|
NS_INTERFACE_TABLE_HEAD(nsGenericHTMLElementTearoff)
|
|
NS_INTERFACE_TABLE_INHERITED(nsGenericHTMLElementTearoff,
|
|
nsIDOMElementCSSInlineStyle)
|
|
NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(nsGenericHTMLElementTearoff)
|
|
NS_INTERFACE_MAP_END_AGGREGATED(mElement)
|
|
|
|
NS_IMPL_ADDREF_INHERITED(nsGenericHTMLElement, nsGenericHTMLElementBase)
|
|
NS_IMPL_RELEASE_INHERITED(nsGenericHTMLElement, nsGenericHTMLElementBase)
|
|
|
|
NS_INTERFACE_MAP_BEGIN(nsGenericHTMLElement)
|
|
NS_INTERFACE_MAP_ENTRY(nsIDOMHTMLElement)
|
|
NS_INTERFACE_MAP_ENTRY(nsIDOMElement)
|
|
NS_INTERFACE_MAP_ENTRY(nsIDOMNode)
|
|
NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOMElementCSSInlineStyle,
|
|
new nsGenericHTMLElementTearoff(this))
|
|
NS_INTERFACE_MAP_END_INHERITING(nsGenericHTMLElementBase)
|
|
|
|
nsresult
|
|
nsGenericHTMLElement::CopyInnerTo(Element* aDst)
|
|
{
|
|
nsresult rv;
|
|
int32_t i, count = GetAttrCount();
|
|
for (i = 0; i < count; ++i) {
|
|
const nsAttrName *name = mAttrsAndChildren.AttrNameAt(i);
|
|
const nsAttrValue *value = mAttrsAndChildren.AttrAt(i);
|
|
|
|
nsAutoString valStr;
|
|
value->ToString(valStr);
|
|
|
|
if (name->Equals(nsGkAtoms::style, kNameSpaceID_None) &&
|
|
value->Type() == nsAttrValue::eCSSDeclaration) {
|
|
// We can't just set this as a string, because that will fail
|
|
// to reparse the string into style data until the node is
|
|
// inserted into the document. Clone the Rule instead.
|
|
RefPtr<css::Declaration> declClone =
|
|
new css::Declaration(*value->GetCSSDeclarationValue());
|
|
|
|
rv = aDst->SetInlineStyleDeclaration(declClone, &valStr, false);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
continue;
|
|
}
|
|
|
|
rv = aDst->SetAttr(name->NamespaceID(), name->LocalName(),
|
|
name->GetPrefix(), valStr, false);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
already_AddRefed<nsDOMStringMap>
|
|
nsGenericHTMLElement::Dataset()
|
|
{
|
|
nsDOMSlots *slots = DOMSlots();
|
|
|
|
if (!slots->mDataset) {
|
|
// mDataset is a weak reference so assignment will not AddRef.
|
|
// AddRef is called before returning the pointer.
|
|
slots->mDataset = new nsDOMStringMap(this);
|
|
}
|
|
|
|
RefPtr<nsDOMStringMap> ret = slots->mDataset;
|
|
return ret.forget();
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsGenericHTMLElement::GetDataset(nsISupports** aDataset)
|
|
{
|
|
*aDataset = Dataset().take();
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsGenericHTMLElement::ClearDataset()
|
|
{
|
|
nsDOMSlots *slots = GetExistingDOMSlots();
|
|
|
|
NS_ASSERTION(slots && slots->mDataset,
|
|
"Slots should exist and dataset should not be null.");
|
|
slots->mDataset = nullptr;
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
static const nsAttrValue::EnumTable kDirTable[] = {
|
|
{ "ltr", eDir_LTR },
|
|
{ "rtl", eDir_RTL },
|
|
{ "auto", eDir_Auto },
|
|
{ 0 }
|
|
};
|
|
|
|
void
|
|
nsGenericHTMLElement::GetAccessKeyLabel(nsString& aLabel)
|
|
{
|
|
nsAutoString suffix;
|
|
GetAccessKey(suffix);
|
|
if (!suffix.IsEmpty()) {
|
|
EventStateManager::GetAccessKeyLabelPrefix(this, aLabel);
|
|
aLabel.Append(suffix);
|
|
}
|
|
}
|
|
|
|
static bool IS_TABLE_CELL(nsIAtom* frameType) {
|
|
return nsGkAtoms::tableCellFrame == frameType ||
|
|
nsGkAtoms::bcTableCellFrame == frameType;
|
|
}
|
|
|
|
static bool
|
|
IsOffsetParent(nsIFrame* aFrame)
|
|
{
|
|
nsIAtom* frameType = aFrame->GetType();
|
|
|
|
if (IS_TABLE_CELL(frameType) || frameType == nsGkAtoms::tableFrame) {
|
|
// Per the IDL for Element, only td, th, and table are acceptable offsetParents
|
|
// apart from body or positioned elements; we need to check the content type as
|
|
// well as the frame type so we ignore anonymous tables created by an element
|
|
// with display: table-cell with no actual table
|
|
nsIContent* content = aFrame->GetContent();
|
|
|
|
return content->IsAnyOfHTMLElements(nsGkAtoms::table,
|
|
nsGkAtoms::td,
|
|
nsGkAtoms::th);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
Element*
|
|
nsGenericHTMLElement::GetOffsetRect(CSSIntRect& aRect)
|
|
{
|
|
aRect = CSSIntRect();
|
|
|
|
nsIFrame* frame = GetStyledFrame();
|
|
if (!frame) {
|
|
return nullptr;
|
|
}
|
|
|
|
nsIFrame* parent = frame->GetParent();
|
|
nsPoint origin(0, 0);
|
|
|
|
if (parent && parent->GetType() == nsGkAtoms::tableOuterFrame &&
|
|
frame->GetType() == nsGkAtoms::tableFrame) {
|
|
origin = parent->GetPositionIgnoringScrolling();
|
|
parent = parent->GetParent();
|
|
}
|
|
|
|
nsIContent* offsetParent = nullptr;
|
|
Element* docElement = GetComposedDoc()->GetRootElement();
|
|
nsIContent* content = frame->GetContent();
|
|
|
|
if (content && (content->IsHTMLElement(nsGkAtoms::body) ||
|
|
content == docElement)) {
|
|
parent = frame;
|
|
}
|
|
else {
|
|
const bool isPositioned = frame->IsAbsPosContaininingBlock();
|
|
const bool isAbsolutelyPositioned = frame->IsAbsolutelyPositioned();
|
|
origin += frame->GetPositionIgnoringScrolling();
|
|
|
|
for ( ; parent ; parent = parent->GetParent()) {
|
|
content = parent->GetContent();
|
|
|
|
// Stop at the first ancestor that is positioned.
|
|
if (parent->IsAbsPosContaininingBlock()) {
|
|
offsetParent = content;
|
|
break;
|
|
}
|
|
|
|
// Add the parent's origin to our own to get to the
|
|
// right coordinate system.
|
|
const bool isOffsetParent = !isPositioned && IsOffsetParent(parent);
|
|
if (!isAbsolutelyPositioned && !isOffsetParent) {
|
|
origin += parent->GetPositionIgnoringScrolling();
|
|
}
|
|
|
|
if (content) {
|
|
// If we've hit the document element, break here.
|
|
if (content == docElement) {
|
|
break;
|
|
}
|
|
|
|
// Break if the ancestor frame type makes it suitable as offset parent
|
|
// and this element is *not* positioned or if we found the body element.
|
|
if (isOffsetParent || content->IsHTMLElement(nsGkAtoms::body)) {
|
|
offsetParent = content;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (isAbsolutelyPositioned && !offsetParent) {
|
|
// If this element is absolutely positioned, but we don't have
|
|
// an offset parent it means this element is an absolutely
|
|
// positioned child that's not nested inside another positioned
|
|
// element, in this case the element's frame's parent is the
|
|
// frame for the HTML element so we fail to find the body in the
|
|
// parent chain. We want the offset parent in this case to be
|
|
// the body, so we just get the body element from the document.
|
|
|
|
nsCOMPtr<nsIDOMHTMLDocument> html_doc(do_QueryInterface(GetComposedDoc()));
|
|
|
|
if (html_doc) {
|
|
offsetParent = static_cast<nsHTMLDocument*>(html_doc.get())->GetBody();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Subtract the parent border unless it uses border-box sizing.
|
|
if (parent &&
|
|
parent->StylePosition()->mBoxSizing != StyleBoxSizing::Border) {
|
|
const nsStyleBorder* border = parent->StyleBorder();
|
|
origin.x -= border->GetComputedBorderWidth(NS_SIDE_LEFT);
|
|
origin.y -= border->GetComputedBorderWidth(NS_SIDE_TOP);
|
|
}
|
|
|
|
// XXX We should really consider subtracting out padding for
|
|
// content-box sizing, but we should see what IE does....
|
|
|
|
// Get the union of all rectangles in this and continuation frames.
|
|
// It doesn't really matter what we use as aRelativeTo here, since
|
|
// we only care about the size. We just have to use something non-null.
|
|
nsRect rcFrame = nsLayoutUtils::GetAllInFlowRectsUnion(frame, frame);
|
|
rcFrame.MoveTo(origin);
|
|
aRect = CSSIntRect::FromAppUnitsRounded(rcFrame);
|
|
|
|
return offsetParent ? offsetParent->AsElement() : nullptr;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsGenericHTMLElement::InsertAdjacentHTML(const nsAString& aPosition,
|
|
const nsAString& aText)
|
|
{
|
|
ErrorResult rv;
|
|
Element::InsertAdjacentHTML(aPosition, aText, rv);
|
|
return rv.StealNSResult();
|
|
}
|
|
|
|
bool
|
|
nsGenericHTMLElement::Spellcheck()
|
|
{
|
|
// Has the state has been explicitly set?
|
|
nsIContent* node;
|
|
for (node = this; node; node = node->GetParent()) {
|
|
if (node->IsHTMLElement()) {
|
|
static nsIContent::AttrValuesArray strings[] =
|
|
{&nsGkAtoms::_true, &nsGkAtoms::_false, nullptr};
|
|
switch (node->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::spellcheck,
|
|
strings, eCaseMatters)) {
|
|
case 0: // spellcheck = "true"
|
|
return true;
|
|
case 1: // spellcheck = "false"
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
// contenteditable/designMode are spellchecked by default
|
|
if (IsEditable()) {
|
|
return true;
|
|
}
|
|
|
|
// Is this a chrome element?
|
|
if (nsContentUtils::IsChromeDoc(OwnerDoc())) {
|
|
return false; // Not spellchecked by default
|
|
}
|
|
|
|
// Anything else that's not a form control is not spellchecked by default
|
|
nsCOMPtr<nsIFormControl> formControl = do_QueryObject(this);
|
|
if (!formControl) {
|
|
return false; // Not spellchecked by default
|
|
}
|
|
|
|
// Is this a multiline plaintext input?
|
|
int32_t controlType = formControl->GetType();
|
|
if (controlType == NS_FORM_TEXTAREA) {
|
|
return true; // Spellchecked by default
|
|
}
|
|
|
|
// Is this anything other than an input text?
|
|
// Other inputs are not spellchecked.
|
|
if (controlType != NS_FORM_INPUT_TEXT) {
|
|
return false; // Not spellchecked by default
|
|
}
|
|
|
|
// Does the user want input text spellchecked by default?
|
|
// NOTE: Do not reflect a pref value of 0 back to the DOM getter.
|
|
// The web page should not know if the user has disabled spellchecking.
|
|
// We'll catch this in the editor itself.
|
|
int32_t spellcheckLevel = Preferences::GetInt("layout.spellcheckDefault", 1);
|
|
return spellcheckLevel == 2; // "Spellcheck multi- and single-line"
|
|
}
|
|
|
|
bool
|
|
nsGenericHTMLElement::InNavQuirksMode(nsIDocument* aDoc)
|
|
{
|
|
return aDoc && aDoc->GetCompatibilityMode() == eCompatibility_NavQuirks;
|
|
}
|
|
|
|
void
|
|
nsGenericHTMLElement::UpdateEditableState(bool aNotify)
|
|
{
|
|
// XXX Should we do this only when in a document?
|
|
ContentEditableTristate value = GetContentEditableValue();
|
|
if (value != eInherit) {
|
|
DoSetEditableFlag(!!value, aNotify);
|
|
return;
|
|
}
|
|
|
|
nsStyledElement::UpdateEditableState(aNotify);
|
|
}
|
|
|
|
EventStates
|
|
nsGenericHTMLElement::IntrinsicState() const
|
|
{
|
|
EventStates state = nsGenericHTMLElementBase::IntrinsicState();
|
|
|
|
if (GetDirectionality() == eDir_RTL) {
|
|
state |= NS_EVENT_STATE_RTL;
|
|
state &= ~NS_EVENT_STATE_LTR;
|
|
} else { // at least for HTML, directionality is exclusively LTR or RTL
|
|
NS_ASSERTION(GetDirectionality() == eDir_LTR,
|
|
"HTML element's directionality must be either RTL or LTR");
|
|
state |= NS_EVENT_STATE_LTR;
|
|
state &= ~NS_EVENT_STATE_RTL;
|
|
}
|
|
|
|
return state;
|
|
}
|
|
|
|
uint32_t
|
|
nsGenericHTMLElement::EditableInclusiveDescendantCount()
|
|
{
|
|
bool isEditable = IsInUncomposedDoc() && HasFlag(NODE_IS_EDITABLE) &&
|
|
GetContentEditableValue() == eTrue;
|
|
return EditableDescendantCount() + isEditable;
|
|
}
|
|
|
|
nsresult
|
|
nsGenericHTMLElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
|
nsIContent* aBindingParent,
|
|
bool aCompileEventHandlers)
|
|
{
|
|
nsresult rv = nsGenericHTMLElementBase::BindToTree(aDocument, aParent,
|
|
aBindingParent,
|
|
aCompileEventHandlers);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
if (aDocument) {
|
|
if (HasProperties()) {
|
|
HTMLPropertiesCollection* properties =
|
|
static_cast<HTMLPropertiesCollection*>(GetProperty(nsGkAtoms::microdataProperties));
|
|
if (properties) {
|
|
properties->SetDocument(aDocument);
|
|
}
|
|
}
|
|
RegAccessKey();
|
|
if (HasName()) {
|
|
aDocument->
|
|
AddToNameTable(this, GetParsedAttr(nsGkAtoms::name)->GetAtomValue());
|
|
}
|
|
|
|
if (HasFlag(NODE_IS_EDITABLE) && GetContentEditableValue() == eTrue) {
|
|
nsCOMPtr<nsIHTMLDocument> htmlDocument = do_QueryInterface(aDocument);
|
|
if (htmlDocument) {
|
|
htmlDocument->ChangeContentEditableCount(this, +1);
|
|
}
|
|
}
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
void
|
|
nsGenericHTMLElement::UnbindFromTree(bool aDeep, bool aNullParent)
|
|
{
|
|
if (IsInDoc()) {
|
|
UnregAccessKey();
|
|
}
|
|
|
|
if(HasProperties()) {
|
|
HTMLPropertiesCollection* properties =
|
|
static_cast<HTMLPropertiesCollection*>(GetProperty(nsGkAtoms::microdataProperties));
|
|
if (properties) {
|
|
properties->SetDocument(nullptr);
|
|
}
|
|
}
|
|
|
|
RemoveFromNameTable();
|
|
|
|
if (GetContentEditableValue() == eTrue) {
|
|
//XXXsmaug Fix this for Shadow DOM, bug 1066965.
|
|
nsCOMPtr<nsIHTMLDocument> htmlDocument = do_QueryInterface(GetUncomposedDoc());
|
|
if (htmlDocument) {
|
|
htmlDocument->ChangeContentEditableCount(this, -1);
|
|
}
|
|
}
|
|
|
|
nsStyledElement::UnbindFromTree(aDeep, aNullParent);
|
|
}
|
|
|
|
HTMLFormElement*
|
|
nsGenericHTMLElement::FindAncestorForm(HTMLFormElement* aCurrentForm)
|
|
{
|
|
NS_ASSERTION(!HasAttr(kNameSpaceID_None, nsGkAtoms::form) ||
|
|
IsHTMLElement(nsGkAtoms::img),
|
|
"FindAncestorForm should not be called if @form is set!");
|
|
|
|
// Make sure we don't end up finding a form that's anonymous from
|
|
// our point of view.
|
|
nsIContent* bindingParent = GetBindingParent();
|
|
|
|
nsIContent* content = this;
|
|
while (content != bindingParent && content) {
|
|
// If the current ancestor is a form, return it as our form
|
|
if (content->IsHTMLElement(nsGkAtoms::form)) {
|
|
#ifdef DEBUG
|
|
if (!nsContentUtils::IsInSameAnonymousTree(this, content)) {
|
|
// It's possible that we started unbinding at |content| or
|
|
// some ancestor of it, and |content| and |this| used to all be
|
|
// anonymous. Check for this the hard way.
|
|
for (nsIContent* child = this; child != content;
|
|
child = child->GetParent()) {
|
|
NS_ASSERTION(child->GetParent()->IndexOf(child) != -1,
|
|
"Walked too far?");
|
|
}
|
|
}
|
|
#endif
|
|
return static_cast<HTMLFormElement*>(content);
|
|
}
|
|
|
|
nsIContent *prevContent = content;
|
|
content = prevContent->GetParent();
|
|
|
|
if (!content && aCurrentForm) {
|
|
// We got to the root of the subtree we're in, and we're being removed
|
|
// from the DOM (the only time we get into this method with a non-null
|
|
// aCurrentForm). Check whether aCurrentForm is in the same subtree. If
|
|
// it is, we want to return aCurrentForm, since this case means that
|
|
// we're one of those inputs-in-a-table that have a hacked mForm pointer
|
|
// and a subtree containing both us and the form got removed from the
|
|
// DOM.
|
|
if (nsContentUtils::ContentIsDescendantOf(aCurrentForm, prevContent)) {
|
|
return aCurrentForm;
|
|
}
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
bool
|
|
nsGenericHTMLElement::CheckHandleEventForAnchorsPreconditions(
|
|
EventChainVisitor& aVisitor)
|
|
{
|
|
NS_PRECONDITION(nsCOMPtr<Link>(do_QueryObject(this)),
|
|
"should be called only when |this| implements |Link|");
|
|
|
|
if (!aVisitor.mPresContext) {
|
|
// We need a pres context to do link stuff. Some events (e.g. mutation
|
|
// events) don't have one.
|
|
// XXX: ideally, shouldn't we be able to do what we need without one?
|
|
return false;
|
|
}
|
|
|
|
//Need to check if we hit an imagemap area and if so see if we're handling
|
|
//the event on that map or on a link farther up the tree. If we're on a
|
|
//link farther up, do nothing.
|
|
nsCOMPtr<nsIContent> target = aVisitor.mPresContext->EventStateManager()->
|
|
GetEventTargetContent(aVisitor.mEvent);
|
|
|
|
return !target || !target->IsHTMLElement(nsGkAtoms::area) ||
|
|
IsHTMLElement(nsGkAtoms::area);
|
|
}
|
|
|
|
nsresult
|
|
nsGenericHTMLElement::PreHandleEventForAnchors(EventChainPreVisitor& aVisitor)
|
|
{
|
|
nsresult rv = nsGenericHTMLElementBase::PreHandleEvent(aVisitor);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
if (!CheckHandleEventForAnchorsPreconditions(aVisitor)) {
|
|
return NS_OK;
|
|
}
|
|
|
|
return PreHandleEventForLinks(aVisitor);
|
|
}
|
|
|
|
nsresult
|
|
nsGenericHTMLElement::PostHandleEventForAnchors(EventChainPostVisitor& aVisitor)
|
|
{
|
|
if (!CheckHandleEventForAnchorsPreconditions(aVisitor)) {
|
|
return NS_OK;
|
|
}
|
|
|
|
return PostHandleEventForLinks(aVisitor);
|
|
}
|
|
|
|
bool
|
|
nsGenericHTMLElement::IsHTMLLink(nsIURI** aURI) const
|
|
{
|
|
NS_PRECONDITION(aURI, "Must provide aURI out param");
|
|
|
|
*aURI = GetHrefURIForAnchors().take();
|
|
// We promise out param is non-null if we return true, so base rv on it
|
|
return *aURI != nullptr;
|
|
}
|
|
|
|
already_AddRefed<nsIURI>
|
|
nsGenericHTMLElement::GetHrefURIForAnchors() const
|
|
{
|
|
// This is used by the three Link implementations and
|
|
// nsHTMLStyleElement.
|
|
|
|
// Get href= attribute (relative URI).
|
|
|
|
// We use the nsAttrValue's copy of the URI string to avoid copying.
|
|
nsCOMPtr<nsIURI> uri;
|
|
GetURIAttr(nsGkAtoms::href, nullptr, getter_AddRefs(uri));
|
|
|
|
return uri.forget();
|
|
}
|
|
|
|
nsresult
|
|
nsGenericHTMLElement::AfterSetAttr(int32_t aNamespaceID, nsIAtom* aName,
|
|
const nsAttrValue* aValue, bool aNotify)
|
|
{
|
|
if (aNamespaceID == kNameSpaceID_None) {
|
|
if (IsEventAttributeName(aName) && aValue) {
|
|
MOZ_ASSERT(aValue->Type() == nsAttrValue::eString,
|
|
"Expected string value for script body");
|
|
nsresult rv = SetEventHandler(aName, aValue->GetStringValue());
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
}
|
|
else if (aNotify && aName == nsGkAtoms::spellcheck) {
|
|
SyncEditorsOnSubtree(this);
|
|
}
|
|
else if (aName == nsGkAtoms::dir) {
|
|
Directionality dir = eDir_LTR;
|
|
if (aValue && aValue->Type() == nsAttrValue::eEnum) {
|
|
SetHasValidDir();
|
|
Directionality dirValue = (Directionality)aValue->GetEnumValue();
|
|
if (dirValue == eDir_Auto) {
|
|
SetHasDirAuto();
|
|
ClearHasFixedDir();
|
|
} else {
|
|
dir = dirValue;
|
|
SetDirectionality(dir, aNotify);
|
|
ClearHasDirAuto();
|
|
SetHasFixedDir();
|
|
}
|
|
} else {
|
|
ClearHasValidDir();
|
|
ClearHasFixedDir();
|
|
if (NodeInfo()->Equals(nsGkAtoms::bdi)) {
|
|
SetHasDirAuto();
|
|
} else {
|
|
ClearHasDirAuto();
|
|
dir = RecomputeDirectionality(this, aNotify);
|
|
}
|
|
}
|
|
SetDirectionalityOnDescendants(this, dir, aNotify);
|
|
}
|
|
}
|
|
|
|
return nsGenericHTMLElementBase::AfterSetAttr(aNamespaceID, aName,
|
|
aValue, aNotify);
|
|
}
|
|
|
|
EventListenerManager*
|
|
nsGenericHTMLElement::GetEventListenerManagerForAttr(nsIAtom* aAttrName,
|
|
bool* aDefer)
|
|
{
|
|
// Attributes on the body and frameset tags get set on the global object
|
|
if ((mNodeInfo->Equals(nsGkAtoms::body) ||
|
|
mNodeInfo->Equals(nsGkAtoms::frameset)) &&
|
|
// We only forward some event attributes from body/frameset to window
|
|
(0
|
|
#define EVENT(name_, id_, type_, struct_) /* nothing */
|
|
#define FORWARDED_EVENT(name_, id_, type_, struct_) \
|
|
|| nsGkAtoms::on##name_ == aAttrName
|
|
#define WINDOW_EVENT FORWARDED_EVENT
|
|
#include "mozilla/EventNameList.h" // IWYU pragma: keep
|
|
#undef WINDOW_EVENT
|
|
#undef FORWARDED_EVENT
|
|
#undef EVENT
|
|
)
|
|
) {
|
|
nsPIDOMWindow *win;
|
|
|
|
// If we have a document, and it has a window, add the event
|
|
// listener on the window (the inner window). If not, proceed as
|
|
// normal.
|
|
// XXXbz sXBL/XBL2 issue: should we instead use GetComposedDoc() here,
|
|
// override BindToTree for those classes and munge event listeners there?
|
|
nsIDocument *document = OwnerDoc();
|
|
|
|
*aDefer = false;
|
|
if ((win = document->GetInnerWindow())) {
|
|
nsCOMPtr<EventTarget> piTarget(do_QueryInterface(win));
|
|
|
|
return piTarget->GetOrCreateListenerManager();
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
return nsGenericHTMLElementBase::GetEventListenerManagerForAttr(aAttrName,
|
|
aDefer);
|
|
}
|
|
|
|
#define EVENT(name_, id_, type_, struct_) /* nothing; handled by nsINode */
|
|
#define FORWARDED_EVENT(name_, id_, type_, struct_) \
|
|
EventHandlerNonNull* \
|
|
nsGenericHTMLElement::GetOn##name_() \
|
|
{ \
|
|
if (IsAnyOfHTMLElements(nsGkAtoms::body, nsGkAtoms::frameset)) { \
|
|
/* XXXbz note to self: add tests for this! */ \
|
|
nsPIDOMWindow* win = OwnerDoc()->GetInnerWindow(); \
|
|
if (win) { \
|
|
nsCOMPtr<nsISupports> supports = do_QueryInterface(win); \
|
|
nsGlobalWindow* globalWin = nsGlobalWindow::FromSupports(supports); \
|
|
return globalWin->GetOn##name_(); \
|
|
} \
|
|
return nullptr; \
|
|
} \
|
|
\
|
|
return nsINode::GetOn##name_(); \
|
|
} \
|
|
void \
|
|
nsGenericHTMLElement::SetOn##name_(EventHandlerNonNull* handler) \
|
|
{ \
|
|
if (IsAnyOfHTMLElements(nsGkAtoms::body, nsGkAtoms::frameset)) { \
|
|
nsPIDOMWindow* win = OwnerDoc()->GetInnerWindow(); \
|
|
if (!win) { \
|
|
return; \
|
|
} \
|
|
\
|
|
nsCOMPtr<nsISupports> supports = do_QueryInterface(win); \
|
|
nsGlobalWindow* globalWin = nsGlobalWindow::FromSupports(supports); \
|
|
return globalWin->SetOn##name_(handler); \
|
|
} \
|
|
\
|
|
return nsINode::SetOn##name_(handler); \
|
|
}
|
|
#define ERROR_EVENT(name_, id_, type_, struct_) \
|
|
already_AddRefed<EventHandlerNonNull> \
|
|
nsGenericHTMLElement::GetOn##name_() \
|
|
{ \
|
|
if (IsAnyOfHTMLElements(nsGkAtoms::body, nsGkAtoms::frameset)) { \
|
|
/* XXXbz note to self: add tests for this! */ \
|
|
nsPIDOMWindow* win = OwnerDoc()->GetInnerWindow(); \
|
|
if (win) { \
|
|
nsCOMPtr<nsISupports> supports = do_QueryInterface(win); \
|
|
nsGlobalWindow* globalWin = nsGlobalWindow::FromSupports(supports); \
|
|
OnErrorEventHandlerNonNull* errorHandler = globalWin->GetOn##name_(); \
|
|
if (errorHandler) { \
|
|
RefPtr<EventHandlerNonNull> handler = \
|
|
new EventHandlerNonNull(errorHandler); \
|
|
return handler.forget(); \
|
|
} \
|
|
} \
|
|
return nullptr; \
|
|
} \
|
|
\
|
|
RefPtr<EventHandlerNonNull> handler = nsINode::GetOn##name_(); \
|
|
return handler.forget(); \
|
|
} \
|
|
void \
|
|
nsGenericHTMLElement::SetOn##name_(EventHandlerNonNull* handler) \
|
|
{ \
|
|
if (IsAnyOfHTMLElements(nsGkAtoms::body, nsGkAtoms::frameset)) { \
|
|
nsPIDOMWindow* win = OwnerDoc()->GetInnerWindow(); \
|
|
if (!win) { \
|
|
return; \
|
|
} \
|
|
\
|
|
nsCOMPtr<nsISupports> supports = do_QueryInterface(win); \
|
|
nsGlobalWindow* globalWin = nsGlobalWindow::FromSupports(supports); \
|
|
RefPtr<OnErrorEventHandlerNonNull> errorHandler; \
|
|
if (handler) { \
|
|
errorHandler = new OnErrorEventHandlerNonNull(handler); \
|
|
} \
|
|
return globalWin->SetOn##name_(errorHandler); \
|
|
} \
|
|
\
|
|
return nsINode::SetOn##name_(handler); \
|
|
}
|
|
#include "mozilla/EventNameList.h" // IWYU pragma: keep
|
|
#undef ERROR_EVENT
|
|
#undef FORWARDED_EVENT
|
|
#undef EVENT
|
|
|
|
nsresult
|
|
nsGenericHTMLElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
|
nsIAtom* aPrefix, const nsAString& aValue,
|
|
bool aNotify)
|
|
{
|
|
bool contentEditable = aNameSpaceID == kNameSpaceID_None &&
|
|
aName == nsGkAtoms::contenteditable;
|
|
bool undoScope = aNameSpaceID == kNameSpaceID_None &&
|
|
aName == nsGkAtoms::undoscope;
|
|
bool accessKey = aName == nsGkAtoms::accesskey &&
|
|
aNameSpaceID == kNameSpaceID_None;
|
|
|
|
int32_t change = 0;
|
|
if (contentEditable) {
|
|
change = GetContentEditableValue() == eTrue ? -1 : 0;
|
|
SetMayHaveContentEditableAttr();
|
|
}
|
|
|
|
if (accessKey) {
|
|
UnregAccessKey();
|
|
}
|
|
|
|
nsresult rv = nsStyledElement::SetAttr(aNameSpaceID, aName, aPrefix, aValue,
|
|
aNotify);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
if (contentEditable) {
|
|
if (aValue.IsEmpty() || aValue.LowerCaseEqualsLiteral("true")) {
|
|
change += 1;
|
|
}
|
|
|
|
ChangeEditableState(change);
|
|
}
|
|
|
|
if (undoScope) {
|
|
rv = SetUndoScopeInternal(true);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
}
|
|
|
|
if (accessKey && !aValue.IsEmpty()) {
|
|
SetFlags(NODE_HAS_ACCESSKEY);
|
|
RegAccessKey();
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsGenericHTMLElement::UnsetAttr(int32_t aNameSpaceID, nsIAtom* aAttribute,
|
|
bool aNotify)
|
|
{
|
|
bool contentEditable = false;
|
|
int32_t contentEditableChange = 0;
|
|
|
|
// Check for event handlers
|
|
if (aNameSpaceID == kNameSpaceID_None) {
|
|
if (aAttribute == nsGkAtoms::name) {
|
|
// Have to do this before clearing flag. See RemoveFromNameTable
|
|
RemoveFromNameTable();
|
|
ClearHasName();
|
|
}
|
|
else if (aAttribute == nsGkAtoms::contenteditable) {
|
|
contentEditable = true;
|
|
contentEditableChange = GetContentEditableValue() == eTrue ? -1 : 0;
|
|
}
|
|
else if (aAttribute == nsGkAtoms::undoscope) {
|
|
nsresult rv = SetUndoScopeInternal(false);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
}
|
|
else if (aAttribute == nsGkAtoms::accesskey) {
|
|
// Have to unregister before clearing flag. See UnregAccessKey
|
|
UnregAccessKey();
|
|
UnsetFlags(NODE_HAS_ACCESSKEY);
|
|
}
|
|
else if (IsEventAttributeName(aAttribute)) {
|
|
if (EventListenerManager* manager = GetExistingListenerManager()) {
|
|
manager->RemoveEventHandler(aAttribute, EmptyString());
|
|
}
|
|
}
|
|
}
|
|
|
|
nsresult rv = nsGenericHTMLElementBase::UnsetAttr(aNameSpaceID, aAttribute,
|
|
aNotify);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
if (contentEditable) {
|
|
ChangeEditableState(contentEditableChange);
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
void
|
|
nsGenericHTMLElement::GetBaseTarget(nsAString& aBaseTarget) const
|
|
{
|
|
OwnerDoc()->GetBaseTarget(aBaseTarget);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
bool
|
|
nsGenericHTMLElement::ParseAttribute(int32_t aNamespaceID,
|
|
nsIAtom* aAttribute,
|
|
const nsAString& aValue,
|
|
nsAttrValue& aResult)
|
|
{
|
|
if (aNamespaceID == kNameSpaceID_None) {
|
|
if (aAttribute == nsGkAtoms::dir) {
|
|
return aResult.ParseEnumValue(aValue, kDirTable, false);
|
|
}
|
|
|
|
if (aAttribute == nsGkAtoms::tabindex) {
|
|
return aResult.ParseIntValue(aValue);
|
|
}
|
|
|
|
if (aAttribute == nsGkAtoms::referrerpolicy) {
|
|
return ParseReferrerAttribute(aValue, aResult);
|
|
}
|
|
|
|
if (aAttribute == nsGkAtoms::name) {
|
|
// Store name as an atom. name="" means that the element has no name,
|
|
// not that it has an emptystring as the name.
|
|
RemoveFromNameTable();
|
|
if (aValue.IsEmpty()) {
|
|
ClearHasName();
|
|
return false;
|
|
}
|
|
|
|
aResult.ParseAtom(aValue);
|
|
|
|
if (CanHaveName(NodeInfo()->NameAtom())) {
|
|
SetHasName();
|
|
AddToNameTable(aResult.GetAtomValue());
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
if (aAttribute == nsGkAtoms::contenteditable) {
|
|
aResult.ParseAtom(aValue);
|
|
return true;
|
|
}
|
|
|
|
if (aAttribute == nsGkAtoms::itemref ||
|
|
aAttribute == nsGkAtoms::itemprop ||
|
|
aAttribute == nsGkAtoms::itemtype ||
|
|
aAttribute == nsGkAtoms::rel) {
|
|
aResult.ParseAtomArray(aValue);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return nsGenericHTMLElementBase::ParseAttribute(aNamespaceID, aAttribute,
|
|
aValue, aResult);
|
|
}
|
|
|
|
bool
|
|
nsGenericHTMLElement::ParseBackgroundAttribute(int32_t aNamespaceID,
|
|
nsIAtom* aAttribute,
|
|
const nsAString& aValue,
|
|
nsAttrValue& aResult)
|
|
{
|
|
if (aNamespaceID == kNameSpaceID_None &&
|
|
aAttribute == nsGkAtoms::background &&
|
|
!aValue.IsEmpty()) {
|
|
// Resolve url to an absolute url
|
|
nsIDocument* doc = OwnerDoc();
|
|
nsCOMPtr<nsIURI> baseURI = GetBaseURI();
|
|
nsCOMPtr<nsIURI> uri;
|
|
nsresult rv = nsContentUtils::NewURIWithDocumentCharset(
|
|
getter_AddRefs(uri), aValue, doc, baseURI);
|
|
if (NS_FAILED(rv)) {
|
|
return false;
|
|
}
|
|
|
|
nsString value(aValue);
|
|
RefPtr<nsStringBuffer> buffer = nsCSSValue::BufferFromString(value);
|
|
if (MOZ_UNLIKELY(!buffer)) {
|
|
return false;
|
|
}
|
|
|
|
mozilla::css::URLValue *url =
|
|
new mozilla::css::URLValue(uri, buffer, doc->GetDocumentURI(),
|
|
NodePrincipal());
|
|
aResult.SetTo(url, &aValue);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
nsGenericHTMLElement::IsAttributeMapped(const nsIAtom* aAttribute) const
|
|
{
|
|
static const MappedAttributeEntry* const map[] = {
|
|
sCommonAttributeMap
|
|
};
|
|
|
|
return FindAttributeDependence(aAttribute, map);
|
|
}
|
|
|
|
nsMapRuleToAttributesFunc
|
|
nsGenericHTMLElement::GetAttributeMappingFunction() const
|
|
{
|
|
return &MapCommonAttributesInto;
|
|
}
|
|
|
|
nsIFormControlFrame*
|
|
nsGenericHTMLElement::GetFormControlFrame(bool aFlushFrames)
|
|
{
|
|
if (aFlushFrames && IsInComposedDoc()) {
|
|
// Cause a flush of the frames, so we get up-to-date frame information
|
|
GetComposedDoc()->FlushPendingNotifications(Flush_Frames);
|
|
}
|
|
nsIFrame* frame = GetPrimaryFrame();
|
|
if (frame) {
|
|
nsIFormControlFrame* form_frame = do_QueryFrame(frame);
|
|
if (form_frame) {
|
|
return form_frame;
|
|
}
|
|
|
|
// If we have generated content, the primary frame will be a
|
|
// wrapper frame.. out real frame will be in its child list.
|
|
for (frame = frame->PrincipalChildList().FirstChild();
|
|
frame;
|
|
frame = frame->GetNextSibling()) {
|
|
form_frame = do_QueryFrame(frame);
|
|
if (form_frame) {
|
|
return form_frame;
|
|
}
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
nsPresContext*
|
|
nsGenericHTMLElement::GetPresContext(PresContextFor aFor)
|
|
{
|
|
// Get the document
|
|
nsIDocument* doc = (aFor == eForComposedDoc) ?
|
|
GetComposedDoc() : GetUncomposedDoc();
|
|
if (doc) {
|
|
// Get presentation shell.
|
|
nsIPresShell *presShell = doc->GetShell();
|
|
if (presShell) {
|
|
return presShell->GetPresContext();
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
static const nsAttrValue::EnumTable kDivAlignTable[] = {
|
|
{ "left", NS_STYLE_TEXT_ALIGN_MOZ_LEFT },
|
|
{ "right", NS_STYLE_TEXT_ALIGN_MOZ_RIGHT },
|
|
{ "center", NS_STYLE_TEXT_ALIGN_MOZ_CENTER },
|
|
{ "middle", NS_STYLE_TEXT_ALIGN_MOZ_CENTER },
|
|
{ "justify", NS_STYLE_TEXT_ALIGN_JUSTIFY },
|
|
{ 0 }
|
|
};
|
|
|
|
static const nsAttrValue::EnumTable kFrameborderTable[] = {
|
|
{ "yes", NS_STYLE_FRAME_YES },
|
|
{ "no", NS_STYLE_FRAME_NO },
|
|
{ "1", NS_STYLE_FRAME_1 },
|
|
{ "0", NS_STYLE_FRAME_0 },
|
|
{ 0 }
|
|
};
|
|
|
|
static const nsAttrValue::EnumTable kScrollingTable[] = {
|
|
{ "yes", NS_STYLE_FRAME_YES },
|
|
{ "no", NS_STYLE_FRAME_NO },
|
|
{ "on", NS_STYLE_FRAME_ON },
|
|
{ "off", NS_STYLE_FRAME_OFF },
|
|
{ "scroll", NS_STYLE_FRAME_SCROLL },
|
|
{ "noscroll", NS_STYLE_FRAME_NOSCROLL },
|
|
{ "auto", NS_STYLE_FRAME_AUTO },
|
|
{ 0 }
|
|
};
|
|
|
|
static const nsAttrValue::EnumTable kTableVAlignTable[] = {
|
|
{ "top", NS_STYLE_VERTICAL_ALIGN_TOP },
|
|
{ "middle", NS_STYLE_VERTICAL_ALIGN_MIDDLE },
|
|
{ "bottom", NS_STYLE_VERTICAL_ALIGN_BOTTOM },
|
|
{ "baseline",NS_STYLE_VERTICAL_ALIGN_BASELINE },
|
|
{ 0 }
|
|
};
|
|
|
|
bool
|
|
nsGenericHTMLElement::ParseAlignValue(const nsAString& aString,
|
|
nsAttrValue& aResult)
|
|
{
|
|
static const nsAttrValue::EnumTable kAlignTable[] = {
|
|
{ "left", NS_STYLE_TEXT_ALIGN_LEFT },
|
|
{ "right", NS_STYLE_TEXT_ALIGN_RIGHT },
|
|
|
|
{ "top", NS_STYLE_VERTICAL_ALIGN_TOP },
|
|
{ "middle", NS_STYLE_VERTICAL_ALIGN_MIDDLE_WITH_BASELINE },
|
|
{ "bottom", NS_STYLE_VERTICAL_ALIGN_BASELINE },
|
|
|
|
{ "center", NS_STYLE_VERTICAL_ALIGN_MIDDLE_WITH_BASELINE },
|
|
{ "baseline", NS_STYLE_VERTICAL_ALIGN_BASELINE },
|
|
|
|
{ "texttop", NS_STYLE_VERTICAL_ALIGN_TEXT_TOP },
|
|
{ "absmiddle", NS_STYLE_VERTICAL_ALIGN_MIDDLE },
|
|
{ "abscenter", NS_STYLE_VERTICAL_ALIGN_MIDDLE },
|
|
{ "absbottom", NS_STYLE_VERTICAL_ALIGN_BOTTOM },
|
|
{ 0 }
|
|
};
|
|
|
|
return aResult.ParseEnumValue(aString, kAlignTable, false);
|
|
}
|
|
|
|
//----------------------------------------
|
|
|
|
static const nsAttrValue::EnumTable kTableHAlignTable[] = {
|
|
{ "left", NS_STYLE_TEXT_ALIGN_LEFT },
|
|
{ "right", NS_STYLE_TEXT_ALIGN_RIGHT },
|
|
{ "center", NS_STYLE_TEXT_ALIGN_CENTER },
|
|
{ "char", NS_STYLE_TEXT_ALIGN_CHAR },
|
|
{ "justify",NS_STYLE_TEXT_ALIGN_JUSTIFY },
|
|
{ 0 }
|
|
};
|
|
|
|
bool
|
|
nsGenericHTMLElement::ParseTableHAlignValue(const nsAString& aString,
|
|
nsAttrValue& aResult)
|
|
{
|
|
return aResult.ParseEnumValue(aString, kTableHAlignTable, false);
|
|
}
|
|
|
|
//----------------------------------------
|
|
|
|
// This table is used for td, th, tr, col, thead, tbody and tfoot.
|
|
static const nsAttrValue::EnumTable kTableCellHAlignTable[] = {
|
|
{ "left", NS_STYLE_TEXT_ALIGN_MOZ_LEFT },
|
|
{ "right", NS_STYLE_TEXT_ALIGN_MOZ_RIGHT },
|
|
{ "center", NS_STYLE_TEXT_ALIGN_MOZ_CENTER },
|
|
{ "char", NS_STYLE_TEXT_ALIGN_CHAR },
|
|
{ "justify",NS_STYLE_TEXT_ALIGN_JUSTIFY },
|
|
{ "middle", NS_STYLE_TEXT_ALIGN_MOZ_CENTER },
|
|
{ "absmiddle", NS_STYLE_TEXT_ALIGN_CENTER },
|
|
{ 0 }
|
|
};
|
|
|
|
bool
|
|
nsGenericHTMLElement::ParseTableCellHAlignValue(const nsAString& aString,
|
|
nsAttrValue& aResult)
|
|
{
|
|
return aResult.ParseEnumValue(aString, kTableCellHAlignTable, false);
|
|
}
|
|
|
|
//----------------------------------------
|
|
|
|
bool
|
|
nsGenericHTMLElement::ParseTableVAlignValue(const nsAString& aString,
|
|
nsAttrValue& aResult)
|
|
{
|
|
return aResult.ParseEnumValue(aString, kTableVAlignTable, false);
|
|
}
|
|
|
|
bool
|
|
nsGenericHTMLElement::ParseDivAlignValue(const nsAString& aString,
|
|
nsAttrValue& aResult)
|
|
{
|
|
return aResult.ParseEnumValue(aString, kDivAlignTable, false);
|
|
}
|
|
|
|
bool
|
|
nsGenericHTMLElement::ParseImageAttribute(nsIAtom* aAttribute,
|
|
const nsAString& aString,
|
|
nsAttrValue& aResult)
|
|
{
|
|
if ((aAttribute == nsGkAtoms::width) ||
|
|
(aAttribute == nsGkAtoms::height)) {
|
|
return aResult.ParseSpecialIntValue(aString);
|
|
}
|
|
if ((aAttribute == nsGkAtoms::hspace) ||
|
|
(aAttribute == nsGkAtoms::vspace) ||
|
|
(aAttribute == nsGkAtoms::border)) {
|
|
return aResult.ParseIntWithBounds(aString, 0);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
nsGenericHTMLElement::ParseReferrerAttribute(const nsAString& aString,
|
|
nsAttrValue& aResult)
|
|
{
|
|
static const nsAttrValue::EnumTable kReferrerTable[] = {
|
|
{ "no-referrer", net::RP_No_Referrer },
|
|
{ "origin", net::RP_Origin },
|
|
{ "unsafe-url", net::RP_Unsafe_URL },
|
|
{ 0 }
|
|
};
|
|
return aResult.ParseEnumValue(aString, kReferrerTable, false);
|
|
}
|
|
|
|
bool
|
|
nsGenericHTMLElement::ParseFrameborderValue(const nsAString& aString,
|
|
nsAttrValue& aResult)
|
|
{
|
|
return aResult.ParseEnumValue(aString, kFrameborderTable, false);
|
|
}
|
|
|
|
bool
|
|
nsGenericHTMLElement::ParseScrollingValue(const nsAString& aString,
|
|
nsAttrValue& aResult)
|
|
{
|
|
return aResult.ParseEnumValue(aString, kScrollingTable, false);
|
|
}
|
|
|
|
static inline void
|
|
MapLangAttributeInto(const nsMappedAttributes* aAttributes, nsRuleData* aData)
|
|
{
|
|
if (!(aData->mSIDs & (NS_STYLE_INHERIT_BIT(Font) |
|
|
NS_STYLE_INHERIT_BIT(Text)))) {
|
|
return;
|
|
}
|
|
|
|
const nsAttrValue* langValue = aAttributes->GetAttr(nsGkAtoms::lang);
|
|
if (!langValue || langValue->Type() != nsAttrValue::eString) {
|
|
return;
|
|
}
|
|
|
|
if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Font)) {
|
|
nsCSSValue* lang = aData->ValueForLang();
|
|
if (lang->GetUnit() == eCSSUnit_Null) {
|
|
lang->SetStringValue(langValue->GetStringValue(), eCSSUnit_Ident);
|
|
}
|
|
}
|
|
if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Text)) {
|
|
nsCSSValue* emphasisPos = aData->ValueForTextEmphasisPosition();
|
|
if (emphasisPos->GetUnit() == eCSSUnit_Null) {
|
|
const nsAString& lang = langValue->GetStringValue();
|
|
if (nsStyleUtil::MatchesLanguagePrefix(lang, MOZ_UTF16("zh"))) {
|
|
emphasisPos->SetIntValue(NS_STYLE_TEXT_EMPHASIS_POSITION_DEFAULT_ZH,
|
|
eCSSUnit_Enumerated);
|
|
} else if (nsStyleUtil::MatchesLanguagePrefix(lang, MOZ_UTF16("ja")) ||
|
|
nsStyleUtil::MatchesLanguagePrefix(lang, MOZ_UTF16("mn"))) {
|
|
// This branch is currently no part of the spec.
|
|
// See bug 1040668 comment 69 and comment 75.
|
|
emphasisPos->SetIntValue(NS_STYLE_TEXT_EMPHASIS_POSITION_DEFAULT,
|
|
eCSSUnit_Enumerated);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Handle attributes common to all html elements
|
|
*/
|
|
void
|
|
nsGenericHTMLElement::MapCommonAttributesIntoExceptHidden(const nsMappedAttributes* aAttributes,
|
|
nsRuleData* aData)
|
|
{
|
|
if (aData->mSIDs & NS_STYLE_INHERIT_BIT(UserInterface)) {
|
|
nsCSSValue* userModify = aData->ValueForUserModify();
|
|
if (userModify->GetUnit() == eCSSUnit_Null) {
|
|
const nsAttrValue* value =
|
|
aAttributes->GetAttr(nsGkAtoms::contenteditable);
|
|
if (value) {
|
|
if (value->Equals(nsGkAtoms::_empty, eCaseMatters) ||
|
|
value->Equals(nsGkAtoms::_true, eIgnoreCase)) {
|
|
userModify->SetIntValue(NS_STYLE_USER_MODIFY_READ_WRITE,
|
|
eCSSUnit_Enumerated);
|
|
}
|
|
else if (value->Equals(nsGkAtoms::_false, eIgnoreCase)) {
|
|
userModify->SetIntValue(NS_STYLE_USER_MODIFY_READ_ONLY,
|
|
eCSSUnit_Enumerated);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
MapLangAttributeInto(aAttributes, aData);
|
|
}
|
|
|
|
void
|
|
nsGenericHTMLElement::MapCommonAttributesInto(const nsMappedAttributes* aAttributes,
|
|
nsRuleData* aData)
|
|
{
|
|
MapCommonAttributesIntoExceptHidden(aAttributes, aData);
|
|
|
|
if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Display)) {
|
|
nsCSSValue* display = aData->ValueForDisplay();
|
|
if (display->GetUnit() == eCSSUnit_Null) {
|
|
if (aAttributes->IndexOfAttr(nsGkAtoms::hidden) >= 0) {
|
|
display->SetIntValue(NS_STYLE_DISPLAY_NONE, eCSSUnit_Enumerated);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* static */ const nsGenericHTMLElement::MappedAttributeEntry
|
|
nsGenericHTMLElement::sCommonAttributeMap[] = {
|
|
{ &nsGkAtoms::contenteditable },
|
|
{ &nsGkAtoms::lang },
|
|
{ &nsGkAtoms::hidden },
|
|
{ nullptr }
|
|
};
|
|
|
|
/* static */ const Element::MappedAttributeEntry
|
|
nsGenericHTMLElement::sImageMarginSizeAttributeMap[] = {
|
|
{ &nsGkAtoms::width },
|
|
{ &nsGkAtoms::height },
|
|
{ &nsGkAtoms::hspace },
|
|
{ &nsGkAtoms::vspace },
|
|
{ nullptr }
|
|
};
|
|
|
|
/* static */ const Element::MappedAttributeEntry
|
|
nsGenericHTMLElement::sImageAlignAttributeMap[] = {
|
|
{ &nsGkAtoms::align },
|
|
{ nullptr }
|
|
};
|
|
|
|
/* static */ const Element::MappedAttributeEntry
|
|
nsGenericHTMLElement::sDivAlignAttributeMap[] = {
|
|
{ &nsGkAtoms::align },
|
|
{ nullptr }
|
|
};
|
|
|
|
/* static */ const Element::MappedAttributeEntry
|
|
nsGenericHTMLElement::sImageBorderAttributeMap[] = {
|
|
{ &nsGkAtoms::border },
|
|
{ nullptr }
|
|
};
|
|
|
|
/* static */ const Element::MappedAttributeEntry
|
|
nsGenericHTMLElement::sBackgroundAttributeMap[] = {
|
|
{ &nsGkAtoms::background },
|
|
{ &nsGkAtoms::bgcolor },
|
|
{ nullptr }
|
|
};
|
|
|
|
/* static */ const Element::MappedAttributeEntry
|
|
nsGenericHTMLElement::sBackgroundColorAttributeMap[] = {
|
|
{ &nsGkAtoms::bgcolor },
|
|
{ nullptr }
|
|
};
|
|
|
|
void
|
|
nsGenericHTMLElement::MapImageAlignAttributeInto(const nsMappedAttributes* aAttributes,
|
|
nsRuleData* aRuleData)
|
|
{
|
|
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();
|
|
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* 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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
nsGenericHTMLElement::MapDivAlignAttributeInto(const nsMappedAttributes* aAttributes,
|
|
nsRuleData* aRuleData)
|
|
{
|
|
if (aRuleData->mSIDs & NS_STYLE_INHERIT_BIT(Text)) {
|
|
nsCSSValue* textAlign = aRuleData->ValueForTextAlign();
|
|
if (textAlign->GetUnit() == eCSSUnit_Null) {
|
|
// align: enum
|
|
const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::align);
|
|
if (value && value->Type() == nsAttrValue::eEnum)
|
|
textAlign->SetIntValue(value->GetEnumValue(), eCSSUnit_Enumerated);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
nsGenericHTMLElement::MapImageMarginAttributeInto(const nsMappedAttributes* aAttributes,
|
|
nsRuleData* aData)
|
|
{
|
|
if (!(aData->mSIDs & NS_STYLE_INHERIT_BIT(Margin)))
|
|
return;
|
|
|
|
const nsAttrValue* value;
|
|
|
|
// hspace: value
|
|
value = aAttributes->GetAttr(nsGkAtoms::hspace);
|
|
if (value) {
|
|
nsCSSValue hval;
|
|
if (value->Type() == nsAttrValue::eInteger)
|
|
hval.SetFloatValue((float)value->GetIntegerValue(), eCSSUnit_Pixel);
|
|
else if (value->Type() == nsAttrValue::ePercent)
|
|
hval.SetPercentValue(value->GetPercentValue());
|
|
|
|
if (hval.GetUnit() != eCSSUnit_Null) {
|
|
nsCSSValue* left = aData->ValueForMarginLeft();
|
|
if (left->GetUnit() == eCSSUnit_Null)
|
|
*left = hval;
|
|
nsCSSValue* right = aData->ValueForMarginRight();
|
|
if (right->GetUnit() == eCSSUnit_Null)
|
|
*right = hval;
|
|
}
|
|
}
|
|
|
|
// vspace: value
|
|
value = aAttributes->GetAttr(nsGkAtoms::vspace);
|
|
if (value) {
|
|
nsCSSValue vval;
|
|
if (value->Type() == nsAttrValue::eInteger)
|
|
vval.SetFloatValue((float)value->GetIntegerValue(), eCSSUnit_Pixel);
|
|
else if (value->Type() == nsAttrValue::ePercent)
|
|
vval.SetPercentValue(value->GetPercentValue());
|
|
|
|
if (vval.GetUnit() != eCSSUnit_Null) {
|
|
nsCSSValue* top = aData->ValueForMarginTop();
|
|
if (top->GetUnit() == eCSSUnit_Null)
|
|
*top = vval;
|
|
nsCSSValue* bottom = aData->ValueForMarginBottom();
|
|
if (bottom->GetUnit() == eCSSUnit_Null)
|
|
*bottom = vval;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
nsGenericHTMLElement::MapImageSizeAttributesInto(const nsMappedAttributes* aAttributes,
|
|
nsRuleData* aData)
|
|
{
|
|
if (!(aData->mSIDs & NS_STYLE_INHERIT_BIT(Position)))
|
|
return;
|
|
|
|
// width: value
|
|
nsCSSValue* width = aData->ValueForWidth();
|
|
if (width->GetUnit() == eCSSUnit_Null) {
|
|
const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::width);
|
|
if (value && value->Type() == nsAttrValue::eInteger)
|
|
width->SetFloatValue((float)value->GetIntegerValue(), eCSSUnit_Pixel);
|
|
else if (value && value->Type() == nsAttrValue::ePercent)
|
|
width->SetPercentValue(value->GetPercentValue());
|
|
}
|
|
|
|
// height: value
|
|
nsCSSValue* height = aData->ValueForHeight();
|
|
if (height->GetUnit() == eCSSUnit_Null) {
|
|
const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::height);
|
|
if (value && value->Type() == nsAttrValue::eInteger)
|
|
height->SetFloatValue((float)value->GetIntegerValue(), eCSSUnit_Pixel);
|
|
else if (value && value->Type() == nsAttrValue::ePercent)
|
|
height->SetPercentValue(value->GetPercentValue());
|
|
}
|
|
}
|
|
|
|
void
|
|
nsGenericHTMLElement::MapImageBorderAttributeInto(const nsMappedAttributes* aAttributes,
|
|
nsRuleData* aData)
|
|
{
|
|
if (!(aData->mSIDs & NS_STYLE_INHERIT_BIT(Border)))
|
|
return;
|
|
|
|
// border: pixels
|
|
const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::border);
|
|
if (!value)
|
|
return;
|
|
|
|
nscoord val = 0;
|
|
if (value->Type() == nsAttrValue::eInteger)
|
|
val = value->GetIntegerValue();
|
|
|
|
nsCSSValue* borderLeftWidth = aData->ValueForBorderLeftWidth();
|
|
if (borderLeftWidth->GetUnit() == eCSSUnit_Null)
|
|
borderLeftWidth->SetFloatValue((float)val, eCSSUnit_Pixel);
|
|
nsCSSValue* borderTopWidth = aData->ValueForBorderTopWidth();
|
|
if (borderTopWidth->GetUnit() == eCSSUnit_Null)
|
|
borderTopWidth->SetFloatValue((float)val, eCSSUnit_Pixel);
|
|
nsCSSValue* borderRightWidth = aData->ValueForBorderRightWidth();
|
|
if (borderRightWidth->GetUnit() == eCSSUnit_Null)
|
|
borderRightWidth->SetFloatValue((float)val, eCSSUnit_Pixel);
|
|
nsCSSValue* borderBottomWidth = aData->ValueForBorderBottomWidth();
|
|
if (borderBottomWidth->GetUnit() == eCSSUnit_Null)
|
|
borderBottomWidth->SetFloatValue((float)val, eCSSUnit_Pixel);
|
|
|
|
nsCSSValue* borderLeftStyle = aData->ValueForBorderLeftStyle();
|
|
if (borderLeftStyle->GetUnit() == eCSSUnit_Null)
|
|
borderLeftStyle->SetIntValue(NS_STYLE_BORDER_STYLE_SOLID, eCSSUnit_Enumerated);
|
|
nsCSSValue* borderTopStyle = aData->ValueForBorderTopStyle();
|
|
if (borderTopStyle->GetUnit() == eCSSUnit_Null)
|
|
borderTopStyle->SetIntValue(NS_STYLE_BORDER_STYLE_SOLID, eCSSUnit_Enumerated);
|
|
nsCSSValue* borderRightStyle = aData->ValueForBorderRightStyle();
|
|
if (borderRightStyle->GetUnit() == eCSSUnit_Null)
|
|
borderRightStyle->SetIntValue(NS_STYLE_BORDER_STYLE_SOLID, eCSSUnit_Enumerated);
|
|
nsCSSValue* borderBottomStyle = aData->ValueForBorderBottomStyle();
|
|
if (borderBottomStyle->GetUnit() == eCSSUnit_Null)
|
|
borderBottomStyle->SetIntValue(NS_STYLE_BORDER_STYLE_SOLID, eCSSUnit_Enumerated);
|
|
|
|
nsCSSValue* borderLeftColor = aData->ValueForBorderLeftColor();
|
|
if (borderLeftColor->GetUnit() == eCSSUnit_Null)
|
|
borderLeftColor->SetIntValue(NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR, eCSSUnit_Enumerated);
|
|
nsCSSValue* borderTopColor = aData->ValueForBorderTopColor();
|
|
if (borderTopColor->GetUnit() == eCSSUnit_Null)
|
|
borderTopColor->SetIntValue(NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR, eCSSUnit_Enumerated);
|
|
nsCSSValue* borderRightColor = aData->ValueForBorderRightColor();
|
|
if (borderRightColor->GetUnit() == eCSSUnit_Null)
|
|
borderRightColor->SetIntValue(NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR, eCSSUnit_Enumerated);
|
|
nsCSSValue* borderBottomColor = aData->ValueForBorderBottomColor();
|
|
if (borderBottomColor->GetUnit() == eCSSUnit_Null)
|
|
borderBottomColor->SetIntValue(NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR, eCSSUnit_Enumerated);
|
|
}
|
|
|
|
void
|
|
nsGenericHTMLElement::MapBackgroundInto(const nsMappedAttributes* aAttributes,
|
|
nsRuleData* aData)
|
|
{
|
|
if (!(aData->mSIDs & NS_STYLE_INHERIT_BIT(Background)))
|
|
return;
|
|
|
|
nsPresContext* presContext = aData->mPresContext;
|
|
nsCSSValue* backImage = aData->ValueForBackgroundImage();
|
|
if (backImage->GetUnit() == eCSSUnit_Null &&
|
|
presContext->UseDocumentColors()) {
|
|
// background
|
|
nsAttrValue* value =
|
|
const_cast<nsAttrValue*>(aAttributes->GetAttr(nsGkAtoms::background));
|
|
// If the value is an image, or it is a URL and we attempted a load,
|
|
// put it in the style tree.
|
|
if (value) {
|
|
if (value->Type() == nsAttrValue::eURL) {
|
|
value->LoadImage(presContext->Document());
|
|
}
|
|
if (value->Type() == nsAttrValue::eImage) {
|
|
nsCSSValueList* list = backImage->SetListValue();
|
|
list->mValue.SetImageValue(value->GetImageValue());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
nsGenericHTMLElement::MapBGColorInto(const nsMappedAttributes* aAttributes,
|
|
nsRuleData* aData)
|
|
{
|
|
if (!(aData->mSIDs & NS_STYLE_INHERIT_BIT(Background)))
|
|
return;
|
|
|
|
nsCSSValue* backColor = aData->ValueForBackgroundColor();
|
|
if (backColor->GetUnit() == eCSSUnit_Null &&
|
|
aData->mPresContext->UseDocumentColors()) {
|
|
const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::bgcolor);
|
|
nscolor color;
|
|
if (value && value->GetColorValue(color)) {
|
|
backColor->SetColorValue(color);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
nsGenericHTMLElement::MapBackgroundAttributesInto(const nsMappedAttributes* aAttributes,
|
|
nsRuleData* aData)
|
|
{
|
|
MapBackgroundInto(aAttributes, aData);
|
|
MapBGColorInto(aAttributes, aData);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
nsresult
|
|
nsGenericHTMLElement::SetAttrHelper(nsIAtom* aAttr, const nsAString& aValue)
|
|
{
|
|
return SetAttr(kNameSpaceID_None, aAttr, aValue, true);
|
|
}
|
|
|
|
int32_t
|
|
nsGenericHTMLElement::GetIntAttr(nsIAtom* aAttr, int32_t aDefault) const
|
|
{
|
|
const nsAttrValue* attrVal = mAttrsAndChildren.GetAttr(aAttr);
|
|
if (attrVal && attrVal->Type() == nsAttrValue::eInteger) {
|
|
return attrVal->GetIntegerValue();
|
|
}
|
|
return aDefault;
|
|
}
|
|
|
|
nsresult
|
|
nsGenericHTMLElement::SetIntAttr(nsIAtom* aAttr, int32_t aValue)
|
|
{
|
|
nsAutoString value;
|
|
value.AppendInt(aValue);
|
|
|
|
return SetAttr(kNameSpaceID_None, aAttr, value, true);
|
|
}
|
|
|
|
uint32_t
|
|
nsGenericHTMLElement::GetUnsignedIntAttr(nsIAtom* aAttr,
|
|
uint32_t aDefault) const
|
|
{
|
|
const nsAttrValue* attrVal = mAttrsAndChildren.GetAttr(aAttr);
|
|
if (!attrVal || attrVal->Type() != nsAttrValue::eInteger) {
|
|
return aDefault;
|
|
}
|
|
|
|
return attrVal->GetIntegerValue();
|
|
}
|
|
|
|
void
|
|
nsGenericHTMLElement::GetURIAttr(nsIAtom* aAttr, nsIAtom* aBaseAttr,
|
|
nsAString& aResult) const
|
|
{
|
|
nsCOMPtr<nsIURI> uri;
|
|
bool hadAttr = GetURIAttr(aAttr, aBaseAttr, getter_AddRefs(uri));
|
|
if (!hadAttr) {
|
|
aResult.Truncate();
|
|
return;
|
|
}
|
|
|
|
if (!uri) {
|
|
// Just return the attr value
|
|
GetAttr(kNameSpaceID_None, aAttr, aResult);
|
|
return;
|
|
}
|
|
|
|
nsAutoCString spec;
|
|
uri->GetSpec(spec);
|
|
CopyUTF8toUTF16(spec, aResult);
|
|
}
|
|
|
|
bool
|
|
nsGenericHTMLElement::GetURIAttr(nsIAtom* aAttr, nsIAtom* aBaseAttr, nsIURI** aURI) const
|
|
{
|
|
*aURI = nullptr;
|
|
|
|
const nsAttrValue* attr = mAttrsAndChildren.GetAttr(aAttr);
|
|
if (!attr) {
|
|
return false;
|
|
}
|
|
|
|
nsCOMPtr<nsIURI> baseURI = GetBaseURI();
|
|
|
|
if (aBaseAttr) {
|
|
nsAutoString baseAttrValue;
|
|
if (GetAttr(kNameSpaceID_None, aBaseAttr, baseAttrValue)) {
|
|
nsCOMPtr<nsIURI> baseAttrURI;
|
|
nsresult rv =
|
|
nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(baseAttrURI),
|
|
baseAttrValue, OwnerDoc(),
|
|
baseURI);
|
|
if (NS_FAILED(rv)) {
|
|
return true;
|
|
}
|
|
baseURI.swap(baseAttrURI);
|
|
}
|
|
}
|
|
|
|
// Don't care about return value. If it fails, we still want to
|
|
// return true, and *aURI will be null.
|
|
nsContentUtils::NewURIWithDocumentCharset(aURI,
|
|
attr->GetStringValue(),
|
|
OwnerDoc(), baseURI);
|
|
return true;
|
|
}
|
|
|
|
/* static */ bool
|
|
nsGenericHTMLElement::IsScrollGrabAllowed(JSContext*, JSObject*)
|
|
{
|
|
// Only allow scroll grabbing in chrome and certified apps.
|
|
nsIPrincipal* prin = nsContentUtils::SubjectPrincipal();
|
|
return nsContentUtils::IsSystemPrincipal(prin) ||
|
|
prin->GetAppStatus() == nsIPrincipal::APP_STATUS_CERTIFIED;
|
|
}
|
|
|
|
nsresult
|
|
nsGenericHTMLElement::GetURIListAttr(nsIAtom* aAttr, nsAString& aResult)
|
|
{
|
|
aResult.Truncate();
|
|
|
|
nsAutoString value;
|
|
if (!GetAttr(kNameSpaceID_None, aAttr, value))
|
|
return NS_OK;
|
|
|
|
nsIDocument* doc = OwnerDoc();
|
|
nsCOMPtr<nsIURI> baseURI = GetBaseURI();
|
|
|
|
nsString::const_iterator end;
|
|
value.EndReading(end);
|
|
|
|
nsAString::const_iterator iter;
|
|
value.BeginReading(iter);
|
|
|
|
while (iter != end) {
|
|
while (*iter == ' ' && iter != end) {
|
|
++iter;
|
|
}
|
|
|
|
if (iter == end) {
|
|
break;
|
|
}
|
|
|
|
nsAString::const_iterator start = iter;
|
|
|
|
while (iter != end && *iter != ' ') {
|
|
++iter;
|
|
}
|
|
|
|
if (!aResult.IsEmpty()) {
|
|
aResult.Append(NS_LITERAL_STRING(" "));
|
|
}
|
|
|
|
const nsSubstring& uriPart = Substring(start, iter);
|
|
nsCOMPtr<nsIURI> attrURI;
|
|
nsresult rv =
|
|
nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(attrURI),
|
|
uriPart, doc, baseURI);
|
|
if (NS_FAILED(rv)) {
|
|
aResult.Append(uriPart);
|
|
continue;
|
|
}
|
|
|
|
MOZ_ASSERT(attrURI);
|
|
|
|
nsAutoCString spec;
|
|
rv = attrURI->GetSpec(spec);
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
aResult.Append(uriPart);
|
|
continue;
|
|
}
|
|
|
|
AppendUTF8toUTF16(spec, aResult);
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
HTMLMenuElement*
|
|
nsGenericHTMLElement::GetContextMenu() const
|
|
{
|
|
nsAutoString value;
|
|
GetHTMLAttr(nsGkAtoms::contextmenu, value);
|
|
if (!value.IsEmpty()) {
|
|
//XXXsmaug How should this work in Shadow DOM?
|
|
nsIDocument* doc = GetUncomposedDoc();
|
|
if (doc) {
|
|
return HTMLMenuElement::FromContentOrNull(doc->GetElementById(value));
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsGenericHTMLElement::GetContextMenu(nsIDOMHTMLMenuElement** aContextMenu)
|
|
{
|
|
NS_IF_ADDREF(*aContextMenu = GetContextMenu());
|
|
return NS_OK;
|
|
}
|
|
|
|
bool
|
|
nsGenericHTMLElement::IsLabelable() const
|
|
{
|
|
return IsAnyOfHTMLElements(nsGkAtoms::progress, nsGkAtoms::meter);
|
|
}
|
|
|
|
bool
|
|
nsGenericHTMLElement::IsInteractiveHTMLContent(bool aIgnoreTabindex) const
|
|
{
|
|
return IsAnyOfHTMLElements(nsGkAtoms::details, nsGkAtoms::embed,
|
|
nsGkAtoms::keygen) ||
|
|
(!aIgnoreTabindex && HasAttr(kNameSpaceID_None, nsGkAtoms::tabindex));
|
|
}
|
|
|
|
already_AddRefed<UndoManager>
|
|
nsGenericHTMLElement::GetUndoManager()
|
|
{
|
|
nsDOMSlots* slots = GetExistingDOMSlots();
|
|
if (slots && slots->mUndoManager) {
|
|
RefPtr<UndoManager> undoManager = slots->mUndoManager;
|
|
return undoManager.forget();
|
|
} else {
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
bool
|
|
nsGenericHTMLElement::UndoScope()
|
|
{
|
|
nsDOMSlots* slots = GetExistingDOMSlots();
|
|
return slots && slots->mUndoManager;
|
|
}
|
|
|
|
void
|
|
nsGenericHTMLElement::SetUndoScope(bool aUndoScope, mozilla::ErrorResult& aError)
|
|
{
|
|
nsresult rv = SetUndoScopeInternal(aUndoScope);
|
|
if (NS_FAILED(rv)) {
|
|
aError.Throw(rv);
|
|
return;
|
|
}
|
|
|
|
// The undoScope property must reflect the undoscope boolean attribute.
|
|
if (aUndoScope) {
|
|
rv = SetAttr(kNameSpaceID_None, nsGkAtoms::undoscope,
|
|
NS_LITERAL_STRING(""), true);
|
|
} else {
|
|
rv = UnsetAttr(kNameSpaceID_None, nsGkAtoms::undoscope, true);
|
|
}
|
|
|
|
if (NS_FAILED(rv)) {
|
|
aError.Throw(rv);
|
|
return;
|
|
}
|
|
}
|
|
|
|
nsresult
|
|
nsGenericHTMLElement::SetUndoScopeInternal(bool aUndoScope)
|
|
{
|
|
if (aUndoScope) {
|
|
nsDOMSlots* slots = DOMSlots();
|
|
if (!slots->mUndoManager) {
|
|
slots->mUndoManager = new UndoManager(this);
|
|
}
|
|
} else {
|
|
nsDOMSlots* slots = GetExistingDOMSlots();
|
|
if (slots && slots->mUndoManager) {
|
|
// Clear transaction history and disconnect.
|
|
ErrorResult rv;
|
|
slots->mUndoManager->ClearRedo(rv);
|
|
if (rv.Failed()) {
|
|
return rv.StealNSResult();
|
|
}
|
|
|
|
slots->mUndoManager->ClearUndo(rv);
|
|
if (rv.Failed()) {
|
|
return rv.StealNSResult();
|
|
}
|
|
|
|
slots->mUndoManager->Disconnect();
|
|
slots->mUndoManager = nullptr;
|
|
}
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
// static
|
|
bool
|
|
nsGenericHTMLElement::TouchEventsEnabled(JSContext* /* unused */, JSObject* /* unused */)
|
|
{
|
|
return TouchEvent::PrefEnabled();
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
nsGenericHTMLFormElement::nsGenericHTMLFormElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
|
|
: nsGenericHTMLElement(aNodeInfo)
|
|
, mForm(nullptr)
|
|
, mFieldSet(nullptr)
|
|
{
|
|
// We should add the NS_EVENT_STATE_ENABLED bit here as needed, but
|
|
// that depends on our type, which is not initialized yet. So we
|
|
// have to do this in subclasses.
|
|
}
|
|
|
|
nsGenericHTMLFormElement::~nsGenericHTMLFormElement()
|
|
{
|
|
if (mFieldSet) {
|
|
mFieldSet->RemoveElement(this);
|
|
}
|
|
|
|
// Check that this element doesn't know anything about its form at this point.
|
|
NS_ASSERTION(!mForm, "mForm should be null at this point!");
|
|
}
|
|
|
|
NS_IMPL_ISUPPORTS_INHERITED(nsGenericHTMLFormElement,
|
|
nsGenericHTMLElement,
|
|
nsIFormControl)
|
|
|
|
nsINode*
|
|
nsGenericHTMLFormElement::GetScopeChainParent() const
|
|
{
|
|
return mForm ? mForm : nsGenericHTMLElement::GetScopeChainParent();
|
|
}
|
|
|
|
bool
|
|
nsGenericHTMLFormElement::IsNodeOfType(uint32_t aFlags) const
|
|
{
|
|
return !(aFlags & ~(eCONTENT | eHTML_FORM_CONTROL));
|
|
}
|
|
|
|
void
|
|
nsGenericHTMLFormElement::SaveSubtreeState()
|
|
{
|
|
SaveState();
|
|
|
|
nsGenericHTMLElement::SaveSubtreeState();
|
|
}
|
|
|
|
void
|
|
nsGenericHTMLFormElement::SetForm(nsIDOMHTMLFormElement* aForm)
|
|
{
|
|
NS_PRECONDITION(aForm, "Don't pass null here");
|
|
NS_ASSERTION(!mForm,
|
|
"We don't support switching from one non-null form to another.");
|
|
|
|
// keep a *weak* ref to the form here
|
|
mForm = static_cast<HTMLFormElement*>(aForm);
|
|
}
|
|
|
|
void
|
|
nsGenericHTMLFormElement::ClearForm(bool aRemoveFromForm)
|
|
{
|
|
NS_ASSERTION((mForm != nullptr) == HasFlag(ADDED_TO_FORM),
|
|
"Form control should have had flag set correctly");
|
|
|
|
if (!mForm) {
|
|
return;
|
|
}
|
|
|
|
if (aRemoveFromForm) {
|
|
nsAutoString nameVal, idVal;
|
|
GetAttr(kNameSpaceID_None, nsGkAtoms::name, nameVal);
|
|
GetAttr(kNameSpaceID_None, nsGkAtoms::id, idVal);
|
|
|
|
mForm->RemoveElement(this, true);
|
|
|
|
if (!nameVal.IsEmpty()) {
|
|
mForm->RemoveElementFromTable(this, nameVal,
|
|
HTMLFormElement::ElementRemoved);
|
|
}
|
|
|
|
if (!idVal.IsEmpty()) {
|
|
mForm->RemoveElementFromTable(this, idVal,
|
|
HTMLFormElement::ElementRemoved);
|
|
}
|
|
}
|
|
|
|
UnsetFlags(ADDED_TO_FORM);
|
|
mForm = nullptr;
|
|
}
|
|
|
|
Element*
|
|
nsGenericHTMLFormElement::GetFormElement()
|
|
{
|
|
return mForm;
|
|
}
|
|
|
|
HTMLFieldSetElement*
|
|
nsGenericHTMLFormElement::GetFieldSet()
|
|
{
|
|
return mFieldSet;
|
|
}
|
|
|
|
nsresult
|
|
nsGenericHTMLFormElement::GetForm(nsIDOMHTMLFormElement** aForm)
|
|
{
|
|
NS_ENSURE_ARG_POINTER(aForm);
|
|
NS_IF_ADDREF(*aForm = mForm);
|
|
return NS_OK;
|
|
}
|
|
|
|
nsIContent::IMEState
|
|
nsGenericHTMLFormElement::GetDesiredIMEState()
|
|
{
|
|
nsIEditor* editor = GetEditorInternal();
|
|
if (!editor)
|
|
return nsGenericHTMLElement::GetDesiredIMEState();
|
|
nsCOMPtr<nsIEditorIMESupport> imeEditor = do_QueryInterface(editor);
|
|
if (!imeEditor)
|
|
return nsGenericHTMLElement::GetDesiredIMEState();
|
|
IMEState state;
|
|
nsresult rv = imeEditor->GetPreferredIMEState(&state);
|
|
if (NS_FAILED(rv))
|
|
return nsGenericHTMLElement::GetDesiredIMEState();
|
|
return state;
|
|
}
|
|
|
|
nsresult
|
|
nsGenericHTMLFormElement::BindToTree(nsIDocument* aDocument,
|
|
nsIContent* aParent,
|
|
nsIContent* aBindingParent,
|
|
bool aCompileEventHandlers)
|
|
{
|
|
nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent,
|
|
aBindingParent,
|
|
aCompileEventHandlers);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
// An autofocus event has to be launched if the autofocus attribute is
|
|
// specified and the element accept the autofocus attribute. In addition,
|
|
// the document should not be already loaded and the "browser.autofocus"
|
|
// preference should be 'true'.
|
|
if (IsAutofocusable() && HasAttr(kNameSpaceID_None, nsGkAtoms::autofocus) &&
|
|
Preferences::GetBool("browser.autofocus", true)) {
|
|
nsCOMPtr<nsIRunnable> event = new nsAutoFocusEvent(this);
|
|
rv = NS_DispatchToCurrentThread(event);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
}
|
|
|
|
// If @form is set, the element *has* to be in a document, otherwise it
|
|
// wouldn't be possible to find an element with the corresponding id.
|
|
// If @form isn't set, the element *has* to have a parent, otherwise it
|
|
// wouldn't be possible to find a form ancestor.
|
|
// We should not call UpdateFormOwner if none of these conditions are
|
|
// fulfilled.
|
|
if (HasAttr(kNameSpaceID_None, nsGkAtoms::form) ? !!GetUncomposedDoc()
|
|
: !!aParent) {
|
|
UpdateFormOwner(true, nullptr);
|
|
}
|
|
|
|
// Set parent fieldset which should be used for the disabled state.
|
|
UpdateFieldSet(false);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
void
|
|
nsGenericHTMLFormElement::UnbindFromTree(bool aDeep, bool aNullParent)
|
|
{
|
|
// Save state before doing anything
|
|
SaveState();
|
|
|
|
if (mForm) {
|
|
// Might need to unset mForm
|
|
if (aNullParent) {
|
|
// No more parent means no more form
|
|
ClearForm(true);
|
|
} else {
|
|
// Recheck whether we should still have an mForm.
|
|
if (HasAttr(kNameSpaceID_None, nsGkAtoms::form) ||
|
|
!FindAncestorForm(mForm)) {
|
|
ClearForm(true);
|
|
} else {
|
|
UnsetFlags(MAYBE_ORPHAN_FORM_ELEMENT);
|
|
}
|
|
}
|
|
|
|
if (!mForm) {
|
|
// Our novalidate state might have changed
|
|
UpdateState(false);
|
|
}
|
|
}
|
|
|
|
// We have to remove the form id observer if there was one.
|
|
// We will re-add one later if needed (during bind to tree).
|
|
if (nsContentUtils::HasNonEmptyAttr(this, kNameSpaceID_None,
|
|
nsGkAtoms::form)) {
|
|
RemoveFormIdObserver();
|
|
}
|
|
|
|
nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
|
|
|
|
// The element might not have a fieldset anymore.
|
|
UpdateFieldSet(false);
|
|
}
|
|
|
|
nsresult
|
|
nsGenericHTMLFormElement::BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
|
nsAttrValueOrString* aValue,
|
|
bool aNotify)
|
|
{
|
|
if (aNameSpaceID == kNameSpaceID_None) {
|
|
nsAutoString tmp;
|
|
|
|
// remove the control from the hashtable as needed
|
|
|
|
if (mForm && (aName == nsGkAtoms::name || aName == nsGkAtoms::id)) {
|
|
GetAttr(kNameSpaceID_None, aName, tmp);
|
|
|
|
if (!tmp.IsEmpty()) {
|
|
mForm->RemoveElementFromTable(this, tmp,
|
|
HTMLFormElement::AttributeUpdated);
|
|
}
|
|
}
|
|
|
|
if (mForm && aName == nsGkAtoms::type) {
|
|
GetAttr(kNameSpaceID_None, nsGkAtoms::name, tmp);
|
|
|
|
if (!tmp.IsEmpty()) {
|
|
mForm->RemoveElementFromTable(this, tmp,
|
|
HTMLFormElement::AttributeUpdated);
|
|
}
|
|
|
|
GetAttr(kNameSpaceID_None, nsGkAtoms::id, tmp);
|
|
|
|
if (!tmp.IsEmpty()) {
|
|
mForm->RemoveElementFromTable(this, tmp,
|
|
HTMLFormElement::AttributeUpdated);
|
|
}
|
|
|
|
mForm->RemoveElement(this, false);
|
|
|
|
// Removing the element from the form can make it not be the default
|
|
// control anymore. Go ahead and notify on that change, though we might
|
|
// end up readding and becoming the default control again in
|
|
// AfterSetAttr.
|
|
// FIXME: Bug 656197
|
|
UpdateState(aNotify);
|
|
}
|
|
|
|
if (aName == nsGkAtoms::form) {
|
|
// If @form isn't set or set to the empty string, there were no observer
|
|
// so we don't have to remove it.
|
|
if (nsContentUtils::HasNonEmptyAttr(this, kNameSpaceID_None,
|
|
nsGkAtoms::form)) {
|
|
// The current form id observer is no longer needed.
|
|
// A new one may be added in AfterSetAttr.
|
|
RemoveFormIdObserver();
|
|
}
|
|
}
|
|
}
|
|
|
|
return nsGenericHTMLElement::BeforeSetAttr(aNameSpaceID, aName,
|
|
aValue, aNotify);
|
|
}
|
|
|
|
nsresult
|
|
nsGenericHTMLFormElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
|
const nsAttrValue* aValue, bool aNotify)
|
|
{
|
|
if (aNameSpaceID == kNameSpaceID_None) {
|
|
// add the control to the hashtable as needed
|
|
|
|
if (mForm && (aName == nsGkAtoms::name || aName == nsGkAtoms::id) &&
|
|
aValue && !aValue->IsEmptyString()) {
|
|
MOZ_ASSERT(aValue->Type() == nsAttrValue::eAtom,
|
|
"Expected atom value for name/id");
|
|
mForm->AddElementToTable(this,
|
|
nsDependentAtomString(aValue->GetAtomValue()));
|
|
}
|
|
|
|
if (mForm && aName == nsGkAtoms::type) {
|
|
nsAutoString tmp;
|
|
|
|
GetAttr(kNameSpaceID_None, nsGkAtoms::name, tmp);
|
|
|
|
if (!tmp.IsEmpty()) {
|
|
mForm->AddElementToTable(this, tmp);
|
|
}
|
|
|
|
GetAttr(kNameSpaceID_None, nsGkAtoms::id, tmp);
|
|
|
|
if (!tmp.IsEmpty()) {
|
|
mForm->AddElementToTable(this, tmp);
|
|
}
|
|
|
|
mForm->AddElement(this, false, aNotify);
|
|
|
|
// Adding the element to the form can make it be the default control .
|
|
// Go ahead and notify on that change.
|
|
// Note: no need to notify on CanBeDisabled(), since type attr
|
|
// changes can't affect that.
|
|
UpdateState(aNotify);
|
|
}
|
|
|
|
if (aName == nsGkAtoms::form) {
|
|
// We need a new form id observer.
|
|
//XXXsmaug How should this work in Shadow DOM?
|
|
nsIDocument* doc = GetUncomposedDoc();
|
|
if (doc) {
|
|
Element* formIdElement = nullptr;
|
|
if (aValue && !aValue->IsEmptyString()) {
|
|
formIdElement = AddFormIdObserver();
|
|
}
|
|
|
|
// Because we have a new @form value (or no more @form), we have to
|
|
// update our form owner.
|
|
UpdateFormOwner(false, formIdElement);
|
|
}
|
|
}
|
|
}
|
|
|
|
return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName,
|
|
aValue, aNotify);
|
|
}
|
|
|
|
nsresult
|
|
nsGenericHTMLFormElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
|
{
|
|
if (aVisitor.mEvent->IsTrusted()) {
|
|
switch (aVisitor.mEvent->mMessage) {
|
|
case eFocus: {
|
|
// Check to see if focus has bubbled up from a form control's
|
|
// child textfield or button. If that's the case, don't focus
|
|
// this parent file control -- leave focus on the child.
|
|
nsIFormControlFrame* formControlFrame = GetFormControlFrame(true);
|
|
if (formControlFrame &&
|
|
aVisitor.mEvent->originalTarget == static_cast<nsINode*>(this))
|
|
formControlFrame->SetFocus(true, true);
|
|
break;
|
|
}
|
|
case eBlur: {
|
|
nsIFormControlFrame* formControlFrame = GetFormControlFrame(true);
|
|
if (formControlFrame)
|
|
formControlFrame->SetFocus(false, false);
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
return nsGenericHTMLElement::PreHandleEvent(aVisitor);
|
|
}
|
|
|
|
/* virtual */
|
|
bool
|
|
nsGenericHTMLFormElement::IsDisabled() const
|
|
{
|
|
return State().HasState(NS_EVENT_STATE_DISABLED);
|
|
}
|
|
|
|
void
|
|
nsGenericHTMLFormElement::ForgetFieldSet(nsIContent* aFieldset)
|
|
{
|
|
if (mFieldSet == aFieldset) {
|
|
mFieldSet = nullptr;
|
|
}
|
|
}
|
|
|
|
bool
|
|
nsGenericHTMLFormElement::CanBeDisabled() const
|
|
{
|
|
int32_t type = GetType();
|
|
// It's easier to test the types that _cannot_ be disabled
|
|
return
|
|
type != NS_FORM_LABEL &&
|
|
type != NS_FORM_OBJECT &&
|
|
type != NS_FORM_OUTPUT;
|
|
}
|
|
|
|
bool
|
|
nsGenericHTMLFormElement::IsHTMLFocusable(bool aWithMouse,
|
|
bool* aIsFocusable,
|
|
int32_t* aTabIndex)
|
|
{
|
|
if (nsGenericHTMLElement::IsHTMLFocusable(aWithMouse, aIsFocusable, aTabIndex)) {
|
|
return true;
|
|
}
|
|
|
|
#ifdef XP_MACOSX
|
|
*aIsFocusable =
|
|
(!aWithMouse || nsFocusManager::sMouseFocusesFormControl) && *aIsFocusable;
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
EventStates
|
|
nsGenericHTMLFormElement::IntrinsicState() const
|
|
{
|
|
// If you add attribute-dependent states here, you need to add them them to
|
|
// AfterSetAttr too. And add them to AfterSetAttr for all subclasses that
|
|
// implement IntrinsicState() and are affected by that attribute.
|
|
EventStates state = nsGenericHTMLElement::IntrinsicState();
|
|
|
|
if (mForm && mForm->IsDefaultSubmitElement(this)) {
|
|
NS_ASSERTION(IsSubmitControl(),
|
|
"Default submit element that isn't a submit control.");
|
|
// We are the default submit element (:default)
|
|
state |= NS_EVENT_STATE_DEFAULT;
|
|
}
|
|
|
|
// Make the text controls read-write
|
|
if (!state.HasState(NS_EVENT_STATE_MOZ_READWRITE) &&
|
|
IsTextOrNumberControl(/*aExcludePassword*/ false)) {
|
|
bool roState = GetBoolAttr(nsGkAtoms::readonly);
|
|
|
|
if (!roState) {
|
|
state |= NS_EVENT_STATE_MOZ_READWRITE;
|
|
state &= ~NS_EVENT_STATE_MOZ_READONLY;
|
|
}
|
|
}
|
|
|
|
return state;
|
|
}
|
|
|
|
nsGenericHTMLFormElement::FocusTristate
|
|
nsGenericHTMLFormElement::FocusState()
|
|
{
|
|
// We can't be focused if we aren't in a (composed) document
|
|
nsIDocument* doc = GetComposedDoc();
|
|
if (!doc)
|
|
return eUnfocusable;
|
|
|
|
// first see if we are disabled or not. If disabled then do nothing.
|
|
if (IsDisabled()) {
|
|
return eUnfocusable;
|
|
}
|
|
|
|
// If the window is not active, do not allow the focus to bring the
|
|
// window to the front. We update the focus controller, but do
|
|
// nothing else.
|
|
nsPIDOMWindow* win = doc->GetWindow();
|
|
if (win) {
|
|
nsCOMPtr<nsIDOMWindow> rootWindow = do_QueryInterface(win->GetPrivateRoot());
|
|
|
|
nsCOMPtr<nsIFocusManager> fm = do_GetService(FOCUSMANAGER_CONTRACTID);
|
|
if (fm && rootWindow) {
|
|
nsCOMPtr<nsIDOMWindow> activeWindow;
|
|
fm->GetActiveWindow(getter_AddRefs(activeWindow));
|
|
if (activeWindow == rootWindow) {
|
|
return eActiveWindow;
|
|
}
|
|
}
|
|
}
|
|
|
|
return eInactiveWindow;
|
|
}
|
|
|
|
Element*
|
|
nsGenericHTMLFormElement::AddFormIdObserver()
|
|
{
|
|
NS_ASSERTION(GetUncomposedDoc(), "When adding a form id observer, "
|
|
"we should be in a document!");
|
|
|
|
nsAutoString formId;
|
|
nsIDocument* doc = OwnerDoc();
|
|
GetAttr(kNameSpaceID_None, nsGkAtoms::form, formId);
|
|
NS_ASSERTION(!formId.IsEmpty(),
|
|
"@form value should not be the empty string!");
|
|
nsCOMPtr<nsIAtom> atom = do_GetAtom(formId);
|
|
|
|
return doc->AddIDTargetObserver(atom, FormIdUpdated, this, false);
|
|
}
|
|
|
|
void
|
|
nsGenericHTMLFormElement::RemoveFormIdObserver()
|
|
{
|
|
/**
|
|
* We are using OwnerDoc() because we don't really care about having the
|
|
* element actually being in the tree. If it is not and @form value changes,
|
|
* this method will be called for nothing but removing an observer which does
|
|
* not exist doesn't cost so much (no entry in the hash table) so having a
|
|
* boolean for GetUncomposedDoc()/GetOwnerDoc() would make everything look
|
|
* more complex for nothing.
|
|
*/
|
|
|
|
nsIDocument* doc = OwnerDoc();
|
|
|
|
// At this point, we may not have a document anymore. In that case, we can't
|
|
// remove the observer. The document did that for us.
|
|
if (!doc) {
|
|
return;
|
|
}
|
|
|
|
nsAutoString formId;
|
|
GetAttr(kNameSpaceID_None, nsGkAtoms::form, formId);
|
|
NS_ASSERTION(!formId.IsEmpty(),
|
|
"@form value should not be the empty string!");
|
|
nsCOMPtr<nsIAtom> atom = do_GetAtom(formId);
|
|
|
|
doc->RemoveIDTargetObserver(atom, FormIdUpdated, this, false);
|
|
}
|
|
|
|
|
|
/* static */
|
|
bool
|
|
nsGenericHTMLFormElement::FormIdUpdated(Element* aOldElement,
|
|
Element* aNewElement,
|
|
void* aData)
|
|
{
|
|
nsGenericHTMLFormElement* element =
|
|
static_cast<nsGenericHTMLFormElement*>(aData);
|
|
|
|
NS_ASSERTION(element->IsHTMLElement(), "aData should be an HTML element");
|
|
|
|
element->UpdateFormOwner(false, aNewElement);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
nsGenericHTMLFormElement::IsElementDisabledForEvents(EventMessage aMessage,
|
|
nsIFrame* aFrame)
|
|
{
|
|
switch (aMessage) {
|
|
case eMouseMove:
|
|
case eMouseOver:
|
|
case eMouseOut:
|
|
case eMouseEnter:
|
|
case eMouseLeave:
|
|
case ePointerMove:
|
|
case ePointerOver:
|
|
case ePointerOut:
|
|
case ePointerEnter:
|
|
case ePointerLeave:
|
|
case eWheel:
|
|
case eLegacyMouseLineOrPageScroll:
|
|
case eLegacyMousePixelScroll:
|
|
return false;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
bool disabled = IsDisabled();
|
|
if (!disabled && aFrame) {
|
|
const nsStyleUserInterface* uiStyle = aFrame->StyleUserInterface();
|
|
disabled = uiStyle->mUserInput == NS_STYLE_USER_INPUT_NONE ||
|
|
uiStyle->mUserInput == NS_STYLE_USER_INPUT_DISABLED;
|
|
|
|
}
|
|
return disabled;
|
|
}
|
|
|
|
void
|
|
nsGenericHTMLFormElement::UpdateFormOwner(bool aBindToTree,
|
|
Element* aFormIdElement)
|
|
{
|
|
NS_PRECONDITION(!aBindToTree || !aFormIdElement,
|
|
"aFormIdElement shouldn't be set if aBindToTree is true!");
|
|
|
|
bool needStateUpdate = false;
|
|
if (!aBindToTree) {
|
|
needStateUpdate = mForm && mForm->IsDefaultSubmitElement(this);
|
|
ClearForm(true);
|
|
}
|
|
|
|
HTMLFormElement *oldForm = mForm;
|
|
|
|
if (!mForm) {
|
|
// If @form is set, we have to use that to find the form.
|
|
nsAutoString formId;
|
|
if (GetAttr(kNameSpaceID_None, nsGkAtoms::form, formId)) {
|
|
if (!formId.IsEmpty()) {
|
|
Element* element = nullptr;
|
|
|
|
if (aBindToTree) {
|
|
element = AddFormIdObserver();
|
|
} else {
|
|
element = aFormIdElement;
|
|
}
|
|
|
|
NS_ASSERTION(GetUncomposedDoc(), "The element should be in a document "
|
|
"when UpdateFormOwner is called!");
|
|
NS_ASSERTION(!GetUncomposedDoc() ||
|
|
element == GetUncomposedDoc()->GetElementById(formId),
|
|
"element should be equals to the current element "
|
|
"associated with the id in @form!");
|
|
|
|
if (element && element->IsHTMLElement(nsGkAtoms::form)) {
|
|
mForm = static_cast<HTMLFormElement*>(element);
|
|
}
|
|
}
|
|
} else {
|
|
// We now have a parent, so we may have picked up an ancestor form. Search
|
|
// for it. Note that if mForm is already set we don't want to do this,
|
|
// because that means someone (probably the content sink) has already set
|
|
// it to the right value. Also note that even if being bound here didn't
|
|
// change our parent, we still need to search, since our parent chain
|
|
// probably changed _somewhere_.
|
|
mForm = FindAncestorForm();
|
|
}
|
|
}
|
|
|
|
if (mForm && !HasFlag(ADDED_TO_FORM)) {
|
|
// Now we need to add ourselves to the form
|
|
nsAutoString nameVal, idVal;
|
|
GetAttr(kNameSpaceID_None, nsGkAtoms::name, nameVal);
|
|
GetAttr(kNameSpaceID_None, nsGkAtoms::id, idVal);
|
|
|
|
SetFlags(ADDED_TO_FORM);
|
|
|
|
// Notify only if we just found this mForm.
|
|
mForm->AddElement(this, true, oldForm == nullptr);
|
|
|
|
if (!nameVal.IsEmpty()) {
|
|
mForm->AddElementToTable(this, nameVal);
|
|
}
|
|
|
|
if (!idVal.IsEmpty()) {
|
|
mForm->AddElementToTable(this, idVal);
|
|
}
|
|
}
|
|
|
|
if (mForm != oldForm || needStateUpdate) {
|
|
UpdateState(true);
|
|
}
|
|
}
|
|
|
|
void
|
|
nsGenericHTMLFormElement::UpdateFieldSet(bool aNotify)
|
|
{
|
|
nsIContent* parent = nullptr;
|
|
nsIContent* prev = nullptr;
|
|
|
|
for (parent = GetParent(); parent;
|
|
prev = parent, parent = parent->GetParent()) {
|
|
HTMLFieldSetElement* fieldset =
|
|
HTMLFieldSetElement::FromContent(parent);
|
|
if (fieldset &&
|
|
(!prev || fieldset->GetFirstLegend() != prev)) {
|
|
if (mFieldSet == fieldset) {
|
|
// We already have the right fieldset;
|
|
return;
|
|
}
|
|
|
|
if (mFieldSet) {
|
|
mFieldSet->RemoveElement(this);
|
|
}
|
|
mFieldSet = fieldset;
|
|
fieldset->AddElement(this);
|
|
|
|
// The disabled state may have changed
|
|
FieldSetDisabledChanged(aNotify);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// No fieldset found.
|
|
if (mFieldSet) {
|
|
mFieldSet->RemoveElement(this);
|
|
mFieldSet = nullptr;
|
|
// The disabled state may have changed
|
|
FieldSetDisabledChanged(aNotify);
|
|
}
|
|
}
|
|
|
|
void nsGenericHTMLFormElement::UpdateDisabledState(bool aNotify)
|
|
{
|
|
if (!CanBeDisabled()) {
|
|
return;
|
|
}
|
|
|
|
bool isDisabled = HasAttr(kNameSpaceID_None, nsGkAtoms::disabled);
|
|
|
|
if (!isDisabled && mFieldSet) {
|
|
isDisabled = mFieldSet->IsDisabled();
|
|
}
|
|
|
|
EventStates disabledStates;
|
|
if (isDisabled) {
|
|
disabledStates |= NS_EVENT_STATE_DISABLED;
|
|
} else {
|
|
disabledStates |= NS_EVENT_STATE_ENABLED;
|
|
}
|
|
|
|
EventStates oldDisabledStates = State() & DISABLED_STATES;
|
|
EventStates changedStates = disabledStates ^ oldDisabledStates;
|
|
|
|
if (!changedStates.IsEmpty()) {
|
|
ToggleStates(changedStates, aNotify);
|
|
}
|
|
}
|
|
|
|
void
|
|
nsGenericHTMLFormElement::FieldSetDisabledChanged(bool aNotify)
|
|
{
|
|
UpdateDisabledState(aNotify);
|
|
}
|
|
|
|
bool
|
|
nsGenericHTMLFormElement::IsLabelable() const
|
|
{
|
|
// TODO: keygen should be in that list, see bug 101019.
|
|
uint32_t type = GetType();
|
|
return (type & NS_FORM_INPUT_ELEMENT && type != NS_FORM_INPUT_HIDDEN) ||
|
|
type & NS_FORM_BUTTON_ELEMENT ||
|
|
// type == NS_FORM_KEYGEN ||
|
|
type == NS_FORM_OUTPUT ||
|
|
type == NS_FORM_SELECT ||
|
|
type == NS_FORM_TEXTAREA;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
void
|
|
nsGenericHTMLElement::Blur(mozilla::ErrorResult& aError)
|
|
{
|
|
if (!ShouldBlur(this)) {
|
|
return;
|
|
}
|
|
|
|
nsIDocument* doc = GetComposedDoc();
|
|
if (!doc) {
|
|
return;
|
|
}
|
|
|
|
nsIDOMWindow* win = doc->GetWindow();
|
|
nsIFocusManager* fm = nsFocusManager::GetFocusManager();
|
|
if (win && fm) {
|
|
aError = fm->ClearFocus(win);
|
|
}
|
|
}
|
|
|
|
void
|
|
nsGenericHTMLElement::Focus(ErrorResult& aError)
|
|
{
|
|
nsIFocusManager* fm = nsFocusManager::GetFocusManager();
|
|
if (fm) {
|
|
aError = fm->SetFocus(this, 0);
|
|
}
|
|
}
|
|
|
|
void
|
|
nsGenericHTMLElement::Click()
|
|
{
|
|
if (HandlingClick())
|
|
return;
|
|
|
|
// Strong in case the event kills it
|
|
nsCOMPtr<nsIDocument> doc = GetComposedDoc();
|
|
|
|
nsCOMPtr<nsIPresShell> shell;
|
|
RefPtr<nsPresContext> context;
|
|
if (doc) {
|
|
shell = doc->GetShell();
|
|
if (shell) {
|
|
context = shell->GetPresContext();
|
|
}
|
|
}
|
|
|
|
SetHandlingClick();
|
|
|
|
// Click() is never called from native code, but it may be
|
|
// called from chrome JS. Mark this event trusted if Click()
|
|
// is called from chrome code.
|
|
WidgetMouseEvent event(nsContentUtils::IsCallerChrome(),
|
|
eMouseClick, nullptr, WidgetMouseEvent::eReal);
|
|
event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN;
|
|
|
|
EventDispatcher::Dispatch(static_cast<nsIContent*>(this), context, &event);
|
|
|
|
ClearHandlingClick();
|
|
}
|
|
|
|
bool
|
|
nsGenericHTMLElement::IsHTMLFocusable(bool aWithMouse,
|
|
bool *aIsFocusable,
|
|
int32_t *aTabIndex)
|
|
{
|
|
nsIDocument* doc = GetComposedDoc();
|
|
if (!doc || doc->HasFlag(NODE_IS_EDITABLE)) {
|
|
// In designMode documents we only allow focusing the document.
|
|
if (aTabIndex) {
|
|
*aTabIndex = -1;
|
|
}
|
|
|
|
*aIsFocusable = false;
|
|
|
|
return true;
|
|
}
|
|
|
|
int32_t tabIndex = TabIndex();
|
|
|
|
bool disabled = false;
|
|
bool disallowOverridingFocusability = true;
|
|
|
|
if (IsEditableRoot()) {
|
|
// Editable roots should always be focusable.
|
|
disallowOverridingFocusability = true;
|
|
|
|
// Ignore the disabled attribute in editable contentEditable/designMode
|
|
// roots.
|
|
if (!HasAttr(kNameSpaceID_None, nsGkAtoms::tabindex)) {
|
|
// The default value for tabindex should be 0 for editable
|
|
// contentEditable roots.
|
|
tabIndex = 0;
|
|
}
|
|
}
|
|
else {
|
|
disallowOverridingFocusability = false;
|
|
|
|
// Just check for disabled attribute on form controls
|
|
disabled = IsDisabled();
|
|
if (disabled) {
|
|
tabIndex = -1;
|
|
}
|
|
}
|
|
|
|
if (aTabIndex) {
|
|
*aTabIndex = tabIndex;
|
|
}
|
|
|
|
// If a tabindex is specified at all, or the default tabindex is 0, we're focusable
|
|
*aIsFocusable =
|
|
(tabIndex >= 0 || (!disabled && HasAttr(kNameSpaceID_None, nsGkAtoms::tabindex)));
|
|
|
|
return disallowOverridingFocusability;
|
|
}
|
|
|
|
void
|
|
nsGenericHTMLElement::RegUnRegAccessKey(bool aDoReg)
|
|
{
|
|
// first check to see if we have an access key
|
|
nsAutoString accessKey;
|
|
GetAttr(kNameSpaceID_None, nsGkAtoms::accesskey, accessKey);
|
|
if (accessKey.IsEmpty()) {
|
|
return;
|
|
}
|
|
|
|
// We have an access key, so get the ESM from the pres context.
|
|
nsPresContext* presContext = GetPresContext(eForUncomposedDoc);
|
|
|
|
if (presContext) {
|
|
EventStateManager* esm = presContext->EventStateManager();
|
|
|
|
// Register or unregister as appropriate.
|
|
if (aDoReg) {
|
|
esm->RegisterAccessKey(this, (uint32_t)accessKey.First());
|
|
} else {
|
|
esm->UnregisterAccessKey(this, (uint32_t)accessKey.First());
|
|
}
|
|
}
|
|
}
|
|
|
|
bool
|
|
nsGenericHTMLElement::PerformAccesskey(bool aKeyCausesActivation,
|
|
bool aIsTrustedEvent)
|
|
{
|
|
nsPresContext* presContext = GetPresContext(eForUncomposedDoc);
|
|
if (!presContext) {
|
|
return false;
|
|
}
|
|
|
|
// It's hard to say what HTML4 wants us to do in all cases.
|
|
bool focused = true;
|
|
nsFocusManager* fm = nsFocusManager::GetFocusManager();
|
|
if (fm) {
|
|
fm->SetFocus(this, nsIFocusManager::FLAG_BYKEY);
|
|
|
|
// Return true if the element became the current focus within its window.
|
|
nsPIDOMWindow* window = OwnerDoc()->GetWindow();
|
|
focused = (window && window->GetFocusedNode());
|
|
}
|
|
|
|
if (aKeyCausesActivation) {
|
|
// Click on it if the users prefs indicate to do so.
|
|
nsAutoPopupStatePusher popupStatePusher(aIsTrustedEvent ?
|
|
openAllowed : openAbused);
|
|
DispatchSimulatedClick(this, aIsTrustedEvent, presContext);
|
|
}
|
|
|
|
return focused;
|
|
}
|
|
|
|
nsresult
|
|
nsGenericHTMLElement::DispatchSimulatedClick(nsGenericHTMLElement* aElement,
|
|
bool aIsTrusted,
|
|
nsPresContext* aPresContext)
|
|
{
|
|
WidgetMouseEvent event(aIsTrusted, eMouseClick, nullptr,
|
|
WidgetMouseEvent::eReal);
|
|
event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_KEYBOARD;
|
|
return EventDispatcher::Dispatch(ToSupports(aElement), aPresContext, &event);
|
|
}
|
|
|
|
nsresult
|
|
nsGenericHTMLElement::GetEditor(nsIEditor** aEditor)
|
|
{
|
|
*aEditor = nullptr;
|
|
|
|
// See also HTMLTextFieldAccessible::GetEditor.
|
|
if (!nsContentUtils::LegacyIsCallerChromeOrNativeCode()) {
|
|
return NS_ERROR_DOM_SECURITY_ERR;
|
|
}
|
|
|
|
NS_IF_ADDREF(*aEditor = GetEditorInternal());
|
|
return NS_OK;
|
|
}
|
|
|
|
already_AddRefed<nsIEditor>
|
|
nsGenericHTMLElement::GetAssociatedEditor()
|
|
{
|
|
// If contenteditable is ever implemented, it might need to do something different here?
|
|
|
|
nsCOMPtr<nsIEditor> editor = GetEditorInternal();
|
|
return editor.forget();
|
|
}
|
|
|
|
bool
|
|
nsGenericHTMLElement::IsCurrentBodyElement()
|
|
{
|
|
// TODO Bug 698498: Should this handle the case where GetBody returns a
|
|
// frameset?
|
|
if (!IsHTMLElement(nsGkAtoms::body)) {
|
|
return false;
|
|
}
|
|
|
|
nsCOMPtr<nsIDOMHTMLDocument> htmlDocument =
|
|
do_QueryInterface(GetUncomposedDoc());
|
|
if (!htmlDocument) {
|
|
return false;
|
|
}
|
|
|
|
nsCOMPtr<nsIDOMHTMLElement> htmlElement;
|
|
htmlDocument->GetBody(getter_AddRefs(htmlElement));
|
|
return htmlElement == static_cast<HTMLBodyElement*>(this);
|
|
}
|
|
|
|
// static
|
|
void
|
|
nsGenericHTMLElement::SyncEditorsOnSubtree(nsIContent* content)
|
|
{
|
|
/* Sync this node */
|
|
nsGenericHTMLElement* element = FromContent(content);
|
|
if (element) {
|
|
nsCOMPtr<nsIEditor> editor = element->GetAssociatedEditor();
|
|
if (editor) {
|
|
editor->SyncRealTimeSpell();
|
|
}
|
|
}
|
|
|
|
/* Sync all children */
|
|
for (nsIContent* child = content->GetFirstChild();
|
|
child;
|
|
child = child->GetNextSibling()) {
|
|
SyncEditorsOnSubtree(child);
|
|
}
|
|
}
|
|
|
|
void
|
|
nsGenericHTMLElement::RecompileScriptEventListeners()
|
|
{
|
|
int32_t i, count = mAttrsAndChildren.AttrCount();
|
|
for (i = 0; i < count; ++i) {
|
|
const nsAttrName *name = mAttrsAndChildren.AttrNameAt(i);
|
|
|
|
// Eventlistenener-attributes are always in the null namespace
|
|
if (!name->IsAtom()) {
|
|
continue;
|
|
}
|
|
|
|
nsIAtom *attr = name->Atom();
|
|
if (!IsEventAttributeName(attr)) {
|
|
continue;
|
|
}
|
|
|
|
nsAutoString value;
|
|
GetAttr(kNameSpaceID_None, attr, value);
|
|
SetEventHandler(attr, value, true);
|
|
}
|
|
}
|
|
|
|
bool
|
|
nsGenericHTMLElement::IsEditableRoot() const
|
|
{
|
|
nsIDocument *document = GetComposedDoc();
|
|
if (!document) {
|
|
return false;
|
|
}
|
|
|
|
if (document->HasFlag(NODE_IS_EDITABLE)) {
|
|
return false;
|
|
}
|
|
|
|
if (GetContentEditableValue() != eTrue) {
|
|
return false;
|
|
}
|
|
|
|
nsIContent *parent = GetParent();
|
|
|
|
return !parent || !parent->HasFlag(NODE_IS_EDITABLE);
|
|
}
|
|
|
|
static void
|
|
MakeContentDescendantsEditable(nsIContent *aContent, nsIDocument *aDocument)
|
|
{
|
|
// If aContent is not an element, we just need to update its
|
|
// internal editable state and don't need to notify anyone about
|
|
// that. For elements, we need to send a ContentStateChanged
|
|
// notification.
|
|
if (!aContent->IsElement()) {
|
|
aContent->UpdateEditableState(false);
|
|
return;
|
|
}
|
|
|
|
Element *element = aContent->AsElement();
|
|
|
|
element->UpdateEditableState(true);
|
|
|
|
for (nsIContent *child = aContent->GetFirstChild();
|
|
child;
|
|
child = child->GetNextSibling()) {
|
|
if (!child->HasAttr(kNameSpaceID_None, nsGkAtoms::contenteditable)) {
|
|
MakeContentDescendantsEditable(child, aDocument);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
nsGenericHTMLElement::ChangeEditableState(int32_t aChange)
|
|
{
|
|
//XXXsmaug Fix this for Shadow DOM, bug 1066965.
|
|
nsIDocument* document = GetUncomposedDoc();
|
|
if (!document) {
|
|
return;
|
|
}
|
|
|
|
if (aChange != 0) {
|
|
nsCOMPtr<nsIHTMLDocument> htmlDocument =
|
|
do_QueryInterface(document);
|
|
if (htmlDocument) {
|
|
htmlDocument->ChangeContentEditableCount(this, aChange);
|
|
}
|
|
|
|
nsIContent* parent = GetParent();
|
|
while (parent) {
|
|
parent->ChangeEditableDescendantCount(aChange);
|
|
parent = parent->GetParent();
|
|
}
|
|
}
|
|
|
|
if (document->HasFlag(NODE_IS_EDITABLE)) {
|
|
document = nullptr;
|
|
}
|
|
|
|
// MakeContentDescendantsEditable is going to call ContentStateChanged for
|
|
// this element and all descendants if editable state has changed.
|
|
// We might as well wrap it all in one script blocker.
|
|
nsAutoScriptBlocker scriptBlocker;
|
|
MakeContentDescendantsEditable(this, document);
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
nsGenericHTMLFormElementWithState::nsGenericHTMLFormElementWithState(
|
|
already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo
|
|
)
|
|
: nsGenericHTMLFormElement(aNodeInfo)
|
|
{
|
|
mStateKey.SetIsVoid(true);
|
|
}
|
|
|
|
nsresult
|
|
nsGenericHTMLFormElementWithState::GenerateStateKey()
|
|
{
|
|
// Keep the key if already computed
|
|
if (!mStateKey.IsVoid()) {
|
|
return NS_OK;
|
|
}
|
|
|
|
nsIDocument* doc = GetUncomposedDoc();
|
|
if (!doc) {
|
|
return NS_OK;
|
|
}
|
|
|
|
// Generate the state key
|
|
nsresult rv = nsContentUtils::GenerateStateKey(this, doc, mStateKey);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
mStateKey.SetIsVoid(true);
|
|
return rv;
|
|
}
|
|
|
|
// If the state key is blank, this is anonymous content or for whatever
|
|
// reason we are not supposed to save/restore state: keep it as such.
|
|
if (!mStateKey.IsEmpty()) {
|
|
// Add something unique to content so layout doesn't muck us up.
|
|
mStateKey += "-C";
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
nsPresState*
|
|
nsGenericHTMLFormElementWithState::GetPrimaryPresState()
|
|
{
|
|
if (mStateKey.IsEmpty()) {
|
|
return nullptr;
|
|
}
|
|
|
|
nsCOMPtr<nsILayoutHistoryState> history = GetLayoutHistory(false);
|
|
|
|
if (!history) {
|
|
return nullptr;
|
|
}
|
|
|
|
// Get the pres state for this key, if it doesn't exist, create one.
|
|
nsPresState* result = history->GetState(mStateKey);
|
|
if (!result) {
|
|
result = new nsPresState();
|
|
history->AddState(mStateKey, result);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
already_AddRefed<nsILayoutHistoryState>
|
|
nsGenericHTMLFormElementWithState::GetLayoutHistory(bool aRead)
|
|
{
|
|
nsCOMPtr<nsIDocument> doc = GetUncomposedDoc();
|
|
if (!doc) {
|
|
return nullptr;
|
|
}
|
|
|
|
//
|
|
// Get the history
|
|
//
|
|
nsCOMPtr<nsILayoutHistoryState> history = doc->GetLayoutHistoryState();
|
|
if (!history) {
|
|
return nullptr;
|
|
}
|
|
|
|
if (aRead && !history->HasStates()) {
|
|
return nullptr;
|
|
}
|
|
|
|
return history.forget();
|
|
}
|
|
|
|
bool
|
|
nsGenericHTMLFormElementWithState::RestoreFormControlState()
|
|
{
|
|
if (mStateKey.IsEmpty()) {
|
|
return false;
|
|
}
|
|
|
|
nsCOMPtr<nsILayoutHistoryState> history =
|
|
GetLayoutHistory(true);
|
|
if (!history) {
|
|
return false;
|
|
}
|
|
|
|
nsPresState *state;
|
|
// Get the pres state for this key
|
|
state = history->GetState(mStateKey);
|
|
if (state) {
|
|
bool result = RestoreState(state);
|
|
history->RemoveState(mStateKey);
|
|
return result;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void
|
|
nsGenericHTMLFormElementWithState::NodeInfoChanged(mozilla::dom::NodeInfo* aOldNodeInfo)
|
|
{
|
|
mStateKey.SetIsVoid(true);
|
|
}
|
|
|
|
void
|
|
nsGenericHTMLElement::GetItemValue(JSContext* aCx, JSObject* aScope,
|
|
JS::MutableHandle<JS::Value> aRetval,
|
|
ErrorResult& aError)
|
|
{
|
|
JS::Rooted<JSObject*> scope(aCx, aScope);
|
|
if (!HasAttr(kNameSpaceID_None, nsGkAtoms::itemprop)) {
|
|
aRetval.setNull();
|
|
return;
|
|
}
|
|
|
|
if (ItemScope()) {
|
|
JS::Rooted<JS::Value> v(aCx);
|
|
JSAutoCompartment ac(aCx, scope);
|
|
if (!mozilla::dom::WrapObject(aCx, this, aRetval)) {
|
|
aError.Throw(NS_ERROR_FAILURE);
|
|
}
|
|
return;
|
|
}
|
|
|
|
DOMString string;
|
|
GetItemValueText(string);
|
|
if (!xpc::NonVoidStringToJsval(aCx, string, aRetval)) {
|
|
aError.Throw(NS_ERROR_FAILURE);
|
|
}
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsGenericHTMLElement::GetItemValue(nsIVariant** aValue)
|
|
{
|
|
nsCOMPtr<nsIWritableVariant> out = new nsVariant();
|
|
|
|
if (!HasAttr(kNameSpaceID_None, nsGkAtoms::itemprop)) {
|
|
out->SetAsEmpty();
|
|
out.forget(aValue);
|
|
return NS_OK;
|
|
}
|
|
|
|
if (ItemScope()) {
|
|
out->SetAsISupports(static_cast<nsIContent*>(this));
|
|
} else {
|
|
DOMString string;
|
|
GetItemValueText(string);
|
|
nsString xpcomString;
|
|
string.ToString(xpcomString);
|
|
out->SetAsAString(xpcomString);
|
|
}
|
|
|
|
out.forget(aValue);
|
|
return NS_OK;
|
|
}
|
|
|
|
void
|
|
nsGenericHTMLElement::SetItemValue(JSContext* aCx, JS::Value aValue,
|
|
ErrorResult& aError)
|
|
{
|
|
if (!HasAttr(kNameSpaceID_None, nsGkAtoms::itemprop) ||
|
|
HasAttr(kNameSpaceID_None, nsGkAtoms::itemscope)) {
|
|
aError.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
|
|
return;
|
|
}
|
|
|
|
nsAutoString string;
|
|
JS::Rooted<JS::Value> value(aCx, aValue);
|
|
if (!ConvertJSValueToString(aCx, value, eStringify, eStringify, string)) {
|
|
aError.Throw(NS_ERROR_UNEXPECTED);
|
|
return;
|
|
}
|
|
SetItemValueText(string);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsGenericHTMLElement::SetItemValue(nsIVariant* aValue)
|
|
{
|
|
if (!HasAttr(kNameSpaceID_None, nsGkAtoms::itemprop) ||
|
|
HasAttr(kNameSpaceID_None, nsGkAtoms::itemscope)) {
|
|
return NS_ERROR_DOM_INVALID_ACCESS_ERR;
|
|
}
|
|
|
|
nsAutoString string;
|
|
aValue->GetAsAString(string);
|
|
SetItemValueText(string);
|
|
return NS_OK;
|
|
}
|
|
|
|
void
|
|
nsGenericHTMLElement::GetItemValueText(DOMString& text)
|
|
{
|
|
ErrorResult rv;
|
|
GetTextContentInternal(text, rv);
|
|
}
|
|
|
|
void
|
|
nsGenericHTMLElement::SetItemValueText(const nsAString& text)
|
|
{
|
|
mozilla::ErrorResult rv;
|
|
SetTextContentInternal(text, rv);
|
|
}
|
|
|
|
static void
|
|
HTMLPropertiesCollectionDestructor(void *aObject, nsIAtom *aProperty,
|
|
void *aPropertyValue, void *aData)
|
|
{
|
|
HTMLPropertiesCollection* properties =
|
|
static_cast<HTMLPropertiesCollection*>(aPropertyValue);
|
|
NS_IF_RELEASE(properties);
|
|
}
|
|
|
|
HTMLPropertiesCollection*
|
|
nsGenericHTMLElement::Properties()
|
|
{
|
|
HTMLPropertiesCollection* properties =
|
|
static_cast<HTMLPropertiesCollection*>(GetProperty(nsGkAtoms::microdataProperties));
|
|
if (!properties) {
|
|
properties = new HTMLPropertiesCollection(this);
|
|
NS_ADDREF(properties);
|
|
SetProperty(nsGkAtoms::microdataProperties, properties, HTMLPropertiesCollectionDestructor);
|
|
}
|
|
return properties;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsGenericHTMLElement::GetProperties(nsISupports** aProperties)
|
|
{
|
|
NS_ADDREF(*aProperties = static_cast<nsIHTMLCollection*>(Properties()));
|
|
return NS_OK;
|
|
}
|
|
|
|
nsSize
|
|
nsGenericHTMLElement::GetWidthHeightForImage(RefPtr<imgRequestProxy>& aImageRequest)
|
|
{
|
|
nsSize size(0,0);
|
|
|
|
nsIFrame* frame = GetPrimaryFrame(Flush_Layout);
|
|
|
|
if (frame) {
|
|
size = frame->GetContentRect().Size();
|
|
|
|
size.width = nsPresContext::AppUnitsToIntCSSPixels(size.width);
|
|
size.height = nsPresContext::AppUnitsToIntCSSPixels(size.height);
|
|
} else {
|
|
const nsAttrValue* value;
|
|
nsCOMPtr<imgIContainer> image;
|
|
if (aImageRequest) {
|
|
aImageRequest->GetImage(getter_AddRefs(image));
|
|
}
|
|
|
|
if ((value = GetParsedAttr(nsGkAtoms::width)) &&
|
|
value->Type() == nsAttrValue::eInteger) {
|
|
size.width = value->GetIntegerValue();
|
|
} else if (image) {
|
|
image->GetWidth(&size.width);
|
|
}
|
|
|
|
if ((value = GetParsedAttr(nsGkAtoms::height)) &&
|
|
value->Type() == nsAttrValue::eInteger) {
|
|
size.height = value->GetIntegerValue();
|
|
} else if (image) {
|
|
image->GetHeight(&size.height);
|
|
}
|
|
}
|
|
|
|
NS_ASSERTION(size.width >= 0, "negative width");
|
|
NS_ASSERTION(size.height >= 0, "negative height");
|
|
return size;
|
|
}
|
|
|
|
bool
|
|
nsGenericHTMLElement::IsEventAttributeName(nsIAtom *aName)
|
|
{
|
|
return nsContentUtils::IsEventAttributeName(aName, EventNameType_HTML);
|
|
}
|
|
|
|
/**
|
|
* Construct a URI from a string, as an element.src attribute
|
|
* would be set to. Helper for the media elements.
|
|
*/
|
|
nsresult
|
|
nsGenericHTMLElement::NewURIFromString(const nsAString& aURISpec,
|
|
nsIURI** aURI)
|
|
{
|
|
NS_ENSURE_ARG_POINTER(aURI);
|
|
|
|
*aURI = nullptr;
|
|
|
|
nsCOMPtr<nsIDocument> doc = OwnerDoc();
|
|
|
|
nsCOMPtr<nsIURI> baseURI = GetBaseURI();
|
|
nsresult rv = nsContentUtils::NewURIWithDocumentCharset(aURI, aURISpec,
|
|
doc, baseURI);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
bool equal;
|
|
if (aURISpec.IsEmpty() &&
|
|
doc->GetDocumentURI() &&
|
|
NS_SUCCEEDED(doc->GetDocumentURI()->Equals(*aURI, &equal)) &&
|
|
equal) {
|
|
// Assume an element can't point to a fragment of its embedding
|
|
// document. Fail here instead of returning the recursive URI
|
|
// and waiting for the subsequent load to fail.
|
|
NS_RELEASE(*aURI);
|
|
return NS_ERROR_DOM_INVALID_STATE_ERR;
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
static bool
|
|
IsOrHasAncestorWithDisplayNone(Element* aElement, nsIPresShell* aPresShell)
|
|
{
|
|
nsTArray<Element*> elementsToCheck;
|
|
for (Element* e = aElement; e; e = e->GetParentElement()) {
|
|
if (e->GetPrimaryFrame()) {
|
|
// e definitely isn't display:none and doesn't have a display:none
|
|
// ancestor.
|
|
break;
|
|
}
|
|
elementsToCheck.AppendElement(e);
|
|
}
|
|
|
|
if (elementsToCheck.IsEmpty()) {
|
|
return false;
|
|
}
|
|
|
|
StyleSetHandle styleSet = aPresShell->StyleSet();
|
|
RefPtr<nsStyleContext> sc;
|
|
for (int32_t i = elementsToCheck.Length() - 1; i >= 0; --i) {
|
|
if (sc) {
|
|
sc = styleSet->ResolveStyleFor(elementsToCheck[i], sc);
|
|
} else {
|
|
sc = nsComputedDOMStyle::GetStyleContextForElementNoFlush(elementsToCheck[i],
|
|
nullptr, aPresShell);
|
|
}
|
|
if (sc->StyleDisplay()->mDisplay == NS_STYLE_DISPLAY_NONE) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void
|
|
nsGenericHTMLElement::GetInnerText(mozilla::dom::DOMString& aValue,
|
|
mozilla::ErrorResult& aError)
|
|
{
|
|
if (!GetPrimaryFrame(Flush_Layout)) {
|
|
nsIPresShell* presShell = nsComputedDOMStyle::GetPresShellForContent(this);
|
|
if (!presShell || IsOrHasAncestorWithDisplayNone(this, presShell)) {
|
|
GetTextContentInternal(aValue, aError);
|
|
return;
|
|
}
|
|
}
|
|
|
|
nsRange::GetInnerTextNoFlush(aValue, aError, this, 0, this, GetChildCount());
|
|
}
|
|
|
|
void
|
|
nsGenericHTMLElement::SetInnerText(const nsAString& aValue)
|
|
{
|
|
// Fire DOMNodeRemoved mutation events before we do anything else.
|
|
nsCOMPtr<nsIContent> kungFuDeathGrip;
|
|
|
|
// Batch possible DOMSubtreeModified events.
|
|
mozAutoSubtreeModified subtree(OwnerDoc(), nullptr);
|
|
FireNodeRemovedForChildren();
|
|
|
|
// Might as well stick a batch around this since we're performing several
|
|
// mutations.
|
|
mozAutoDocUpdate updateBatch(GetComposedDoc(),
|
|
UPDATE_CONTENT_MODEL, true);
|
|
nsAutoMutationBatch mb;
|
|
|
|
uint32_t childCount = GetChildCount();
|
|
|
|
mb.Init(this, true, false);
|
|
for (uint32_t i = 0; i < childCount; ++i) {
|
|
RemoveChildAt(0, true);
|
|
}
|
|
mb.RemovalDone();
|
|
|
|
nsString str;
|
|
const char16_t* s = aValue.BeginReading();
|
|
const char16_t* end = aValue.EndReading();
|
|
while (true) {
|
|
if (s != end && *s == '\r' && s + 1 != end && s[1] == '\n') {
|
|
// a \r\n pair should only generate one <br>, so just skip the \r
|
|
++s;
|
|
}
|
|
if (s == end || *s == '\r' || *s == '\n') {
|
|
if (!str.IsEmpty()) {
|
|
RefPtr<nsTextNode> textContent =
|
|
new nsTextNode(NodeInfo()->NodeInfoManager());
|
|
textContent->SetText(str, true);
|
|
AppendChildTo(textContent, true);
|
|
}
|
|
if (s == end) {
|
|
break;
|
|
}
|
|
str.Truncate();
|
|
already_AddRefed<mozilla::dom::NodeInfo> ni =
|
|
NodeInfo()->NodeInfoManager()->GetNodeInfo(nsGkAtoms::br,
|
|
nullptr, kNameSpaceID_XHTML, nsIDOMNode::ELEMENT_NODE);
|
|
RefPtr<HTMLBRElement> br = new HTMLBRElement(ni);
|
|
AppendChildTo(br, true);
|
|
} else {
|
|
str.Append(*s);
|
|
}
|
|
++s;
|
|
}
|
|
|
|
mb.NodesAdded();
|
|
}
|