Merge remote-tracking branch 'origin/master' into custom

This commit is contained in:
Roy Tam 2019-09-06 23:57:22 +08:00
commit 6d191b58d4
64 changed files with 532 additions and 20498 deletions

View file

@ -682,6 +682,15 @@ pref("plugins.update.notifyUser", false);
//Enable tri-state option (Always/Never/Ask)
pref("plugins.click_to_play", true);
// Platform pref is to enable all plugins by default.
// Uncomment this pref to default to click-to-play
// pref("plugin.default.state", 1);
// Don't load plugin instances with no src declared.
// These prefs are documented in detail in all.js.
pref("plugins.favorfallback.mode", "follow-ctp");
pref("plugins.favorfallback.rules", "nosrc");
#ifdef XP_WIN
pref("browser.preferences.instantApply", false);
#else

View file

@ -361,10 +361,10 @@ set_config('LIB', lib_path)
option(env='MT', nargs=1, help='Path to the Microsoft Manifest Tool')
@depends_win(valid_windows_sdk_dir)
@depends_win(valid_windows_sdk_dir, valid_ucrt_sdk_dir)
@imports(_from='os', _import='environ')
@imports('platform')
def sdk_bin_path(valid_windows_sdk_dir):
def sdk_bin_path(valid_windows_sdk_dir, valid_ucrt_sdk_dir):
if not valid_windows_sdk_dir:
return
@ -373,13 +373,17 @@ def sdk_bin_path(valid_windows_sdk_dir):
'AMD64': 'x64',
}.get(platform.machine())
# From version 10.0.15063.0 onwards the bin path contains the version number.
versioned_bin = ('bin' if valid_ucrt_sdk_dir.version < '10.0.15063.0'
else os.path.join('bin', str(valid_ucrt_sdk_dir.version)))
result = [
environ['PATH'],
os.path.join(valid_windows_sdk_dir.path, 'bin', vc_host)
os.path.join(valid_windows_sdk_dir.path, versioned_bin, vc_host)
]
if vc_host == 'x64':
result.append(
os.path.join(valid_windows_sdk_dir.path, 'bin', 'x86'))
os.path.join(valid_windows_sdk_dir.path, versioned_bin, 'x86'))
return result

View file

@ -718,9 +718,9 @@ nsObjectLoadingContent::UnbindFromTree(bool aDeep, bool aNullParent)
if (mType == eType_Plugin) {
nsIDocument* doc = thisContent->GetComposedDoc();
if (doc && doc->IsActive()) {
nsCOMPtr<nsIRunnable> ev = new nsSimplePluginEvent(doc,
NS_LITERAL_STRING("PluginRemoved"));
NS_DispatchToCurrentThread(ev);
nsCOMPtr<nsIRunnable> ev = new nsSimplePluginEvent(doc,
NS_LITERAL_STRING("PluginRemoved"));
NS_DispatchToCurrentThread(ev);
}
}
}
@ -3628,6 +3628,14 @@ nsObjectLoadingContent::HasGoodFallback() {
}
}
// RULE "nosrc":
// Use fallback content if the object has not specified a src URI.
if (rulesList[i].EqualsLiteral("nosrc")) {
if (!mOriginalURI) {
return true;
}
}
// RULE "adobelink":
// Don't use fallback content when it has a link to adobe's website.
if (rulesList[i].EqualsLiteral("adobelink")) {

View file

@ -659,7 +659,7 @@ ImageDocument::CreateSyntheticDocument()
NS_ENSURE_SUCCESS(rv, rv);
// Add the image element
Element* body = GetBodyElement();
RefPtr<Element> body = GetBodyElement();
if (!body) {
NS_WARNING("no body on image document!");
return NS_ERROR_FAILURE;

View file

@ -206,7 +206,7 @@ PluginDocument::CreateSyntheticPluginDocument()
NS_ENSURE_SUCCESS(rv, rv);
// then attach our plugin
Element* body = GetBodyElement();
RefPtr<Element> body = GetBodyElement();
if (!body) {
NS_WARNING("no body on plugin document!");
return NS_ERROR_FAILURE;

View file

@ -90,7 +90,7 @@ VideoDocument::CreateSyntheticVideoDocument(nsIChannel* aChannel,
nsresult rv = MediaDocument::CreateSyntheticDocument();
NS_ENSURE_SUCCESS(rv, rv);
Element* body = GetBodyElement();
RefPtr<Element> body = GetBodyElement();
if (!body) {
NS_WARNING("no body on video document!");
return NS_ERROR_FAILURE;

View file

@ -430,7 +430,7 @@ IDBCursor::Continue(JSContext* aCx,
}
Key key;
aRv = key.SetFromJSVal(aCx, aKey);
aRv = key.SetFromJSVal(aCx, aKey, /* aCallGetters */ true);
if (aRv.Failed()) {
return;
}
@ -536,7 +536,7 @@ IDBCursor::ContinuePrimaryKey(JSContext* aCx,
}
Key key;
aRv = key.SetFromJSVal(aCx, aKey);
aRv = key.SetFromJSVal(aCx, aKey, /* aCallGetters */ true);
if (aRv.Failed()) {
return;
}
@ -558,7 +558,7 @@ IDBCursor::ContinuePrimaryKey(JSContext* aCx,
}
Key primaryKey;
aRv = primaryKey.SetFromJSVal(aCx, aPrimaryKey);
aRv = primaryKey.SetFromJSVal(aCx, aPrimaryKey, /* aCallGetters */ true);
if (aRv.Failed()) {
return;
}
@ -718,7 +718,7 @@ IDBCursor::Update(JSContext* aCx, JS::Handle<JS::Value> aValue,
const KeyPath& keyPath = objectStore->GetKeyPath();
Key key;
aRv = keyPath.ExtractKey(aCx, aValue, key);
aRv = keyPath.ExtractKey(aCx, aValue, key, /* aCallGetters */ false);
if (aRv.Failed()) {
return nullptr;
}

View file

@ -482,13 +482,13 @@ IDBFactory::Cmp(JSContext* aCx, JS::Handle<JS::Value> aFirst,
JS::Handle<JS::Value> aSecond, ErrorResult& aRv)
{
Key first, second;
nsresult rv = first.SetFromJSVal(aCx, aFirst);
nsresult rv = first.SetFromJSVal(aCx, aFirst, /* aCallGetters */ true);
if (NS_FAILED(rv)) {
aRv.Throw(rv);
return 0;
}
rv = second.SetFromJSVal(aCx, aSecond);
rv = second.SetFromJSVal(aCx, aSecond, /* aCallGetters */ true);
if (NS_FAILED(rv)) {
aRv.Throw(rv);
return 0;

View file

@ -24,7 +24,7 @@ GetKeyFromJSVal(JSContext* aCx,
JS::Handle<JS::Value> aVal,
Key& aKey)
{
nsresult rv = aKey.SetFromJSVal(aCx, aVal);
nsresult rv = aKey.SetFromJSVal(aCx, aVal, /* aCallGetters */ true);
if (NS_FAILED(rv)) {
MOZ_ASSERT(NS_ERROR_GET_MODULE(rv) == NS_ERROR_MODULE_DOM_INDEXEDDB);
return rv;

View file

@ -1084,7 +1084,7 @@ IDBObjectStore::AppendIndexUpdateInfo(
if (!aMultiEntry) {
Key key;
rv = aKeyPath.ExtractKey(aCx, aVal, key);
rv = aKeyPath.ExtractKey(aCx, aVal, key, /* aCallGetters */ false);
// If an index's keyPath doesn't match an object, we ignore that object.
if (rv == NS_ERROR_DOM_INDEXEDDB_DATA_ERR || key.IsUnset()) {
@ -1128,13 +1128,13 @@ IDBObjectStore::AppendIndexUpdateInfo(
for (uint32_t arrayIndex = 0; arrayIndex < arrayLength; arrayIndex++) {
JS::Rooted<JS::Value> arrayItem(aCx);
if (NS_WARN_IF(!JS_GetElement(aCx, array, arrayIndex, &arrayItem))) {
if (NS_WARN_IF(!JS_GetOwnElement(aCx, array, arrayIndex, &arrayItem))) {
IDB_REPORT_INTERNAL_ERR();
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
Key value;
if (NS_FAILED(value.SetFromJSVal(aCx, arrayItem)) ||
if (NS_FAILED(value.SetFromJSVal(aCx, arrayItem, /* aCallGetters */ false)) ||
value.IsUnset()) {
// Not a value we can do anything with, ignore it.
continue;
@ -1153,7 +1153,7 @@ IDBObjectStore::AppendIndexUpdateInfo(
}
else {
Key value;
if (NS_FAILED(value.SetFromJSVal(aCx, val)) ||
if (NS_FAILED(value.SetFromJSVal(aCx, val, /* aCallGetters */ false)) ||
value.IsUnset()) {
// Not a value we can do anything with, ignore it.
return NS_OK;
@ -1324,12 +1324,12 @@ IDBObjectStore::GetAddInfo(JSContext* aCx,
if (!HasValidKeyPath()) {
// Out-of-line keys must be passed in.
rv = aKey.SetFromJSVal(aCx, aKeyVal);
rv = aKey.SetFromJSVal(aCx, aKeyVal, /* aCallGetters */ true);
if (NS_FAILED(rv)) {
return rv;
}
} else if (!isAutoIncrement) {
rv = GetKeyPath().ExtractKey(aCx, aValue, aKey);
rv = GetKeyPath().ExtractKey(aCx, aValue, aKey, /* aCallGetters */ false);
if (NS_FAILED(rv)) {
return rv;
}
@ -1368,7 +1368,8 @@ IDBObjectStore::GetAddInfo(JSContext* aCx,
aValue,
aKey,
&GetAddInfoCallback,
&data);
&data,
/* aCallGetters */ false);
} else {
rv = GetAddInfoCallback(aCx, &data);
}

View file

@ -201,8 +201,11 @@ Key::ToLocaleBasedKey(Key& aTarget, const nsCString& aLocale) const
}
nsresult
Key::EncodeJSValInternal(JSContext* aCx, JS::Handle<JS::Value> aVal,
uint8_t aTypeOffset, uint16_t aRecursionDepth)
Key::EncodeJSValInternal(JSContext* aCx,
JS::Handle<JS::Value> aVal,
uint8_t aTypeOffset,
uint16_t aRecursionDepth,
bool aCallGetters)
{
static_assert(eMaxType * kMaxArrayCollapse < 256,
"Unable to encode jsvals.");
@ -257,13 +260,18 @@ Key::EncodeJSValInternal(JSContext* aCx, JS::Handle<JS::Value> aVal,
for (uint32_t index = 0; index < length; index++) {
JS::Rooted<JS::Value> val(aCx);
if (!JS_GetElement(aCx, obj, index, &val)) {
bool ok = aCallGetters ? JS_GetElement(aCx, obj, index, &val)
: JS_GetOwnElement(aCx, obj, index, &val);
if (!ok) {
IDB_REPORT_INTERNAL_ERR();
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
nsresult rv = EncodeJSValInternal(aCx, val, aTypeOffset,
aRecursionDepth + 1);
nsresult rv = EncodeJSValInternal(aCx,
val,
aTypeOffset,
aRecursionDepth + 1,
aCallGetters);
if (NS_FAILED(rv)) {
return rv;
}
@ -406,9 +414,10 @@ Key::DecodeJSValInternal(const unsigned char*& aPos, const unsigned char* aEnd,
nsresult
Key::EncodeJSVal(JSContext* aCx,
JS::Handle<JS::Value> aVal,
uint8_t aTypeOffset)
uint8_t aTypeOffset,
bool aCallGetters)
{
return EncodeJSValInternal(aCx, aVal, aTypeOffset, 0);
return EncodeJSValInternal(aCx, aVal, aTypeOffset, 0, aCallGetters);
}
void
@ -741,7 +750,8 @@ Key::SetFromValueArray(mozIStorageValueArray* aValues,
nsresult
Key::SetFromJSVal(JSContext* aCx,
JS::Handle<JS::Value> aVal)
JS::Handle<JS::Value> aVal,
bool aCallGetters)
{
mBuffer.Truncate();
@ -750,7 +760,7 @@ Key::SetFromJSVal(JSContext* aCx,
return NS_OK;
}
nsresult rv = EncodeJSVal(aCx, aVal, 0);
nsresult rv = EncodeJSVal(aCx, aVal, 0, aCallGetters);
if (NS_FAILED(rv)) {
Unset();
return rv;
@ -793,9 +803,15 @@ Key::ToJSVal(JSContext* aCx,
}
nsresult
Key::AppendItem(JSContext* aCx, bool aFirstOfArray, JS::Handle<JS::Value> aVal)
Key::AppendItem(JSContext* aCx,
bool aFirstOfArray,
JS::Handle<JS::Value> aVal,
bool aCallGetters)
{
nsresult rv = EncodeJSVal(aCx, aVal, aFirstOfArray ? eMaxType : 0);
nsresult rv = EncodeJSVal(aCx,
aVal,
aFirstOfArray ? eMaxType : 0,
aCallGetters);
if (NS_FAILED(rv)) {
Unset();
return rv;

View file

@ -203,7 +203,7 @@ public:
}
nsresult
SetFromJSVal(JSContext* aCx, JS::Handle<JS::Value> aVal);
SetFromJSVal(JSContext* aCx, JS::Handle<JS::Value> aVal, bool aCallGetters);
nsresult
ToJSVal(JSContext* aCx, JS::MutableHandle<JS::Value> aVal) const;
@ -212,7 +212,10 @@ public:
ToJSVal(JSContext* aCx, JS::Heap<JS::Value>& aVal) const;
nsresult
AppendItem(JSContext* aCx, bool aFirstOfArray, JS::Handle<JS::Value> aVal);
AppendItem(JSContext* aCx,
bool aFirstOfArray,
JS::Handle<JS::Value> aVal,
bool aCallGetters);
nsresult
ToLocaleBasedKey(Key& aTarget, const nsCString& aLocale) const;
@ -283,7 +286,10 @@ private:
// Encoding functions. These append the encoded value to the end of mBuffer
nsresult
EncodeJSVal(JSContext* aCx, JS::Handle<JS::Value> aVal, uint8_t aTypeOffset);
EncodeJSVal(JSContext* aCx,
JS::Handle<JS::Value> aVal,
uint8_t aTypeOffset,
bool aCallGetters);
void
EncodeString(const nsAString& aString, uint8_t aTypeOffset);
@ -331,7 +337,8 @@ private:
EncodeJSValInternal(JSContext* aCx,
JS::Handle<JS::Value> aVal,
uint8_t aTypeOffset,
uint16_t aRecursionDepth);
uint16_t aRecursionDepth,
bool aCallGetters);
static nsresult
DecodeJSValInternal(const unsigned char*& aPos,

View file

@ -372,11 +372,13 @@ KeyPath::AppendStringWithValidation(const nsAString& aString)
}
nsresult
KeyPath::ExtractKey(JSContext* aCx, const JS::Value& aValue, Key& aKey) const
KeyPath::ExtractKey(JSContext* aCx,
const JS::Value& aValue,
Key& aKey,
bool aCallGetters) const
{
uint32_t len = mStrings.Length();
JS::Rooted<JS::Value> value(aCx);
aKey.Unset();
for (uint32_t i = 0; i < len; ++i) {
@ -388,7 +390,10 @@ KeyPath::ExtractKey(JSContext* aCx, const JS::Value& aValue, Key& aKey) const
return rv;
}
if (NS_FAILED(aKey.AppendItem(aCx, IsArray() && i == 0, value))) {
if (NS_FAILED(aKey.AppendItem(aCx,
IsArray() && i == 0,
value,
aCallGetters))) {
NS_ASSERTION(aKey.IsUnset(), "Encoding error should unset");
return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
}
@ -437,9 +442,12 @@ KeyPath::ExtractKeyAsJSVal(JSContext* aCx, const JS::Value& aValue,
}
nsresult
KeyPath::ExtractOrCreateKey(JSContext* aCx, const JS::Value& aValue,
Key& aKey, ExtractOrCreateKeyCallback aCallback,
void* aClosure) const
KeyPath::ExtractOrCreateKey(JSContext* aCx,
const JS::Value& aValue,
Key& aKey,
ExtractOrCreateKeyCallback aCallback,
void* aClosure,
bool aCallGetters) const
{
NS_ASSERTION(IsString(), "This doesn't make sense!");
@ -455,7 +463,7 @@ KeyPath::ExtractOrCreateKey(JSContext* aCx, const JS::Value& aValue,
return rv;
}
if (NS_FAILED(aKey.AppendItem(aCx, false, value))) {
if (NS_FAILED(aKey.AppendItem(aCx, false, value, aCallGetters))) {
NS_ASSERTION(aKey.IsUnset(), "Should be unset");
return value.isUndefined() ? NS_OK : NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
}

View file

@ -72,7 +72,10 @@ public:
Parse(const Nullable<OwningStringOrStringSequence>& aValue, KeyPath* aKeyPath);
nsresult
ExtractKey(JSContext* aCx, const JS::Value& aValue, Key& aKey) const;
ExtractKey(JSContext* aCx,
const JS::Value& aValue,
Key& aKey,
bool aCallGetters) const;
nsresult
ExtractKeyAsJSVal(JSContext* aCx, const JS::Value& aValue,
@ -82,9 +85,12 @@ public:
(*ExtractOrCreateKeyCallback)(JSContext* aCx, void* aClosure);
nsresult
ExtractOrCreateKey(JSContext* aCx, const JS::Value& aValue, Key& aKey,
ExtractOrCreateKey(JSContext* aCx,
const JS::Value& aValue,
Key& aKey,
ExtractOrCreateKeyCallback aCallback,
void* aClosure) const;
void* aClosure,
bool aCallGetters) const;
inline bool IsValid() const {
return mType != NONEXISTENT;

View file

@ -513,8 +513,19 @@ nsCSPContext::GetAllowsInline(nsContentPolicyType aContentType,
for (uint32_t i = 0; i < mPolicies.Length(); i++) {
bool allowed =
mPolicies[i]->allows(aContentType, CSP_UNSAFE_INLINE, EmptyString(), aParserCreated) ||
mPolicies[i]->allows(aContentType, CSP_NONCE, aNonce, aParserCreated) ||
mPolicies[i]->allows(aContentType, CSP_HASH, aContent, aParserCreated);
mPolicies[i]->allows(aContentType, CSP_NONCE, aNonce, aParserCreated);
// If the inlined script or style is allowed by either unsafe-inline or the
// nonce, go ahead and shortcut this loop.
if (allowed) {
continue;
}
// Check if the csp-hash matches against the hash of the script.
// If we don't have any content to check, block the script.
if (!aContent.IsEmpty()) {
allowed = mPolicies[i]->allows(aContentType, CSP_HASH, aContent, aParserCreated);
}
if (!allowed) {
// policy is violoated: deny the load unless policy is report only and

View file

@ -641,13 +641,22 @@ nsCSPHostSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected
// just a specific scheme, the parser should generate a nsCSPSchemeSource.
NS_ASSERTION((!mHost.IsEmpty()), "host can not be the empty string");
// Before we can check if the host matches, we have to
// extract the host part from aUri.
nsAutoCString uriHost;
nsresult rv = aUri->GetAsciiHost(uriHost);
NS_ENSURE_SUCCESS(rv, false);
nsString decodedUriHost;
CSP_PercentDecodeStr(NS_ConvertUTF8toUTF16(uriHost), decodedUriHost);
// 2) host matching: Enforce a single *
if (mHost.EqualsASCII("*")) {
// The single ASTERISK character (*) does not match a URI's scheme of a type
// designating a globally unique identifier (such as blob:, data:, or filesystem:)
// At the moment firefox does not support filesystem; but for future compatibility
// At the moment UXP does not support "filesystem:" but for future compatibility
// we support it in CSP according to the spec, see: 4.2.2 Matching Source Expressions
// Note, that whitelisting any of these schemes would call nsCSPSchemeSrc::permits().
// Note: whitelisting any of these schemes would call nsCSPSchemeSrc::permits().
bool isBlobScheme =
(NS_SUCCEEDED(aUri->SchemeIs("blob", &isBlobScheme)) && isBlobScheme);
bool isDataScheme =
@ -658,20 +667,15 @@ nsCSPHostSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected
if (isBlobScheme || isDataScheme || isFileScheme) {
return false;
}
return true;
// If no scheme is present there also won't be a port and folder to check
// which means we can return early.
if (mScheme.IsEmpty()) {
return true;
}
}
// Before we can check if the host matches, we have to
// extract the host part from aUri.
nsAutoCString uriHost;
nsresult rv = aUri->GetAsciiHost(uriHost);
NS_ENSURE_SUCCESS(rv, false);
nsString decodedUriHost;
CSP_PercentDecodeStr(NS_ConvertUTF8toUTF16(uriHost), decodedUriHost);
// 4.5) host matching: Check if the allowed host starts with a wilcard.
if (mHost.First() == '*') {
else if (mHost.First() == '*') {
NS_ASSERTION(mHost[1] == '.', "Second character needs to be '.' whenever host starts with '*'");
// Eliminate leading "*", but keeping the FULL STOP (.) thereafter before checking

View file

@ -723,7 +723,7 @@ public:
* The resulting vertices are populated in aVerts. aVerts must be
* pre-allocated to hold at least kTransformAndClipRectMaxVerts Points.
* The vertex count is returned by TransformAndClipRect. It is possible to
* emit fewer that 3 vertices, indicating that aRect will not be visible
* emit fewer than 3 vertices, indicating that aRect will not be visible
* within aClip.
*/
template<class F>
@ -734,7 +734,8 @@ public:
// Initialize a double-buffered array of points in homogenous space with
// the input rectangle, aRect.
Point4DTyped<UnknownUnits, F> points[2][kTransformAndClipRectMaxVerts];
Point4DTyped<UnknownUnits, F>* dstPoint = points[0];
Point4DTyped<UnknownUnits, F>* dstPointStart = points[0];
Point4DTyped<UnknownUnits, F>* dstPoint = dstPointStart;
*dstPoint++ = TransformPoint(Point4DTyped<UnknownUnits, F>(aRect.x, aRect.y, 0, 1));
*dstPoint++ = TransformPoint(Point4DTyped<UnknownUnits, F>(aRect.XMost(), aRect.y, 0, 1));
@ -750,16 +751,26 @@ public:
planeNormals[3] = Point4DTyped<UnknownUnits, F>(0.0, -1.0, 0.0, aClip.YMost());
// Iterate through each clipping plane and clip the polygon.
// In each pass, we double buffer, alternating between points[0] and
// points[1].
// For each clipping plane, we intersect the plane with all polygon edges.
// Each pass can increase or decrease the number of points that make up the
// current clipped polygon. We double buffer that set of points, alternating
// between points[0] and points[1].
for (int plane=0; plane < 4; plane++) {
planeNormals[plane].Normalize();
Point4DTyped<UnknownUnits, F>* srcPoint = points[plane & 1];
Point4DTyped<UnknownUnits, F>* srcPoint = dstPointStart;
Point4DTyped<UnknownUnits, F>* srcPointEnd = dstPoint;
dstPoint = points[~plane & 1];
Point4DTyped<UnknownUnits, F>* dstPointStart = dstPoint;
dstPointStart = points[~plane & 1];
dstPoint = dstPointStart;
// Iterate over the polygon edges. In each iteration the current edge is
// the edge from prevPoint to srcPoint. If the two end points lie on
// different sides of the plane, we have an intersection. Otherwise, the
// edge is either completely "inside" the half-space created by the
// clipping plane, and we add srcPoint, or it is completely "outside", and
// we discard srcPoint.
// We may create duplicated points in the polygon. We keep those around
// until all clipping is done and then filter out duplicates at the end.
Point4DTyped<UnknownUnits, F>* prevPoint = srcPointEnd - 1;
F prevDot = planeNormals[plane].DotProduct(*prevPoint);
while (srcPoint < srcPointEnd && ((dstPoint - dstPointStart) < kTransformAndClipRectMaxVerts)) {
@ -783,14 +794,16 @@ public:
}
if (dstPoint == dstPointStart) {
// No polygon points were produced, so the polygon has been
// completely clipped away by the current clipping plane. Exit.
break;
}
}
size_t dstPointCount = 0;
size_t srcPointCount = dstPoint - points[0];
for (Point4DTyped<UnknownUnits, F>* srcPoint = points[0]; srcPoint < points[0] + srcPointCount; srcPoint++) {
Point4DTyped<UnknownUnits, F>* srcPoint = dstPointStart;
Point4DTyped<UnknownUnits, F>* srcPointEnd = dstPoint;
size_t vertCount = 0;
while (srcPoint < srcPointEnd) {
PointTyped<TargetUnits, F> p;
if (srcPoint->w == 0.0) {
// If a point lies on the intersection of the clipping planes at
@ -800,12 +813,13 @@ public:
p = srcPoint->As2DPoint();
}
// Emit only unique points
if (dstPointCount == 0 || p != aVerts[dstPointCount - 1]) {
aVerts[dstPointCount++] = p;
if (vertCount == 0 || p != aVerts[vertCount - 1]) {
aVerts[vertCount++] = p;
}
srcPoint++;
}
return dstPointCount;
return vertCount;
}
static const int kTransformAndClipRectMaxVerts = 32;

View file

@ -0,0 +1,61 @@
/* -*- 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 "gtest/gtest.h"
#include "mozilla/gfx/Matrix.h"
using namespace mozilla;
using namespace mozilla::gfx;
static Rect NudgedToInt(const Rect& aRect) {
Rect r(aRect);
r.NudgeToIntegers();
return r;
}
TEST(Matrix, TransformAndClipRect)
{
Rect c(100, 100, 100, 100);
Matrix4x4 m;
EXPECT_TRUE(m.TransformAndClipBounds(Rect(50, 50, 20, 20), c).IsEmpty());
EXPECT_TRUE(m.TransformAndClipBounds(Rect(250, 50, 20, 20), c).IsEmpty());
EXPECT_TRUE(m.TransformAndClipBounds(Rect(250, 250, 20, 20), c).IsEmpty());
EXPECT_TRUE(m.TransformAndClipBounds(Rect(50, 250, 20, 20), c).IsEmpty());
EXPECT_TRUE(m.TransformAndClipBounds(Rect(50, 50, 100, 20), c).IsEmpty());
EXPECT_TRUE(m.TransformAndClipBounds(Rect(150, 50, 100, 20), c).IsEmpty());
EXPECT_TRUE(m.TransformAndClipBounds(Rect(50, 250, 100, 20), c).IsEmpty());
EXPECT_TRUE(m.TransformAndClipBounds(Rect(150, 250, 100, 20), c).IsEmpty());
EXPECT_TRUE(m.TransformAndClipBounds(Rect(50, 50, 20, 100), c).IsEmpty());
EXPECT_TRUE(m.TransformAndClipBounds(Rect(50, 150, 20, 100), c).IsEmpty());
EXPECT_TRUE(m.TransformAndClipBounds(Rect(250, 50, 20, 100), c).IsEmpty());
EXPECT_TRUE(m.TransformAndClipBounds(Rect(250, 150, 20, 100), c).IsEmpty());
EXPECT_TRUE(NudgedToInt(m.TransformAndClipBounds(Rect(50, 50, 100, 100), c))
.IsEqualInterior(Rect(100, 100, 50, 50)));
EXPECT_TRUE(NudgedToInt(m.TransformAndClipBounds(Rect(150, 50, 100, 100), c))
.IsEqualInterior(Rect(150, 100, 50, 50)));
EXPECT_TRUE(NudgedToInt(m.TransformAndClipBounds(Rect(150, 150, 100, 100), c))
.IsEqualInterior(Rect(150, 150, 50, 50)));
EXPECT_TRUE(NudgedToInt(m.TransformAndClipBounds(Rect(50, 150, 100, 100), c))
.IsEqualInterior(Rect(100, 150, 50, 50)));
EXPECT_TRUE(NudgedToInt(m.TransformAndClipBounds(Rect(110, 110, 80, 80), c))
.IsEqualInterior(Rect(110, 110, 80, 80)));
EXPECT_TRUE(NudgedToInt(m.TransformAndClipBounds(Rect(50, 50, 200, 200), c))
.IsEqualInterior(Rect(100, 100, 100, 100)));
EXPECT_TRUE(NudgedToInt(m.TransformAndClipBounds(Rect(50, 50, 200, 100), c))
.IsEqualInterior(Rect(100, 100, 100, 50)));
EXPECT_TRUE(NudgedToInt(m.TransformAndClipBounds(Rect(50, 150, 200, 100), c))
.IsEqualInterior(Rect(100, 150, 100, 50)));
EXPECT_TRUE(NudgedToInt(m.TransformAndClipBounds(Rect(50, 50, 100, 200), c))
.IsEqualInterior(Rect(100, 100, 50, 100)));
EXPECT_TRUE(NudgedToInt(m.TransformAndClipBounds(Rect(150, 50, 100, 200), c))
.IsEqualInterior(Rect(150, 100, 50, 100)));
}

View file

@ -17,6 +17,7 @@ UNIFIED_SOURCES += [
'TestGfxWidgets.cpp',
'TestJobScheduler.cpp',
'TestLayers.cpp',
'TestMatrix.cpp',
'TestMoz2D.cpp',
'TestPolygon.cpp',
'TestQcms.cpp',

View file

@ -4005,7 +4005,7 @@ jit::ConvertLinearInequality(TempAllocator& alloc, MBasicBlock* block, const Lin
}
static bool
AnalyzePoppedThis(JSContext* cx, ObjectGroup* group,
AnalyzePoppedThis(JSContext* cx, DPAConstraintInfo& constraintInfo, ObjectGroup* group,
MDefinition* thisValue, MInstruction* ins, bool definitelyExecuted,
HandlePlainObject baseobj,
Vector<TypeNewScript::Initializer>* initializerList,
@ -4046,7 +4046,12 @@ AnalyzePoppedThis(JSContext* cx, ObjectGroup* group,
return true;
RootedId id(cx, NameToId(setprop->name()));
if (!AddClearDefiniteGetterSetterForPrototypeChain(cx, group, id)) {
bool added = false;
if (!AddClearDefiniteGetterSetterForPrototypeChain(cx, constraintInfo,
group, id, &added)) {
return false;
}
if (!added) {
// The prototype chain already contains a getter/setter for this
// property, or type information is too imprecise.
return true;
@ -4106,7 +4111,12 @@ AnalyzePoppedThis(JSContext* cx, ObjectGroup* group,
if (!baseobj->lookup(cx, id) && !accessedProperties->append(get->name()))
return false;
if (!AddClearDefiniteGetterSetterForPrototypeChain(cx, group, id)) {
bool added = false;
if (!AddClearDefiniteGetterSetterForPrototypeChain(cx, constraintInfo,
group, id, &added)) {
return false;
}
if (!added) {
// The |this| value can escape if any property reads it does go
// through a getter.
return true;
@ -4132,8 +4142,11 @@ CmpInstructions(const void* a, const void* b)
}
bool
jit::AnalyzeNewScriptDefiniteProperties(JSContext* cx, HandleFunction fun,
ObjectGroup* group, HandlePlainObject baseobj,
jit::AnalyzeNewScriptDefiniteProperties(JSContext* cx,
DPAConstraintInfo& constraintInfo,
HandleFunction fun,
ObjectGroup* group,
HandlePlainObject baseobj,
Vector<TypeNewScript::Initializer>* initializerList)
{
MOZ_ASSERT(cx->zone()->types.activeAnalysis);
@ -4293,7 +4306,7 @@ jit::AnalyzeNewScriptDefiniteProperties(JSContext* cx, HandleFunction fun,
bool handled = false;
size_t slotSpan = baseobj->slotSpan();
if (!AnalyzePoppedThis(cx, group, thisValue, ins, definitelyExecuted,
if (!AnalyzePoppedThis(cx, constraintInfo, group, thisValue, ins, definitelyExecuted,
baseobj, initializerList, &accessedProperties, &handled))
{
return false;
@ -4312,7 +4325,6 @@ jit::AnalyzeNewScriptDefiniteProperties(JSContext* cx, HandleFunction fun,
// contingent on the correct frames being inlined. Add constraints to
// invalidate the definite properties if additional functions could be
// called at the inline frame sites.
Vector<MBasicBlock*> exitBlocks(cx);
for (MBasicBlockIterator block(graph.begin()); block != graph.end(); block++) {
// Inlining decisions made after the last new property was added to
// the object don't need to be frozen.
@ -4320,9 +4332,11 @@ jit::AnalyzeNewScriptDefiniteProperties(JSContext* cx, HandleFunction fun,
break;
if (MResumePoint* rp = block->callerResumePoint()) {
if (block->numPredecessors() == 1 && block->getPredecessor(0) == rp->block()) {
JSScript* script = rp->block()->info().script();
if (!AddClearDefiniteFunctionUsesInScript(cx, group, script, block->info().script()))
JSScript* caller = rp->block()->info().script();
JSScript* callee = block->info().script();
if (!constraintInfo.addInliningConstraint(caller, callee)) {
return false;
}
}
}
}

View file

@ -196,8 +196,11 @@ MCompare*
ConvertLinearInequality(TempAllocator& alloc, MBasicBlock* block, const LinearSum& sum);
MOZ_MUST_USE bool
AnalyzeNewScriptDefiniteProperties(JSContext* cx, HandleFunction fun,
ObjectGroup* group, HandlePlainObject baseobj,
AnalyzeNewScriptDefiniteProperties(JSContext* cx,
DPAConstraintInfo& constraintInfo,
HandleFunction fun,
ObjectGroup* group,
HandlePlainObject baseobj,
Vector<TypeNewScript::Initializer>* initializerList);
MOZ_MUST_USE bool

View file

@ -2010,6 +2010,28 @@ JS_GetOwnUCPropertyDescriptor(JSContext* cx, HandleObject obj, const char16_t* n
return JS_GetOwnPropertyDescriptorById(cx, obj, id, desc);
}
JS_PUBLIC_API(bool)
JS_GetOwnElement(JSContext* cx, JS::HandleObject obj, uint32_t index, JS::MutableHandleValue vp)
{
RootedId id(cx);
if (!IndexToId(cx, index, &id)) {
return false;
}
Rooted<PropertyDescriptor> desc(cx);
if (!JS_GetOwnPropertyDescriptorById(cx, obj, id, &desc)) {
return false;
}
if (desc.object() && desc.isDataDescriptor()) {
vp.set(desc.value());
} else {
vp.setUndefined();
}
return true;
}
JS_PUBLIC_API(bool)
JS_GetPropertyDescriptorById(JSContext* cx, HandleObject obj, HandleId id,
MutableHandle<PropertyDescriptor> desc)

View file

@ -2922,6 +2922,9 @@ extern JS_PUBLIC_API(bool)
JS_GetOwnUCPropertyDescriptor(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen,
JS::MutableHandle<JS::PropertyDescriptor> desc);
extern JS_PUBLIC_API(bool)
JS_GetOwnElement(JSContext* cx, JS::HandleObject obj, uint32_t index, JS::MutableHandleValue vp);
/**
* Like JS_GetOwnPropertyDescriptorById, but also searches the prototype chain
* if no own property is found directly on obj. The object on which the

View file

@ -3084,29 +3084,39 @@ class TypeConstraintClearDefiniteGetterSetter : public TypeConstraint
};
bool
js::AddClearDefiniteGetterSetterForPrototypeChain(JSContext* cx, ObjectGroup* group, HandleId id)
js::AddClearDefiniteGetterSetterForPrototypeChain(JSContext* cx,
DPAConstraintInfo& constraintInfo,
ObjectGroup* group,
HandleId id,
bool* added)
{
/*
* Ensure that if the properties named here could have a getter, setter or
* a permanent property in any transitive prototype, the definite
* properties get cleared from the group.
*/
*added = false;
RootedObject proto(cx, group->proto().toObjectOrNull());
while (proto) {
ObjectGroup* protoGroup = JSObject::getGroup(cx, proto);
if (!protoGroup) {
cx->recoverFromOutOfMemory();
return false;
}
if (protoGroup->unknownProperties())
return false;
return true;
HeapTypeSet* protoTypes = protoGroup->getProperty(cx, proto, id);
if (!protoTypes || protoTypes->nonDataProperty() || protoTypes->nonWritableProperty())
if (!protoTypes)
return false;
if (!protoTypes->addConstraint(cx, cx->typeLifoAlloc().new_<TypeConstraintClearDefiniteGetterSetter>(group)))
if (protoTypes->nonDataProperty() || protoTypes->nonWritableProperty())
return true;
if (!constraintInfo.addProtoConstraint(proto, id))
return false;
proto = proto->staticPrototype();
}
*added = true;
return true;
}
@ -3612,6 +3622,43 @@ struct DestroyTypeNewScript
} // namespace
bool DPAConstraintInfo::finishConstraints(JSContext* cx, ObjectGroup* group) {
for (const ProtoConstraint& constraint : protoConstraints_) {
ObjectGroup* protoGroup = constraint.proto->group();
// Note: we rely on the group's type information being unchanged since
// AddClearDefiniteGetterSetterForPrototypeChain.
bool unknownProperties = protoGroup->unknownProperties();
MOZ_RELEASE_ASSERT(!unknownProperties);
HeapTypeSet* protoTypes =
protoGroup->getProperty(cx, constraint.proto, constraint.id);
MOZ_RELEASE_ASSERT(protoTypes);
MOZ_ASSERT(!protoTypes->nonDataProperty());
MOZ_ASSERT(!protoTypes->nonWritableProperty());
if (!protoTypes->addConstraint(
cx,
cx->typeLifoAlloc().new_<TypeConstraintClearDefiniteGetterSetter>(
group))) {
ReportOutOfMemory(cx);
return false;
}
}
for (const InliningConstraint& constraint : inliningConstraints_) {
if (!AddClearDefiniteFunctionUsesInScript(cx, group, constraint.caller,
constraint.callee)) {
ReportOutOfMemory(cx);
return false;
}
}
return true;
}
bool
TypeNewScript::maybeAnalyze(JSContext* cx, ObjectGroup* group, bool* regenerate, bool force)
{
@ -3715,10 +3762,17 @@ TypeNewScript::maybeAnalyze(JSContext* cx, ObjectGroup* group, bool* regenerate,
return false;
Vector<Initializer> initializerVector(cx);
DPAConstraintInfo constraintInfo(cx);
RootedPlainObject templateRoot(cx, templateObject());
RootedFunction fun(cx, function());
if (!jit::AnalyzeNewScriptDefiniteProperties(cx, fun, group, templateRoot, &initializerVector))
if (!jit::AnalyzeNewScriptDefiniteProperties(cx,
constraintInfo,
fun,
group,
templateRoot,
&initializerVector))
return false;
if (!group->newScript())
@ -3772,6 +3826,14 @@ TypeNewScript::maybeAnalyze(JSContext* cx, ObjectGroup* group, bool* regenerate,
// The definite properties analysis found exactly the properties that
// are held in common by the preliminary objects. No further analysis
// is needed.
if (!constraintInfo.finishConstraints(cx, group)) {
return false;
}
if (!group->newScript()) {
return true;
}
group->addDefiniteProperties(cx, templateObject()->lastProperty());
destroyNewScript.group = nullptr;
@ -3792,6 +3854,16 @@ TypeNewScript::maybeAnalyze(JSContext* cx, ObjectGroup* group, bool* regenerate,
initialFlags);
if (!initialGroup)
return false;
// Add the constraints. Use the initialGroup as group referenced by the
// constraints because that's the group that will have the TypeNewScript
// associated with it. See the detachNewScript and setNewScript calls below.
if (!constraintInfo.finishConstraints(cx, initialGroup)) {
return false;
}
if (!group->newScript()) {
return true;
}
initialGroup->addDefiniteProperties(cx, templateObject()->lastProperty());
group->addDefiniteProperties(cx, prefixShape);

View file

@ -789,8 +789,65 @@ class TemporaryTypeSet : public TypeSet
TypedArraySharedness* sharedness);
};
// Stack class to record information about constraints that need to be added
// after finishing the Definite Properties Analysis. When the analysis succeeds,
// the |finishConstraints| method must be called to add the constraints to the
// TypeSets.
//
// There are two constraint types managed here:
//
// 1. Proto constraints for HeapTypeSets, to guard against things like getters
// and setters on the proto chain.
//
// 2. Inlining constraints for StackTypeSets, to invalidate when additional
// functions could be called at call sites where we inlined a function.
//
// This class uses bare GC-thing pointers because GC is suppressed when the
// analysis runs.
class MOZ_RAII DPAConstraintInfo {
struct ProtoConstraint {
JSObject* proto;
jsid id;
ProtoConstraint(JSObject* proto, jsid id) : proto(proto), id(id) {}
};
struct InliningConstraint {
JSScript* caller;
JSScript* callee;
InliningConstraint(JSScript* caller, JSScript* callee)
: caller(caller), callee(callee) {}
};
JS::AutoCheckCannotGC nogc_;
Vector<ProtoConstraint, 8> protoConstraints_;
Vector<InliningConstraint, 4> inliningConstraints_;
public:
explicit DPAConstraintInfo(JSContext* cx)
: nogc_(cx)
, protoConstraints_(cx)
, inliningConstraints_(cx)
{
}
DPAConstraintInfo(const DPAConstraintInfo&) = delete;
void operator=(const DPAConstraintInfo&) = delete;
MOZ_MUST_USE bool addProtoConstraint(JSObject* proto, jsid id) {
return protoConstraints_.emplaceBack(proto, id);
}
MOZ_MUST_USE bool addInliningConstraint(JSScript* caller, JSScript* callee) {
return inliningConstraints_.emplaceBack(caller, callee);
}
MOZ_MUST_USE bool finishConstraints(JSContext* cx, ObjectGroup* group);
};
bool
AddClearDefiniteGetterSetterForPrototypeChain(JSContext* cx, ObjectGroup* group, HandleId id);
AddClearDefiniteGetterSetterForPrototypeChain(JSContext* cx,
DPAConstraintInfo& constraintInfo,
ObjectGroup* group,
HandleId id,
bool* added);
bool
AddClearDefiniteFunctionUsesInScript(JSContext* cx, ObjectGroup* group,

View file

@ -1,5 +1,6 @@
/*
* Copyright (c) 2008-2015 Mozilla Foundation
* Copyright (c) 2019 Moonchild Productions
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@ -44,32 +45,66 @@ struct staticJArray {
}
};
template<class T, class L>
struct jArray {
template <class T, class L>
class autoJArray;
template <class T, class L>
class jArray {
friend class autoJArray<T, L>;
private:
T* arr;
public:
L length;
static jArray<T,L> newJArray(L const len) {
MOZ_ASSERT(len >= 0, "Negative length.");
jArray<T,L> newArray = { new T[size_t(len)], len };
return newArray;
}
static jArray<T,L> newFallibleJArray(L const len) {
MOZ_ASSERT(len >= 0, "Negative length.");
T* a = new (mozilla::fallible) T[size_t(len)];
jArray<T,L> newArray = { a, a ? len : 0 };
return newArray;
}
operator T*() { return arr; }
operator T*() {
return arr;
}
T& operator[] (L const index) {
MOZ_ASSERT(index >= 0, "Array access with negative index.");
MOZ_ASSERT(index < length, "Array index out of bounds.");
return arr[index];
}
void operator=(staticJArray<T,L>& other) {
arr = (T*)other.arr;
length = other.length;
}
};
MOZ_IMPLICIT jArray(decltype(nullptr))
: arr(nullptr)
, length(0)
{
}
jArray()
: arr(nullptr)
, length(0)
{
}
private:
jArray(T* aArr, L aLength)
: arr(aArr)
, length(aLength)
{
}
}; // class jArray
template<class T, class L>
class autoJArray {

View file

@ -1,59 +0,0 @@
# 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/.
libs:: translator
translator:: javaparser \
; mkdir -p htmlparser/bin && \
find htmlparser/translator-src/nu/validator/htmlparser -name "*.java" | \
xargs javac -cp javaparser.jar -g -d htmlparser/bin && \
jar cfm translator.jar manifest.txt -C htmlparser/bin .
javaparser:: \
; mkdir -p javaparser/bin && \
find javaparser/src -name "*.java" | \
xargs javac -encoding ISO-8859-1 -g -d javaparser/bin && \
jar cf javaparser.jar -C javaparser/bin .
sync_javaparser:: \
; if [ ! -d javaparser/.git ] ; \
then rm -rf javaparser ; \
git clone https://github.com/javaparser/javaparser.git ; \
fi ; \
cd javaparser ; git checkout javaparser-1.0.6 ; cd ..
sync_htmlparser:: \
; if [ -d htmlparser/.hg ] ; \
then cd htmlparser ; hg pull --rebase ; cd .. ; \
else \
rm -rf htmlparser ; \
hg clone https://hg.mozilla.org/projects/htmlparser ; \
fi
sync:: sync_javaparser sync_htmlparser
translate:: translator \
; mkdir -p ../javasrc ; \
java -jar translator.jar \
htmlparser/src/nu/validator/htmlparser/impl \
.. ../nsHtml5AtomList.h
translate_from_snapshot:: translator \
; mkdir -p ../javasrc ; \
java -jar translator.jar \
../javasrc \
.. ../nsHtml5AtomList.h
named_characters:: translator \
; java -cp translator.jar \
nu.validator.htmlparser.generator.GenerateNamedCharactersCpp \
named-character-references.html ../
clean_javaparser:: \
; rm -rf javaparser/bin javaparser.jar
clean_htmlparser:: \
; rm -rf htmlparser/bin translator.jar
clean:: clean_javaparser clean_htmlparser

View file

@ -1,46 +0,0 @@
If this is your first time building the HTML5 parser, you need to execute the
following commands (from this directory) to bootstrap the translation:
make sync # fetch remote source files and licenses
make translate # perform the Java-to-C++ translation from the remote
# sources
make named_characters # Generate tables for named character tokenization
If you make changes to the translator or the javaparser, you can rebuild by
retyping 'make' in this directory. If you make changes to the HTML5 Java
implementation, you can retranslate the Java sources from the htmlparser
repository by retyping 'make translate' in this directory.
The makefile supports the following targets:
sync_htmlparser:
Retrieves the HTML parser and Java to C++ translator sources from Mozilla's
htmlparser repository.
sync_javaparser:
Retrieves the javaparser sources from GitHub.
sync:
Runs both sync_javaparser and sync_htmlparser.
javaparser:
Builds the javaparser library retrieved earlier by sync_javaparser.
translator:
Runs the javaparser target and then builds the Java to C++ translator from
sources retrieved earlier by sync_htmlparser.
libs:
The default target. Alias for translator
translate:
Runs the translator target and then translates the HTML parser sources
retrieved by sync_htmlparser copying the Java sources to ../javasrc.
translate_from_snapshot:
Runs the translator target and then translates the HTML parser sources
stored in ../javasrc.
named_characters:
Generates data tables for named character tokenization.
clean_javaparser:
Removes the build products of the javaparser target.
clean_htmlparser:
Removes the build products of the translator target.
clean:
Runs both clean_javaparser and clean_htmlparser.
Ben Newman (23 September 2009)
Henri Sivonen (11 August 2016)

View file

@ -1,2 +0,0 @@
Main-Class: nu.validator.htmlparser.cpptranslate.Main
Class-Path: javaparser.jar

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,618 +0,0 @@
/*
* Copyright (c) 2007 Henri Sivonen
* Copyright (c) 2008-2011 Mozilla Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
package nu.validator.htmlparser.impl;
import nu.validator.htmlparser.annotation.Auto;
import nu.validator.htmlparser.annotation.IdType;
import nu.validator.htmlparser.annotation.Local;
import nu.validator.htmlparser.annotation.NsUri;
import nu.validator.htmlparser.annotation.Prefix;
import nu.validator.htmlparser.annotation.QName;
import nu.validator.htmlparser.common.Interner;
import nu.validator.htmlparser.common.XmlViolationPolicy;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
/**
* Be careful with this class. QName is the name in from HTML tokenization.
* Otherwise, please refer to the interface doc.
*
* @version $Id: AttributesImpl.java 206 2008-03-20 14:09:29Z hsivonen $
* @author hsivonen
*/
public final class HtmlAttributes implements Attributes {
// [NOCPP[
private static final AttributeName[] EMPTY_ATTRIBUTENAMES = new AttributeName[0];
private static final String[] EMPTY_STRINGS = new String[0];
// ]NOCPP]
public static final HtmlAttributes EMPTY_ATTRIBUTES = new HtmlAttributes(
AttributeName.HTML);
private int mode;
private int length;
private @Auto AttributeName[] names;
private @Auto String[] values; // XXX perhaps make this @NoLength?
// CPPONLY: private @Auto int[] lines; // XXX perhaps make this @NoLength?
// [NOCPP[
private String idValue;
private int xmlnsLength;
private AttributeName[] xmlnsNames;
private String[] xmlnsValues;
// ]NOCPP]
public HtmlAttributes(int mode) {
this.mode = mode;
this.length = 0;
/*
* The length of 5 covers covers 98.3% of elements
* according to Hixie, but lets round to the next power of two for
* jemalloc.
*/
this.names = new AttributeName[8];
this.values = new String[8];
// CPPONLY: this.lines = new int[8];
// [NOCPP[
this.idValue = null;
this.xmlnsLength = 0;
this.xmlnsNames = HtmlAttributes.EMPTY_ATTRIBUTENAMES;
this.xmlnsValues = HtmlAttributes.EMPTY_STRINGS;
// ]NOCPP]
}
/*
public HtmlAttributes(HtmlAttributes other) {
this.mode = other.mode;
this.length = other.length;
this.names = new AttributeName[other.length];
this.values = new String[other.length];
// [NOCPP[
this.idValue = other.idValue;
this.xmlnsLength = other.xmlnsLength;
this.xmlnsNames = new AttributeName[other.xmlnsLength];
this.xmlnsValues = new String[other.xmlnsLength];
// ]NOCPP]
}
*/
void destructor() {
clear(0);
}
/**
* Only use with a static argument
*
* @param name
* @return
*/
public int getIndex(AttributeName name) {
for (int i = 0; i < length; i++) {
if (names[i] == name) {
return i;
}
}
return -1;
}
/**
* Only use with static argument.
*
* @see org.xml.sax.Attributes#getValue(java.lang.String)
*/
public String getValue(AttributeName name) {
int index = getIndex(name);
if (index == -1) {
return null;
} else {
return getValueNoBoundsCheck(index);
}
}
public int getLength() {
return length;
}
/**
* Variant of <code>getLocalName(int index)</code> without bounds check.
* @param index a valid attribute index
* @return the local name at index
*/
public @Local String getLocalNameNoBoundsCheck(int index) {
// CPPONLY: assert index < length && index >= 0: "Index out of bounds";
return names[index].getLocal(mode);
}
/**
* Variant of <code>getURI(int index)</code> without bounds check.
* @param index a valid attribute index
* @return the namespace URI at index
*/
public @NsUri String getURINoBoundsCheck(int index) {
// CPPONLY: assert index < length && index >= 0: "Index out of bounds";
return names[index].getUri(mode);
}
/**
* Variant of <code>getPrefix(int index)</code> without bounds check.
* @param index a valid attribute index
* @return the namespace prefix at index
*/
public @Prefix String getPrefixNoBoundsCheck(int index) {
// CPPONLY: assert index < length && index >= 0: "Index out of bounds";
return names[index].getPrefix(mode);
}
/**
* Variant of <code>getValue(int index)</code> without bounds check.
* @param index a valid attribute index
* @return the attribute value at index
*/
public String getValueNoBoundsCheck(int index) {
// CPPONLY: assert index < length && index >= 0: "Index out of bounds";
return values[index];
}
/**
* Variant of <code>getAttributeName(int index)</code> without bounds check.
* @param index a valid attribute index
* @return the attribute name at index
*/
public AttributeName getAttributeNameNoBoundsCheck(int index) {
// CPPONLY: assert index < length && index >= 0: "Index out of bounds";
return names[index];
}
// CPPONLY: /**
// CPPONLY: * Obtains a line number without bounds check.
// CPPONLY: * @param index a valid attribute index
// CPPONLY: * @return the line number at index or -1 if unknown
// CPPONLY: */
// CPPONLY: public int getLineNoBoundsCheck(int index) {
// CPPONLY: assert index < length && index >= 0: "Index out of bounds";
// CPPONLY: return lines[index];
// CPPONLY: }
// [NOCPP[
/**
* Variant of <code>getQName(int index)</code> without bounds check.
* @param index a valid attribute index
* @return the QName at index
*/
public @QName String getQNameNoBoundsCheck(int index) {
return names[index].getQName(mode);
}
/**
* Variant of <code>getType(int index)</code> without bounds check.
* @param index a valid attribute index
* @return the attribute type at index
*/
public @IdType String getTypeNoBoundsCheck(int index) {
return (names[index] == AttributeName.ID) ? "ID" : "CDATA";
}
public int getIndex(String qName) {
for (int i = 0; i < length; i++) {
if (names[i].getQName(mode).equals(qName)) {
return i;
}
}
return -1;
}
public int getIndex(String uri, String localName) {
for (int i = 0; i < length; i++) {
if (names[i].getLocal(mode).equals(localName)
&& names[i].getUri(mode).equals(uri)) {
return i;
}
}
return -1;
}
public @IdType String getType(String qName) {
int index = getIndex(qName);
if (index == -1) {
return null;
} else {
return getType(index);
}
}
public @IdType String getType(String uri, String localName) {
int index = getIndex(uri, localName);
if (index == -1) {
return null;
} else {
return getType(index);
}
}
public String getValue(String qName) {
int index = getIndex(qName);
if (index == -1) {
return null;
} else {
return getValue(index);
}
}
public String getValue(String uri, String localName) {
int index = getIndex(uri, localName);
if (index == -1) {
return null;
} else {
return getValue(index);
}
}
public @Local String getLocalName(int index) {
if (index < length && index >= 0) {
return names[index].getLocal(mode);
} else {
return null;
}
}
public @QName String getQName(int index) {
if (index < length && index >= 0) {
return names[index].getQName(mode);
} else {
return null;
}
}
public @IdType String getType(int index) {
if (index < length && index >= 0) {
return (names[index] == AttributeName.ID) ? "ID" : "CDATA";
} else {
return null;
}
}
public AttributeName getAttributeName(int index) {
if (index < length && index >= 0) {
return names[index];
} else {
return null;
}
}
public @NsUri String getURI(int index) {
if (index < length && index >= 0) {
return names[index].getUri(mode);
} else {
return null;
}
}
public @Prefix String getPrefix(int index) {
if (index < length && index >= 0) {
return names[index].getPrefix(mode);
} else {
return null;
}
}
public String getValue(int index) {
if (index < length && index >= 0) {
return values[index];
} else {
return null;
}
}
public String getId() {
return idValue;
}
public int getXmlnsLength() {
return xmlnsLength;
}
public @Local String getXmlnsLocalName(int index) {
if (index < xmlnsLength && index >= 0) {
return xmlnsNames[index].getLocal(mode);
} else {
return null;
}
}
public @NsUri String getXmlnsURI(int index) {
if (index < xmlnsLength && index >= 0) {
return xmlnsNames[index].getUri(mode);
} else {
return null;
}
}
public String getXmlnsValue(int index) {
if (index < xmlnsLength && index >= 0) {
return xmlnsValues[index];
} else {
return null;
}
}
public int getXmlnsIndex(AttributeName name) {
for (int i = 0; i < xmlnsLength; i++) {
if (xmlnsNames[i] == name) {
return i;
}
}
return -1;
}
public String getXmlnsValue(AttributeName name) {
int index = getXmlnsIndex(name);
if (index == -1) {
return null;
} else {
return getXmlnsValue(index);
}
}
public AttributeName getXmlnsAttributeName(int index) {
if (index < xmlnsLength && index >= 0) {
return xmlnsNames[index];
} else {
return null;
}
}
// ]NOCPP]
void addAttribute(AttributeName name, String value
// [NOCPP[
, XmlViolationPolicy xmlnsPolicy
// ]NOCPP]
// CPPONLY: , int line
) throws SAXException {
// [NOCPP[
if (name == AttributeName.ID) {
idValue = value;
}
if (name.isXmlns()) {
if (xmlnsNames.length == xmlnsLength) {
int newLen = xmlnsLength == 0 ? 2 : xmlnsLength << 1;
AttributeName[] newNames = new AttributeName[newLen];
System.arraycopy(xmlnsNames, 0, newNames, 0, xmlnsNames.length);
xmlnsNames = newNames;
String[] newValues = new String[newLen];
System.arraycopy(xmlnsValues, 0, newValues, 0, xmlnsValues.length);
xmlnsValues = newValues;
}
xmlnsNames[xmlnsLength] = name;
xmlnsValues[xmlnsLength] = value;
xmlnsLength++;
switch (xmlnsPolicy) {
case FATAL:
// this is ugly
throw new SAXException("Saw an xmlns attribute.");
case ALTER_INFOSET:
return;
case ALLOW:
// fall through
}
}
// ]NOCPP]
if (names.length == length) {
int newLen = length << 1; // The first growth covers virtually
// 100% of elements according to
// Hixie
AttributeName[] newNames = new AttributeName[newLen];
System.arraycopy(names, 0, newNames, 0, names.length);
names = newNames;
String[] newValues = new String[newLen];
System.arraycopy(values, 0, newValues, 0, values.length);
values = newValues;
// CPPONLY: int[] newLines = new int[newLen];
// CPPONLY: System.arraycopy(lines, 0, newLines, 0, lines.length);
// CPPONLY: lines = newLines;
}
names[length] = name;
values[length] = value;
// CPPONLY: lines[length] = line;
length++;
}
void clear(int m) {
for (int i = 0; i < length; i++) {
names[i].release();
names[i] = null;
Portability.releaseString(values[i]);
values[i] = null;
}
length = 0;
mode = m;
// [NOCPP[
idValue = null;
for (int i = 0; i < xmlnsLength; i++) {
xmlnsNames[i] = null;
xmlnsValues[i] = null;
}
xmlnsLength = 0;
// ]NOCPP]
}
/**
* This is used in C++ to release special <code>isindex</code>
* attribute values whose ownership is not transferred.
*/
void releaseValue(int i) {
Portability.releaseString(values[i]);
}
/**
* This is only used for <code>AttributeName</code> ownership transfer
* in the isindex case to avoid freeing custom names twice in C++.
*/
void clearWithoutReleasingContents() {
for (int i = 0; i < length; i++) {
names[i] = null;
values[i] = null;
}
length = 0;
}
boolean contains(AttributeName name) {
for (int i = 0; i < length; i++) {
if (name.equalsAnother(names[i])) {
return true;
}
}
// [NOCPP[
for (int i = 0; i < xmlnsLength; i++) {
if (name.equalsAnother(xmlnsNames[i])) {
return true;
}
}
// ]NOCPP]
return false;
}
public void adjustForMath() {
mode = AttributeName.MATHML;
}
public void adjustForSvg() {
mode = AttributeName.SVG;
}
public HtmlAttributes cloneAttributes(Interner interner)
throws SAXException {
assert (length == 0
// [NOCPP[
&& xmlnsLength == 0
// ]NOCPP]
)
|| mode == 0 || mode == 3;
HtmlAttributes clone = new HtmlAttributes(0);
for (int i = 0; i < length; i++) {
clone.addAttribute(names[i].cloneAttributeName(interner),
Portability.newStringFromString(values[i])
// [NOCPP[
, XmlViolationPolicy.ALLOW
// ]NOCPP]
// CPPONLY: , lines[i]
);
}
// [NOCPP[
for (int i = 0; i < xmlnsLength; i++) {
clone.addAttribute(xmlnsNames[i], xmlnsValues[i],
XmlViolationPolicy.ALLOW);
}
// ]NOCPP]
return clone; // XXX!!!
}
public boolean equalsAnother(HtmlAttributes other) {
assert mode == 0 || mode == 3 : "Trying to compare attributes in foreign content.";
int otherLength = other.getLength();
if (length != otherLength) {
return false;
}
for (int i = 0; i < length; i++) {
// Work around the limitations of C++
boolean found = false;
// The comparing just the local names is OK, since these attribute
// holders are both supposed to belong to HTML formatting elements
@Local String ownLocal = names[i].getLocal(AttributeName.HTML);
for (int j = 0; j < otherLength; j++) {
if (ownLocal == other.names[j].getLocal(AttributeName.HTML)) {
found = true;
if (!Portability.stringEqualsString(values[i], other.values[j])) {
return false;
}
}
}
if (!found) {
return false;
}
}
return true;
}
// [NOCPP[
void processNonNcNames(TreeBuilder<?> treeBuilder, XmlViolationPolicy namePolicy) throws SAXException {
for (int i = 0; i < length; i++) {
AttributeName attName = names[i];
if (!attName.isNcName(mode)) {
String name = attName.getLocal(mode);
switch (namePolicy) {
case ALTER_INFOSET:
names[i] = AttributeName.create(NCName.escapeName(name));
// fall through
case ALLOW:
if (attName != AttributeName.XML_LANG) {
treeBuilder.warn("Attribute \u201C" + name + "\u201D is not serializable as XML 1.0.");
}
break;
case FATAL:
treeBuilder.fatal("Attribute \u201C" + name + "\u201D is not serializable as XML 1.0.");
break;
}
}
}
}
public void merge(HtmlAttributes attributes) throws SAXException {
int len = attributes.getLength();
for (int i = 0; i < len; i++) {
AttributeName name = attributes.getAttributeNameNoBoundsCheck(i);
if (!contains(name)) {
addAttribute(name, attributes.getValueNoBoundsCheck(i), XmlViolationPolicy.ALLOW);
}
}
}
// ]NOCPP]
}

View file

@ -1,854 +0,0 @@
/*
* Copyright (c) 2007 Henri Sivonen
* Copyright (c) 2008-2015 Mozilla Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
package nu.validator.htmlparser.impl;
import java.io.IOException;
import nu.validator.htmlparser.annotation.Auto;
import nu.validator.htmlparser.annotation.Inline;
import nu.validator.htmlparser.common.ByteReadable;
import org.xml.sax.SAXException;
public abstract class MetaScanner {
/**
* Constant for "charset".
*/
private static final char[] CHARSET = { 'h', 'a', 'r', 's', 'e', 't' };
/**
* Constant for "content".
*/
private static final char[] CONTENT = { 'o', 'n', 't', 'e', 'n', 't' };
/**
* Constant for "http-equiv".
*/
private static final char[] HTTP_EQUIV = { 't', 't', 'p', '-', 'e', 'q',
'u', 'i', 'v' };
/**
* Constant for "content-type".
*/
private static final char[] CONTENT_TYPE = { 'c', 'o', 'n', 't', 'e', 'n',
't', '-', 't', 'y', 'p', 'e' };
private static final int NO = 0;
private static final int M = 1;
private static final int E = 2;
private static final int T = 3;
private static final int A = 4;
private static final int DATA = 0;
private static final int TAG_OPEN = 1;
private static final int SCAN_UNTIL_GT = 2;
private static final int TAG_NAME = 3;
private static final int BEFORE_ATTRIBUTE_NAME = 4;
private static final int ATTRIBUTE_NAME = 5;
private static final int AFTER_ATTRIBUTE_NAME = 6;
private static final int BEFORE_ATTRIBUTE_VALUE = 7;
private static final int ATTRIBUTE_VALUE_DOUBLE_QUOTED = 8;
private static final int ATTRIBUTE_VALUE_SINGLE_QUOTED = 9;
private static final int ATTRIBUTE_VALUE_UNQUOTED = 10;
private static final int AFTER_ATTRIBUTE_VALUE_QUOTED = 11;
private static final int MARKUP_DECLARATION_OPEN = 13;
private static final int MARKUP_DECLARATION_HYPHEN = 14;
private static final int COMMENT_START = 15;
private static final int COMMENT_START_DASH = 16;
private static final int COMMENT = 17;
private static final int COMMENT_END_DASH = 18;
private static final int COMMENT_END = 19;
private static final int SELF_CLOSING_START_TAG = 20;
private static final int HTTP_EQUIV_NOT_SEEN = 0;
private static final int HTTP_EQUIV_CONTENT_TYPE = 1;
private static final int HTTP_EQUIV_OTHER = 2;
/**
* The data source.
*/
protected ByteReadable readable;
/**
* The state of the state machine that recognizes the tag name "meta".
*/
private int metaState = NO;
/**
* The current position in recognizing the attribute name "content".
*/
private int contentIndex = Integer.MAX_VALUE;
/**
* The current position in recognizing the attribute name "charset".
*/
private int charsetIndex = Integer.MAX_VALUE;
/**
* The current position in recognizing the attribute name "http-equive".
*/
private int httpEquivIndex = Integer.MAX_VALUE;
/**
* The current position in recognizing the attribute value "content-type".
*/
private int contentTypeIndex = Integer.MAX_VALUE;
/**
* The tokenizer state.
*/
protected int stateSave = DATA;
/**
* The currently filled length of strBuf.
*/
private int strBufLen;
/**
* Accumulation buffer for attribute values.
*/
private @Auto char[] strBuf;
private String content;
private String charset;
private int httpEquivState;
// CPPONLY: private TreeBuilder treeBuilder;
public MetaScanner(
// CPPONLY: TreeBuilder tb
) {
this.readable = null;
this.metaState = NO;
this.contentIndex = Integer.MAX_VALUE;
this.charsetIndex = Integer.MAX_VALUE;
this.httpEquivIndex = Integer.MAX_VALUE;
this.contentTypeIndex = Integer.MAX_VALUE;
this.stateSave = DATA;
this.strBufLen = 0;
this.strBuf = new char[36];
this.content = null;
this.charset = null;
this.httpEquivState = HTTP_EQUIV_NOT_SEEN;
// CPPONLY: this.treeBuilder = tb;
}
@SuppressWarnings("unused") private void destructor() {
Portability.releaseString(content);
Portability.releaseString(charset);
}
// [NOCPP[
/**
* Reads a byte from the data source.
*
* -1 means end.
* @return
* @throws IOException
*/
protected int read() throws IOException {
return readable.readByte();
}
// ]NOCPP]
// WARNING When editing this, makes sure the bytecode length shown by javap
// stays under 8000 bytes!
/**
* The runs the meta scanning algorithm.
*/
protected final void stateLoop(int state)
throws SAXException, IOException {
int c = -1;
boolean reconsume = false;
stateloop: for (;;) {
switch (state) {
case DATA:
dataloop: for (;;) {
if (reconsume) {
reconsume = false;
} else {
c = read();
}
switch (c) {
case -1:
break stateloop;
case '<':
state = MetaScanner.TAG_OPEN;
break dataloop; // FALL THROUGH continue
// stateloop;
default:
continue;
}
}
// WARNING FALLTHRU CASE TRANSITION: DON'T REORDER
case TAG_OPEN:
tagopenloop: for (;;) {
c = read();
switch (c) {
case -1:
break stateloop;
case 'm':
case 'M':
metaState = M;
state = MetaScanner.TAG_NAME;
break tagopenloop;
// continue stateloop;
case '!':
state = MetaScanner.MARKUP_DECLARATION_OPEN;
continue stateloop;
case '?':
case '/':
state = MetaScanner.SCAN_UNTIL_GT;
continue stateloop;
case '>':
state = MetaScanner.DATA;
continue stateloop;
default:
if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) {
metaState = NO;
state = MetaScanner.TAG_NAME;
break tagopenloop;
// continue stateloop;
}
state = MetaScanner.DATA;
reconsume = true;
continue stateloop;
}
}
// FALL THROUGH DON'T REORDER
case TAG_NAME:
tagnameloop: for (;;) {
c = read();
switch (c) {
case -1:
break stateloop;
case ' ':
case '\t':
case '\n':
case '\u000C':
state = MetaScanner.BEFORE_ATTRIBUTE_NAME;
break tagnameloop;
// continue stateloop;
case '/':
state = MetaScanner.SELF_CLOSING_START_TAG;
continue stateloop;
case '>':
state = MetaScanner.DATA;
continue stateloop;
case 'e':
case 'E':
if (metaState == M) {
metaState = E;
} else {
metaState = NO;
}
continue;
case 't':
case 'T':
if (metaState == E) {
metaState = T;
} else {
metaState = NO;
}
continue;
case 'a':
case 'A':
if (metaState == T) {
metaState = A;
} else {
metaState = NO;
}
continue;
default:
metaState = NO;
continue;
}
}
// FALLTHRU DON'T REORDER
case BEFORE_ATTRIBUTE_NAME:
beforeattributenameloop: for (;;) {
if (reconsume) {
reconsume = false;
} else {
c = read();
}
/*
* Consume the next input character:
*/
switch (c) {
case -1:
break stateloop;
case ' ':
case '\t':
case '\n':
case '\u000C':
continue;
case '/':
state = MetaScanner.SELF_CLOSING_START_TAG;
continue stateloop;
case '>':
if (handleTag()) {
break stateloop;
}
state = DATA;
continue stateloop;
case 'c':
case 'C':
contentIndex = 0;
charsetIndex = 0;
httpEquivIndex = Integer.MAX_VALUE;
contentTypeIndex = Integer.MAX_VALUE;
state = MetaScanner.ATTRIBUTE_NAME;
break beforeattributenameloop;
case 'h':
case 'H':
contentIndex = Integer.MAX_VALUE;
charsetIndex = Integer.MAX_VALUE;
httpEquivIndex = 0;
contentTypeIndex = Integer.MAX_VALUE;
state = MetaScanner.ATTRIBUTE_NAME;
break beforeattributenameloop;
default:
contentIndex = Integer.MAX_VALUE;
charsetIndex = Integer.MAX_VALUE;
httpEquivIndex = Integer.MAX_VALUE;
contentTypeIndex = Integer.MAX_VALUE;
state = MetaScanner.ATTRIBUTE_NAME;
break beforeattributenameloop;
// continue stateloop;
}
}
// FALLTHRU DON'T REORDER
case ATTRIBUTE_NAME:
attributenameloop: for (;;) {
c = read();
switch (c) {
case -1:
break stateloop;
case ' ':
case '\t':
case '\n':
case '\u000C':
state = MetaScanner.AFTER_ATTRIBUTE_NAME;
continue stateloop;
case '/':
state = MetaScanner.SELF_CLOSING_START_TAG;
continue stateloop;
case '=':
strBufLen = 0;
contentTypeIndex = 0;
state = MetaScanner.BEFORE_ATTRIBUTE_VALUE;
break attributenameloop;
// continue stateloop;
case '>':
if (handleTag()) {
break stateloop;
}
state = MetaScanner.DATA;
continue stateloop;
default:
if (metaState == A) {
if (c >= 'A' && c <= 'Z') {
c += 0x20;
}
if (contentIndex < CONTENT.length && c == CONTENT[contentIndex]) {
++contentIndex;
} else {
contentIndex = Integer.MAX_VALUE;
}
if (charsetIndex < CHARSET.length && c == CHARSET[charsetIndex]) {
++charsetIndex;
} else {
charsetIndex = Integer.MAX_VALUE;
}
if (httpEquivIndex < HTTP_EQUIV.length && c == HTTP_EQUIV[httpEquivIndex]) {
++httpEquivIndex;
} else {
httpEquivIndex = Integer.MAX_VALUE;
}
}
continue;
}
}
// FALLTHRU DON'T REORDER
case BEFORE_ATTRIBUTE_VALUE:
beforeattributevalueloop: for (;;) {
c = read();
switch (c) {
case -1:
break stateloop;
case ' ':
case '\t':
case '\n':
case '\u000C':
continue;
case '"':
state = MetaScanner.ATTRIBUTE_VALUE_DOUBLE_QUOTED;
break beforeattributevalueloop;
// continue stateloop;
case '\'':
state = MetaScanner.ATTRIBUTE_VALUE_SINGLE_QUOTED;
continue stateloop;
case '>':
if (handleTag()) {
break stateloop;
}
state = MetaScanner.DATA;
continue stateloop;
default:
handleCharInAttributeValue(c);
state = MetaScanner.ATTRIBUTE_VALUE_UNQUOTED;
continue stateloop;
}
}
// FALLTHRU DON'T REORDER
case ATTRIBUTE_VALUE_DOUBLE_QUOTED:
attributevaluedoublequotedloop: for (;;) {
if (reconsume) {
reconsume = false;
} else {
c = read();
}
switch (c) {
case -1:
break stateloop;
case '"':
handleAttributeValue();
state = MetaScanner.AFTER_ATTRIBUTE_VALUE_QUOTED;
break attributevaluedoublequotedloop;
// continue stateloop;
default:
handleCharInAttributeValue(c);
continue;
}
}
// FALLTHRU DON'T REORDER
case AFTER_ATTRIBUTE_VALUE_QUOTED:
afterattributevaluequotedloop: for (;;) {
c = read();
switch (c) {
case -1:
break stateloop;
case ' ':
case '\t':
case '\n':
case '\u000C':
state = MetaScanner.BEFORE_ATTRIBUTE_NAME;
continue stateloop;
case '/':
state = MetaScanner.SELF_CLOSING_START_TAG;
break afterattributevaluequotedloop;
// continue stateloop;
case '>':
if (handleTag()) {
break stateloop;
}
state = MetaScanner.DATA;
continue stateloop;
default:
state = MetaScanner.BEFORE_ATTRIBUTE_NAME;
reconsume = true;
continue stateloop;
}
}
// FALLTHRU DON'T REORDER
case SELF_CLOSING_START_TAG:
c = read();
switch (c) {
case -1:
break stateloop;
case '>':
if (handleTag()) {
break stateloop;
}
state = MetaScanner.DATA;
continue stateloop;
default:
state = MetaScanner.BEFORE_ATTRIBUTE_NAME;
reconsume = true;
continue stateloop;
}
// XXX reorder point
case ATTRIBUTE_VALUE_UNQUOTED:
for (;;) {
if (reconsume) {
reconsume = false;
} else {
c = read();
}
switch (c) {
case -1:
break stateloop;
case ' ':
case '\t':
case '\n':
case '\u000C':
handleAttributeValue();
state = MetaScanner.BEFORE_ATTRIBUTE_NAME;
continue stateloop;
case '>':
handleAttributeValue();
if (handleTag()) {
break stateloop;
}
state = MetaScanner.DATA;
continue stateloop;
default:
handleCharInAttributeValue(c);
continue;
}
}
// XXX reorder point
case AFTER_ATTRIBUTE_NAME:
for (;;) {
c = read();
switch (c) {
case -1:
break stateloop;
case ' ':
case '\t':
case '\n':
case '\u000C':
continue;
case '/':
handleAttributeValue();
state = MetaScanner.SELF_CLOSING_START_TAG;
continue stateloop;
case '=':
strBufLen = 0;
contentTypeIndex = 0;
state = MetaScanner.BEFORE_ATTRIBUTE_VALUE;
continue stateloop;
case '>':
handleAttributeValue();
if (handleTag()) {
break stateloop;
}
state = MetaScanner.DATA;
continue stateloop;
case 'c':
case 'C':
contentIndex = 0;
charsetIndex = 0;
state = MetaScanner.ATTRIBUTE_NAME;
continue stateloop;
default:
contentIndex = Integer.MAX_VALUE;
charsetIndex = Integer.MAX_VALUE;
state = MetaScanner.ATTRIBUTE_NAME;
continue stateloop;
}
}
// XXX reorder point
case MARKUP_DECLARATION_OPEN:
markupdeclarationopenloop: for (;;) {
c = read();
switch (c) {
case -1:
break stateloop;
case '-':
state = MetaScanner.MARKUP_DECLARATION_HYPHEN;
break markupdeclarationopenloop;
// continue stateloop;
default:
state = MetaScanner.SCAN_UNTIL_GT;
reconsume = true;
continue stateloop;
}
}
// FALLTHRU DON'T REORDER
case MARKUP_DECLARATION_HYPHEN:
markupdeclarationhyphenloop: for (;;) {
c = read();
switch (c) {
case -1:
break stateloop;
case '-':
state = MetaScanner.COMMENT_START;
break markupdeclarationhyphenloop;
// continue stateloop;
default:
state = MetaScanner.SCAN_UNTIL_GT;
reconsume = true;
continue stateloop;
}
}
// FALLTHRU DON'T REORDER
case COMMENT_START:
commentstartloop: for (;;) {
c = read();
switch (c) {
case -1:
break stateloop;
case '-':
state = MetaScanner.COMMENT_START_DASH;
continue stateloop;
case '>':
state = MetaScanner.DATA;
continue stateloop;
default:
state = MetaScanner.COMMENT;
break commentstartloop;
// continue stateloop;
}
}
// FALLTHRU DON'T REORDER
case COMMENT:
commentloop: for (;;) {
c = read();
switch (c) {
case -1:
break stateloop;
case '-':
state = MetaScanner.COMMENT_END_DASH;
break commentloop;
// continue stateloop;
default:
continue;
}
}
// FALLTHRU DON'T REORDER
case COMMENT_END_DASH:
commentenddashloop: for (;;) {
c = read();
switch (c) {
case -1:
break stateloop;
case '-':
state = MetaScanner.COMMENT_END;
break commentenddashloop;
// continue stateloop;
default:
state = MetaScanner.COMMENT;
continue stateloop;
}
}
// FALLTHRU DON'T REORDER
case COMMENT_END:
for (;;) {
c = read();
switch (c) {
case -1:
break stateloop;
case '>':
state = MetaScanner.DATA;
continue stateloop;
case '-':
continue;
default:
state = MetaScanner.COMMENT;
continue stateloop;
}
}
// XXX reorder point
case COMMENT_START_DASH:
c = read();
switch (c) {
case -1:
break stateloop;
case '-':
state = MetaScanner.COMMENT_END;
continue stateloop;
case '>':
state = MetaScanner.DATA;
continue stateloop;
default:
state = MetaScanner.COMMENT;
continue stateloop;
}
// XXX reorder point
case ATTRIBUTE_VALUE_SINGLE_QUOTED:
for (;;) {
if (reconsume) {
reconsume = false;
} else {
c = read();
}
switch (c) {
case -1:
break stateloop;
case '\'':
handleAttributeValue();
state = MetaScanner.AFTER_ATTRIBUTE_VALUE_QUOTED;
continue stateloop;
default:
handleCharInAttributeValue(c);
continue;
}
}
// XXX reorder point
case SCAN_UNTIL_GT:
for (;;) {
if (reconsume) {
reconsume = false;
} else {
c = read();
}
switch (c) {
case -1:
break stateloop;
case '>':
state = MetaScanner.DATA;
continue stateloop;
default:
continue;
}
}
}
}
stateSave = state;
}
private void handleCharInAttributeValue(int c) {
if (metaState == A) {
if (contentIndex == CONTENT.length || charsetIndex == CHARSET.length) {
addToBuffer(c);
} else if (httpEquivIndex == HTTP_EQUIV.length) {
if (contentTypeIndex < CONTENT_TYPE.length && toAsciiLowerCase(c) == CONTENT_TYPE[contentTypeIndex]) {
++contentTypeIndex;
} else {
contentTypeIndex = Integer.MAX_VALUE;
}
}
}
}
@Inline private int toAsciiLowerCase(int c) {
if (c >= 'A' && c <= 'Z') {
return c + 0x20;
}
return c;
}
/**
* Adds a character to the accumulation buffer.
* @param c the character to add
*/
private void addToBuffer(int c) {
if (strBufLen == strBuf.length) {
char[] newBuf = new char[strBuf.length + (strBuf.length << 1)];
System.arraycopy(strBuf, 0, newBuf, 0, strBuf.length);
strBuf = newBuf;
}
strBuf[strBufLen++] = (char)c;
}
/**
* Attempts to extract a charset name from the accumulation buffer.
* @return <code>true</code> if successful
* @throws SAXException
*/
private void handleAttributeValue() throws SAXException {
if (metaState != A) {
return;
}
if (contentIndex == CONTENT.length && content == null) {
content = Portability.newStringFromBuffer(strBuf, 0, strBufLen
// CPPONLY: , treeBuilder
);
return;
}
if (charsetIndex == CHARSET.length && charset == null) {
charset = Portability.newStringFromBuffer(strBuf, 0, strBufLen
// CPPONLY: , treeBuilder
);
return;
}
if (httpEquivIndex == HTTP_EQUIV.length
&& httpEquivState == HTTP_EQUIV_NOT_SEEN) {
httpEquivState = (contentTypeIndex == CONTENT_TYPE.length) ? HTTP_EQUIV_CONTENT_TYPE
: HTTP_EQUIV_OTHER;
return;
}
}
private boolean handleTag() throws SAXException {
boolean stop = handleTagInner();
Portability.releaseString(content);
content = null;
Portability.releaseString(charset);
charset = null;
httpEquivState = HTTP_EQUIV_NOT_SEEN;
return stop;
}
private boolean handleTagInner() throws SAXException {
if (charset != null && tryCharset(charset)) {
return true;
}
if (content != null && httpEquivState == HTTP_EQUIV_CONTENT_TYPE) {
String extract = TreeBuilder.extractCharsetFromContent(content
// CPPONLY: , treeBuilder
);
if (extract == null) {
return false;
}
boolean success = tryCharset(extract);
Portability.releaseString(extract);
return success;
}
return false;
}
/**
* Tries to switch to an encoding.
*
* @param encoding
* @return <code>true</code> if successful
* @throws SAXException
*/
protected abstract boolean tryCharset(String encoding) throws SAXException;
}

View file

@ -1,150 +0,0 @@
/*
* Copyright (c) 2008-2015 Mozilla Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
package nu.validator.htmlparser.impl;
import nu.validator.htmlparser.annotation.Literal;
import nu.validator.htmlparser.annotation.Local;
import nu.validator.htmlparser.annotation.NoLength;
import nu.validator.htmlparser.common.Interner;
public final class Portability {
// Allocating methods
/**
* Allocates a new local name object. In C++, the refcount must be set up in such a way that
* calling <code>releaseLocal</code> on the return value balances the refcount set by this method.
*/
public static @Local String newLocalNameFromBuffer(@NoLength char[] buf, int offset, int length, Interner interner) {
return new String(buf, offset, length).intern();
}
public static String newStringFromBuffer(@NoLength char[] buf, int offset, int length
// CPPONLY: , TreeBuilder treeBuilder
) {
return new String(buf, offset, length);
}
public static String newEmptyString() {
return "";
}
public static String newStringFromLiteral(@Literal String literal) {
return literal;
}
public static String newStringFromString(String string) {
return string;
}
// XXX get rid of this
public static char[] newCharArrayFromLocal(@Local String local) {
return local.toCharArray();
}
public static char[] newCharArrayFromString(String string) {
return string.toCharArray();
}
public static @Local String newLocalFromLocal(@Local String local, Interner interner) {
return local;
}
// Deallocation methods
public static void releaseString(String str) {
// No-op in Java
}
// Comparison methods
public static boolean localEqualsBuffer(@Local String local, @NoLength char[] buf, int offset, int length) {
if (local.length() != length) {
return false;
}
for (int i = 0; i < length; i++) {
if (local.charAt(i) != buf[offset + i]) {
return false;
}
}
return true;
}
public static boolean lowerCaseLiteralIsPrefixOfIgnoreAsciiCaseString(@Literal String lowerCaseLiteral,
String string) {
if (string == null) {
return false;
}
if (lowerCaseLiteral.length() > string.length()) {
return false;
}
for (int i = 0; i < lowerCaseLiteral.length(); i++) {
char c0 = lowerCaseLiteral.charAt(i);
char c1 = string.charAt(i);
if (c1 >= 'A' && c1 <= 'Z') {
c1 += 0x20;
}
if (c0 != c1) {
return false;
}
}
return true;
}
public static boolean lowerCaseLiteralEqualsIgnoreAsciiCaseString(@Literal String lowerCaseLiteral,
String string) {
if (string == null) {
return false;
}
if (lowerCaseLiteral.length() != string.length()) {
return false;
}
for (int i = 0; i < lowerCaseLiteral.length(); i++) {
char c0 = lowerCaseLiteral.charAt(i);
char c1 = string.charAt(i);
if (c1 >= 'A' && c1 <= 'Z') {
c1 += 0x20;
}
if (c0 != c1) {
return false;
}
}
return true;
}
public static boolean literalEqualsString(@Literal String literal, String string) {
return literal.equals(string);
}
public static boolean stringEqualsString(String one, String other) {
return one.equals(other);
}
public static void delete(Object o) {
}
public static void deleteArray(Object o) {
}
}

View file

@ -1,6 +0,0 @@
The .java files in this directory were placed here by the Java-to-C++
translator that lives in parser/html/java/translator. Together they represent
a snapshot of the Java code that was translated to produce the corresponding
.h and .cpp files in the parent directory. Changing these .java files is not
worthwhile, as they will just be overwritten by the next translation. See
parser/html/java/README.txt for information about performing the translation.

View file

@ -1,322 +0,0 @@
/*
* Copyright (c) 2007 Henri Sivonen
* Copyright (c) 2007-2011 Mozilla Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
package nu.validator.htmlparser.impl;
import nu.validator.htmlparser.annotation.Inline;
import nu.validator.htmlparser.annotation.Local;
import nu.validator.htmlparser.annotation.NsUri;
final class StackNode<T> {
// Index where this stack node is stored in the tree builder's list of stack nodes.
// A value of -1 indicates that the stack node is not owned by a tree builder and
// must delete itself when its refcount reaches 0.
final int idxInTreeBuilder;
int flags;
@Local String name;
@Local String popName;
@NsUri String ns;
T node;
// Only used on the list of formatting elements
HtmlAttributes attributes;
private int refcount = 0;
// [NOCPP[
private TaintableLocatorImpl locator;
public TaintableLocatorImpl getLocator() {
return locator;
}
// ]NOCPP]
@Inline public int getFlags() {
return flags;
}
public int getGroup() {
return flags & ElementName.GROUP_MASK;
}
public boolean isScoping() {
return (flags & ElementName.SCOPING) != 0;
}
public boolean isSpecial() {
return (flags & ElementName.SPECIAL) != 0;
}
public boolean isFosterParenting() {
return (flags & ElementName.FOSTER_PARENTING) != 0;
}
public boolean isHtmlIntegrationPoint() {
return (flags & ElementName.HTML_INTEGRATION_POINT) != 0;
}
// [NOCPP[
public boolean isOptionalEndTag() {
return (flags & ElementName.OPTIONAL_END_TAG) != 0;
}
// ]NOCPP]
StackNode(int idxInTreeBuilder) {
this.idxInTreeBuilder = idxInTreeBuilder;
this.refcount = 0;
}
/**
* Setter for copying. This doesn't take another <code>StackNode</code>
* because in C++ the caller is responsible for reobtaining the local names
* from another interner.
*
* @param flags
* @param ns
* @param name
* @param node
* @param popName
* @param attributes
*/
void setValues(int flags, @NsUri String ns, @Local String name, T node,
@Local String popName, HtmlAttributes attributes
// [NOCPP[
, TaintableLocatorImpl locator
// ]NOCPP]
) {
assert isUnused();
this.flags = flags;
this.name = name;
this.popName = popName;
this.ns = ns;
this.node = node;
this.attributes = attributes;
this.refcount = 1;
// [NOCPP[
this.locator = locator;
// ]NOCPP]
}
/**
* Short hand for well-known HTML elements.
*
* @param elementName
* @param node
*/
void setValues(ElementName elementName, T node
// [NOCPP[
, TaintableLocatorImpl locator
// ]NOCPP]
) {
assert isUnused();
this.flags = elementName.getFlags();
this.name = elementName.name;
this.popName = elementName.name;
this.ns = "http://www.w3.org/1999/xhtml";
this.node = node;
this.attributes = null;
this.refcount = 1;
assert !elementName.isCustom() : "Don't use this constructor for custom elements.";
// [NOCPP[
this.locator = locator;
// ]NOCPP]
}
/**
* Setter for HTML formatting elements.
*
* @param elementName
* @param node
* @param attributes
*/
void setValues(ElementName elementName, T node, HtmlAttributes attributes
// [NOCPP[
, TaintableLocatorImpl locator
// ]NOCPP]
) {
assert isUnused();
this.flags = elementName.getFlags();
this.name = elementName.name;
this.popName = elementName.name;
this.ns = "http://www.w3.org/1999/xhtml";
this.node = node;
this.attributes = attributes;
this.refcount = 1;
assert !elementName.isCustom() : "Don't use this constructor for custom elements.";
// [NOCPP[
this.locator = locator;
// ]NOCPP]
}
/**
* The common-case HTML setter.
*
* @param elementName
* @param node
* @param popName
*/
void setValues(ElementName elementName, T node, @Local String popName
// [NOCPP[
, TaintableLocatorImpl locator
// ]NOCPP]
) {
assert isUnused();
this.flags = elementName.getFlags();
this.name = elementName.name;
this.popName = popName;
this.ns = "http://www.w3.org/1999/xhtml";
this.node = node;
this.attributes = null;
this.refcount = 1;
// [NOCPP[
this.locator = locator;
// ]NOCPP]
}
/**
* Setter for SVG elements. Note that the order of the arguments is
* what distinguishes this from the HTML setter. This is ugly, but
* AFAICT the least disruptive way to make this work with Java's generics
* and without unnecessary branches. :-(
*
* @param elementName
* @param popName
* @param node
*/
void setValues(ElementName elementName, @Local String popName, T node
// [NOCPP[
, TaintableLocatorImpl locator
// ]NOCPP]
) {
assert isUnused();
this.flags = prepareSvgFlags(elementName.getFlags());
this.name = elementName.name;
this.popName = popName;
this.ns = "http://www.w3.org/2000/svg";
this.node = node;
this.attributes = null;
this.refcount = 1;
// [NOCPP[
this.locator = locator;
// ]NOCPP]
}
/**
* Setter for MathML.
*
* @param elementName
* @param node
* @param popName
* @param markAsIntegrationPoint
*/
void setValues(ElementName elementName, T node, @Local String popName,
boolean markAsIntegrationPoint
// [NOCPP[
, TaintableLocatorImpl locator
// ]NOCPP]
) {
assert isUnused();
this.flags = prepareMathFlags(elementName.getFlags(),
markAsIntegrationPoint);
this.name = elementName.name;
this.popName = popName;
this.ns = "http://www.w3.org/1998/Math/MathML";
this.node = node;
this.attributes = null;
this.refcount = 1;
// [NOCPP[
this.locator = locator;
// ]NOCPP]
}
private static int prepareSvgFlags(int flags) {
flags &= ~(ElementName.FOSTER_PARENTING | ElementName.SCOPING
| ElementName.SPECIAL | ElementName.OPTIONAL_END_TAG);
if ((flags & ElementName.SCOPING_AS_SVG) != 0) {
flags |= (ElementName.SCOPING | ElementName.SPECIAL | ElementName.HTML_INTEGRATION_POINT);
}
return flags;
}
private static int prepareMathFlags(int flags,
boolean markAsIntegrationPoint) {
flags &= ~(ElementName.FOSTER_PARENTING | ElementName.SCOPING
| ElementName.SPECIAL | ElementName.OPTIONAL_END_TAG);
if ((flags & ElementName.SCOPING_AS_MATHML) != 0) {
flags |= (ElementName.SCOPING | ElementName.SPECIAL);
}
if (markAsIntegrationPoint) {
flags |= ElementName.HTML_INTEGRATION_POINT;
}
return flags;
}
@SuppressWarnings("unused") private void destructor() {
// The translator adds refcount debug code here.
}
public void dropAttributes() {
attributes = null;
}
// [NOCPP[
/**
* @see java.lang.Object#toString()
*/
@Override public @Local String toString() {
return name;
}
// ]NOCPP]
public void retain() {
refcount++;
}
public void release(TreeBuilder<T> owningTreeBuilder) {
refcount--;
assert refcount >= 0;
if (refcount == 0) {
Portability.delete(attributes);
if (idxInTreeBuilder >= 0) {
owningTreeBuilder.notifyUnusedStackNode(idxInTreeBuilder);
} else {
assert owningTreeBuilder == null;
Portability.delete(this);
}
}
}
boolean isUnused() {
return refcount == 0;
}
}

View file

@ -1,204 +0,0 @@
/*
* Copyright (c) 2009-2010 Mozilla Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
package nu.validator.htmlparser.impl;
import nu.validator.htmlparser.annotation.Auto;
public class StateSnapshot<T> implements TreeBuilderState<T> {
private final @Auto StackNode<T>[] stack;
private final @Auto StackNode<T>[] listOfActiveFormattingElements;
private final @Auto int[] templateModeStack;
private final T formPointer;
private final T headPointer;
private final T deepTreeSurrogateParent;
private final int mode;
private final int originalMode;
private final boolean framesetOk;
private final boolean needToDropLF;
private final boolean quirks;
/**
* @param stack
* @param listOfActiveFormattingElements
* @param templateModeStack
* @param formPointer
* @param headPointer
* @param deepTreeSurrogateParent
* @param mode
* @param originalMode
* @param framesetOk
* @param needToDropLF
* @param quirks
*/
StateSnapshot(StackNode<T>[] stack,
StackNode<T>[] listOfActiveFormattingElements, int[] templateModeStack, T formPointer,
T headPointer, T deepTreeSurrogateParent, int mode, int originalMode,
boolean framesetOk, boolean needToDropLF, boolean quirks) {
this.stack = stack;
this.listOfActiveFormattingElements = listOfActiveFormattingElements;
this.templateModeStack = templateModeStack;
this.formPointer = formPointer;
this.headPointer = headPointer;
this.deepTreeSurrogateParent = deepTreeSurrogateParent;
this.mode = mode;
this.originalMode = originalMode;
this.framesetOk = framesetOk;
this.needToDropLF = needToDropLF;
this.quirks = quirks;
}
/**
* @see nu.validator.htmlparser.impl.TreeBuilderState#getStack()
*/
public StackNode<T>[] getStack() {
return stack;
}
/**
* @see nu.validator.htmlparser.impl.TreeBuilderState#getTemplateModeStack()
*/
public int[] getTemplateModeStack() {
return templateModeStack;
}
/**
* @see nu.validator.htmlparser.impl.TreeBuilderState#getListOfActiveFormattingElements()
*/
public StackNode<T>[] getListOfActiveFormattingElements() {
return listOfActiveFormattingElements;
}
/**
* @see nu.validator.htmlparser.impl.TreeBuilderState#getFormPointer()
*/
public T getFormPointer() {
return formPointer;
}
/**
* Returns the headPointer.
*
* @return the headPointer
*/
public T getHeadPointer() {
return headPointer;
}
/**
* Returns the deepTreeSurrogateParent.
*
* @return the deepTreeSurrogateParent
*/
public T getDeepTreeSurrogateParent() {
return deepTreeSurrogateParent;
}
/**
* Returns the mode.
*
* @return the mode
*/
public int getMode() {
return mode;
}
/**
* Returns the originalMode.
*
* @return the originalMode
*/
public int getOriginalMode() {
return originalMode;
}
/**
* Returns the framesetOk.
*
* @return the framesetOk
*/
public boolean isFramesetOk() {
return framesetOk;
}
/**
* Returns the needToDropLF.
*
* @return the needToDropLF
*/
public boolean isNeedToDropLF() {
return needToDropLF;
}
/**
* Returns the quirks.
*
* @return the quirks
*/
public boolean isQuirks() {
return quirks;
}
/**
* @see nu.validator.htmlparser.impl.TreeBuilderState#getListOfActiveFormattingElementsLength()
*/
public int getListOfActiveFormattingElementsLength() {
return listOfActiveFormattingElements.length;
}
/**
* @see nu.validator.htmlparser.impl.TreeBuilderState#getStackLength()
*/
public int getStackLength() {
return stack.length;
}
/**
* @see nu.validator.htmlparser.impl.TreeBuilderState#getTemplateModeStackLength()
*/
public int getTemplateModeStackLength() {
return templateModeStack.length;
}
@SuppressWarnings("unused") private void destructor() {
for (int i = 0; i < stack.length; i++) {
stack[i].release(null);
}
for (int i = 0; i < listOfActiveFormattingElements.length; i++) {
if (listOfActiveFormattingElements[i] != null) {
listOfActiveFormattingElements[i].release(null);
}
}
}
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,151 +0,0 @@
/*
* Copyright (c) 2008-2010 Mozilla Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
package nu.validator.htmlparser.impl;
import nu.validator.htmlparser.annotation.NoLength;
/**
* An UTF-16 buffer that knows the start and end indeces of its unconsumed
* content.
*
* @version $Id$
* @author hsivonen
*/
public final class UTF16Buffer {
/**
* The backing store of the buffer. May be larger than the logical content
* of this <code>UTF16Buffer</code>.
*/
private final @NoLength char[] buffer;
/**
* The index of the first unconsumed character in the backing buffer.
*/
private int start;
/**
* The index of the slot immediately after the last character in the backing
* buffer that is part of the logical content of this
* <code>UTF16Buffer</code>.
*/
private int end;
//[NOCPP[
/**
* Constructor for wrapping an existing UTF-16 code unit array.
*
* @param buffer
* the backing buffer
* @param start
* the index of the first character to consume
* @param end
* the index immediately after the last character to consume
*/
public UTF16Buffer(@NoLength char[] buffer, int start, int end) {
this.buffer = buffer;
this.start = start;
this.end = end;
}
// ]NOCPP]
/**
* Returns the start index.
*
* @return the start index
*/
public int getStart() {
return start;
}
/**
* Sets the start index.
*
* @param start
* the start index
*/
public void setStart(int start) {
this.start = start;
}
/**
* Returns the backing buffer.
*
* @return the backing buffer
*/
public @NoLength char[] getBuffer() {
return buffer;
}
/**
* Returns the end index.
*
* @return the end index
*/
public int getEnd() {
return end;
}
/**
* Checks if the buffer has data left.
*
* @return <code>true</code> if there's data left
*/
public boolean hasMore() {
return start < end;
}
/**
* Returns <code>end - start</code>.
*
* @return <code>end - start</code>
*/
public int getLength() {
return end - start;
}
/**
* Adjusts the start index to skip over the first character if it is a line
* feed and the previous character was a carriage return.
*
* @param lastWasCR
* whether the previous character was a carriage return
*/
public void adjust(boolean lastWasCR) {
if (lastWasCR && buffer[start] == '\n') {
start++;
}
}
/**
* Sets the end index.
*
* @param end
* the end index
*/
public void setEnd(int end) {
this.end = end;
}
}

View file

@ -1,5 +1,6 @@
/*
* Copyright (c) 2008 Mozilla Foundation
* Copyright (c) 2019 Moonchild Productions
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),

View file

@ -1,5 +1,6 @@
/*
* Copyright (c) 2008-2011 Mozilla Foundation
* Copyright (c) 2019 Moonchild Productions
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@ -20,11 +21,6 @@
* DEALINGS IN THE SOFTWARE.
*/
/*
* THIS IS A GENERATED FILE. PLEASE DO NOT EDIT.
* Please edit AttributeName.java instead and regenerate.
*/
#define nsHtml5AttributeName_cpp__
#include "nsIAtom.h"

View file

@ -1,5 +1,6 @@
/*
* Copyright (c) 2008-2011 Mozilla Foundation
* Copyright (c) 2019 Moonchild Productions
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@ -20,11 +21,6 @@
* DEALINGS IN THE SOFTWARE.
*/
/*
* THIS IS A GENERATED FILE. PLEASE DO NOT EDIT.
* Please edit AttributeName.java instead and regenerate.
*/
#ifndef nsHtml5AttributeName_h
#define nsHtml5AttributeName_h

View file

@ -1,5 +1,6 @@
/*
* Copyright (c) 2008-2014 Mozilla Foundation
* Copyright (c) 2019 Moonchild Productions
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@ -20,11 +21,6 @@
* DEALINGS IN THE SOFTWARE.
*/
/*
* THIS IS A GENERATED FILE. PLEASE DO NOT EDIT.
* Please edit ElementName.java instead and regenerate.
*/
#define nsHtml5ElementName_cpp__
#include "nsIAtom.h"

View file

@ -1,5 +1,6 @@
/*
* Copyright (c) 2008-2014 Mozilla Foundation
* Copyright (c) 2019 Moonchild Productions
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@ -20,11 +21,6 @@
* DEALINGS IN THE SOFTWARE.
*/
/*
* THIS IS A GENERATED FILE. PLEASE DO NOT EDIT.
* Please edit ElementName.java instead and regenerate.
*/
#ifndef nsHtml5ElementName_h
#define nsHtml5ElementName_h

View file

@ -1,6 +1,7 @@
/*
* Copyright (c) 2007 Henri Sivonen
* Copyright (c) 2008-2011 Mozilla Foundation
* Copyright (c) 2019 Moonchild Productions
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@ -21,11 +22,6 @@
* DEALINGS IN THE SOFTWARE.
*/
/*
* THIS IS A GENERATED FILE. PLEASE DO NOT EDIT.
* Please edit HtmlAttributes.java instead and regenerate.
*/
#define nsHtml5HtmlAttributes_cpp__
#include "nsIAtom.h"

View file

@ -1,6 +1,7 @@
/*
* Copyright (c) 2007 Henri Sivonen
* Copyright (c) 2008-2011 Mozilla Foundation
* Copyright (c) 2019 Moonchild Productions
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@ -21,11 +22,6 @@
* DEALINGS IN THE SOFTWARE.
*/
/*
* THIS IS A GENERATED FILE. PLEASE DO NOT EDIT.
* Please edit HtmlAttributes.java instead and regenerate.
*/
#ifndef nsHtml5HtmlAttributes_h
#define nsHtml5HtmlAttributes_h

View file

@ -1,6 +1,7 @@
/*
* Copyright (c) 2007 Henri Sivonen
* Copyright (c) 2008-2015 Mozilla Foundation
* Copyright (c) 2019 Moonchild Productions
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@ -21,11 +22,6 @@
* DEALINGS IN THE SOFTWARE.
*/
/*
* THIS IS A GENERATED FILE. PLEASE DO NOT EDIT.
* Please edit MetaScanner.java instead and regenerate.
*/
#define nsHtml5MetaScanner_cpp__
#include "nsIAtom.h"

View file

@ -1,6 +1,7 @@
/*
* Copyright (c) 2007 Henri Sivonen
* Copyright (c) 2008-2015 Mozilla Foundation
* Copyright (c) 2019 Moonchild Productions
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@ -21,11 +22,6 @@
* DEALINGS IN THE SOFTWARE.
*/
/*
* THIS IS A GENERATED FILE. PLEASE DO NOT EDIT.
* Please edit MetaScanner.java instead and regenerate.
*/
#ifndef nsHtml5MetaScanner_h
#define nsHtml5MetaScanner_h

View file

@ -1,5 +1,6 @@
/*
* Copyright (c) 2008-2015 Mozilla Foundation
* Copyright (c) 2019 Moonchild Productions
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@ -20,11 +21,6 @@
* DEALINGS IN THE SOFTWARE.
*/
/*
* THIS IS A GENERATED FILE. PLEASE DO NOT EDIT.
* Please edit Portability.java instead and regenerate.
*/
#ifndef nsHtml5Portability_h
#define nsHtml5Portability_h

View file

@ -1,6 +1,7 @@
/*
* Copyright (c) 2007 Henri Sivonen
* Copyright (c) 2007-2011 Mozilla Foundation
* Copyright (c) 2019 Moonchild Productions
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@ -21,11 +22,6 @@
* DEALINGS IN THE SOFTWARE.
*/
/*
* THIS IS A GENERATED FILE. PLEASE DO NOT EDIT.
* Please edit StackNode.java instead and regenerate.
*/
#define nsHtml5StackNode_cpp__
#include "nsIAtom.h"

View file

@ -1,6 +1,7 @@
/*
* Copyright (c) 2007 Henri Sivonen
* Copyright (c) 2007-2011 Mozilla Foundation
* Copyright (c) 2019 Moonchild Productions
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@ -21,11 +22,6 @@
* DEALINGS IN THE SOFTWARE.
*/
/*
* THIS IS A GENERATED FILE. PLEASE DO NOT EDIT.
* Please edit StackNode.java instead and regenerate.
*/
#ifndef nsHtml5StackNode_h
#define nsHtml5StackNode_h

View file

@ -1,5 +1,6 @@
/*
* Copyright (c) 2009-2010 Mozilla Foundation
* Copyright (c) 2019 Moonchild Productions
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@ -20,11 +21,6 @@
* DEALINGS IN THE SOFTWARE.
*/
/*
* THIS IS A GENERATED FILE. PLEASE DO NOT EDIT.
* Please edit StateSnapshot.java instead and regenerate.
*/
#define nsHtml5StateSnapshot_cpp__
#include "nsIAtom.h"

View file

@ -1,5 +1,6 @@
/*
* Copyright (c) 2009-2010 Mozilla Foundation
* Copyright (c) 2019 Moonchild Productions
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@ -20,11 +21,6 @@
* DEALINGS IN THE SOFTWARE.
*/
/*
* THIS IS A GENERATED FILE. PLEASE DO NOT EDIT.
* Please edit StateSnapshot.java instead and regenerate.
*/
#ifndef nsHtml5StateSnapshot_h
#define nsHtml5StateSnapshot_h

View file

@ -1,6 +1,7 @@
/*
* Copyright (c) 2005-2007 Henri Sivonen
* Copyright (c) 2007-2015 Mozilla Foundation
* Copyright (c) 2019 Moonchild Productions
* Portions of comments Copyright 2004-2010 Apple Computer, Inc., Mozilla
* Foundation, and Opera Software ASA.
*
@ -23,11 +24,6 @@
* DEALINGS IN THE SOFTWARE.
*/
/*
* THIS IS A GENERATED FILE. PLEASE DO NOT EDIT.
* Please edit Tokenizer.java instead and regenerate.
*/
#define nsHtml5Tokenizer_cpp__
#include "nsIAtom.h"
@ -127,15 +123,11 @@ nsHtml5Tokenizer::isViewingXmlSource()
}
void
nsHtml5Tokenizer::setStateAndEndTagExpectation(int32_t specialTokenizerState, nsIAtom* endTagExpectation)
nsHtml5Tokenizer::setState(int32_t specialTokenizerState)
{
this->stateSave = specialTokenizerState;
if (specialTokenizerState == NS_HTML5TOKENIZER_DATA) {
return;
}
autoJArray<char16_t,int32_t> asArray = nsHtml5Portability::newCharArrayFromLocal(endTagExpectation);
this->endTagExpectation = nsHtml5ElementName::elementNameByBuffer(asArray, 0, asArray.length, interner);
endTagExpectationToArray();
this->endTagExpectation = nullptr;
this->endTagExpectationAsArray = nullptr;
}
void
@ -2040,7 +2032,13 @@ nsHtml5Tokenizer::stateLoop(int32_t state, char16_t c, int32_t pos, char16_t* bu
NS_HTML5_BREAK(stateloop);
}
c = checkChar(buf, pos);
if (index < endTagExpectationAsArray.length) {
if (!endTagExpectationAsArray) {
tokenHandler->characters(nsHtml5Tokenizer::LT_SOLIDUS, 0, 2);
cstart = pos;
reconsume = true;
state = P::transition(mViewSource, returnState, reconsume, pos);
NS_HTML5_CONTINUE(stateloop);
} else if (index < endTagExpectationAsArray.length) {
char16_t e = endTagExpectationAsArray[index];
char16_t folded = c;
if (c >= 'A' && c <= 'Z') {

View file

@ -1,6 +1,7 @@
/*
* Copyright (c) 2005-2007 Henri Sivonen
* Copyright (c) 2007-2015 Mozilla Foundation
* Copyright (c) 2019 Moonchild Productions
* Portions of comments Copyright 2004-2010 Apple Computer, Inc., Mozilla
* Foundation, and Opera Software ASA.
*
@ -23,11 +24,6 @@
* DEALINGS IN THE SOFTWARE.
*/
/*
* THIS IS A GENERATED FILE. PLEASE DO NOT EDIT.
* Please edit Tokenizer.java instead and regenerate.
*/
#ifndef nsHtml5Tokenizer_h
#define nsHtml5Tokenizer_h
@ -143,7 +139,7 @@ class nsHtml5Tokenizer
void setInterner(nsHtml5AtomTable* interner);
void initLocation(nsHtml5String newPublicId, nsHtml5String newSystemId);
bool isViewingXmlSource();
void setStateAndEndTagExpectation(int32_t specialTokenizerState, nsIAtom* endTagExpectation);
void setState(int32_t specialTokenizerState);
void setStateAndEndTagExpectation(int32_t specialTokenizerState, nsHtml5ElementName* endTagExpectation);
private:
void endTagExpectationToArray();

View file

@ -1,6 +1,7 @@
/*
* Copyright (c) 2007 Henri Sivonen
* Copyright (c) 2007-2015 Mozilla Foundation
* Copyright (c) 2019 Moonchild Productions
* Portions of comments Copyright 2004-2008 Apple Computer, Inc., Mozilla
* Foundation, and Opera Software ASA.
*
@ -23,11 +24,6 @@
* DEALINGS IN THE SOFTWARE.
*/
/*
* THIS IS A GENERATED FILE. PLEASE DO NOT EDIT.
* Please edit TreeBuilder.java instead and regenerate.
*/
#define nsHtml5TreeBuilder_cpp__
#include "nsContentUtils.h"
@ -108,7 +104,7 @@ nsHtml5TreeBuilder::startTokenization(nsHtml5Tokenizer* self)
nsHtml5StackNode* node = createStackNode(elementName, elementName->camelCaseName, elt);
currentPtr++;
stack[currentPtr] = node;
tokenizer->setStateAndEndTagExpectation(NS_HTML5TOKENIZER_DATA, contextName);
tokenizer->setState(NS_HTML5TOKENIZER_DATA);
mode = NS_HTML5TREE_BUILDER_FRAMESET_OK;
} else if (contextNamespace == kNameSpaceID_MathML) {
nsHtml5ElementName* elementName = nsHtml5ElementName::ELT_MATH;
@ -120,7 +116,7 @@ nsHtml5TreeBuilder::startTokenization(nsHtml5Tokenizer* self)
nsHtml5StackNode* node = createStackNode(elementName, elt, elementName->name, false);
currentPtr++;
stack[currentPtr] = node;
tokenizer->setStateAndEndTagExpectation(NS_HTML5TOKENIZER_DATA, contextName);
tokenizer->setState(NS_HTML5TOKENIZER_DATA);
mode = NS_HTML5TREE_BUILDER_FRAMESET_OK;
} else {
nsHtml5StackNode* node = createStackNode(nsHtml5ElementName::ELT_HTML, elt);
@ -132,15 +128,20 @@ nsHtml5TreeBuilder::startTokenization(nsHtml5Tokenizer* self)
resetTheInsertionMode();
formPointer = getFormPointerForContext(contextNode);
if (nsHtml5Atoms::title == contextName || nsHtml5Atoms::textarea == contextName) {
tokenizer->setStateAndEndTagExpectation(NS_HTML5TOKENIZER_RCDATA, contextName);
} else if (nsHtml5Atoms::style == contextName || nsHtml5Atoms::xmp == contextName || nsHtml5Atoms::iframe == contextName || nsHtml5Atoms::noembed == contextName || nsHtml5Atoms::noframes == contextName || (scriptingEnabled && nsHtml5Atoms::noscript == contextName)) {
tokenizer->setStateAndEndTagExpectation(NS_HTML5TOKENIZER_RAWTEXT, contextName);
tokenizer->setState(NS_HTML5TOKENIZER_RCDATA);
} else if (nsHtml5Atoms::style == contextName ||
nsHtml5Atoms::xmp == contextName ||
nsHtml5Atoms::iframe == contextName ||
nsHtml5Atoms::noembed == contextName ||
nsHtml5Atoms::noframes == contextName ||
(scriptingEnabled && nsHtml5Atoms::noscript == contextName)) {
tokenizer->setState(NS_HTML5TOKENIZER_RAWTEXT);
} else if (nsHtml5Atoms::plaintext == contextName) {
tokenizer->setStateAndEndTagExpectation(NS_HTML5TOKENIZER_PLAINTEXT, contextName);
tokenizer->setState(NS_HTML5TOKENIZER_PLAINTEXT);
} else if (nsHtml5Atoms::script == contextName) {
tokenizer->setStateAndEndTagExpectation(NS_HTML5TOKENIZER_SCRIPT_DATA, contextName);
tokenizer->setState(NS_HTML5TOKENIZER_SCRIPT_DATA);
} else {
tokenizer->setStateAndEndTagExpectation(NS_HTML5TOKENIZER_DATA, contextName);
tokenizer->setState(NS_HTML5TOKENIZER_DATA);
}
}
contextName = nullptr;

View file

@ -1,6 +1,7 @@
/*
* Copyright (c) 2007 Henri Sivonen
* Copyright (c) 2007-2015 Mozilla Foundation
* Copyright (c) 2019 Moonchild Productions
* Portions of comments Copyright 2004-2008 Apple Computer, Inc., Mozilla
* Foundation, and Opera Software ASA.
*
@ -23,11 +24,6 @@
* DEALINGS IN THE SOFTWARE.
*/
/*
* THIS IS A GENERATED FILE. PLEASE DO NOT EDIT.
* Please edit TreeBuilder.java instead and regenerate.
*/
#ifndef nsHtml5TreeBuilder_h
#define nsHtml5TreeBuilder_h

View file

@ -1,5 +1,6 @@
/*
* Copyright (c) 2008-2010 Mozilla Foundation
* Copyright (c) 2019 Moonchild Productions
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@ -20,11 +21,6 @@
* DEALINGS IN THE SOFTWARE.
*/
/*
* THIS IS A GENERATED FILE. PLEASE DO NOT EDIT.
* Please edit UTF16Buffer.java instead and regenerate.
*/
#define nsHtml5UTF16Buffer_cpp__
#include "nsIAtom.h"

View file

@ -1,5 +1,6 @@
/*
* Copyright (c) 2008-2010 Mozilla Foundation
* Copyright (c) 2019 Moonchild Productions
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@ -20,11 +21,6 @@
* DEALINGS IN THE SOFTWARE.
*/
/*
* THIS IS A GENERATED FILE. PLEASE DO NOT EDIT.
* Please edit UTF16Buffer.java instead and regenerate.
*/
#ifndef nsHtml5UTF16Buffer_h
#define nsHtml5UTF16Buffer_h

View file

@ -23,7 +23,7 @@ namespace mozilla
[ref] native nsCStringTArrayRef(nsTArray<nsCString>);
[ref] native mozillaPkixTime(mozilla::pkix::Time);
[scriptable, uuid(275127f8-dbd7-4681-afbf-6df0c6587a01)]
[scriptable, uuid(233908bd-6741-4474-a6e1-f298c6ce9eaf)]
interface nsISiteSecurityService : nsISupports
{
const uint32_t HEADER_HSTS = 0;
@ -98,15 +98,21 @@ interface nsISiteSecurityService : nsISupports
* Given a header type, removes state relating to that header of a host,
* including the includeSubdomains state that would affect subdomains.
* This essentially removes the state for the domain tree rooted at this
* host.
* host. If any preloaded information is present for that host, that
* information will then be used instead of any other previously existing
* state, unless the force parameter is set.
*
* @param aType the type of security state in question
* @param aURI the URI of the target host
* @param aFlags options for this request as defined in nsISocketProvider:
* NO_PERMANENT_STORAGE
* @param force if set, forces no-HSTS state by writing a knockout value,
* overriding any preload list state
*/
void removeState(in uint32_t aType,
in nsIURI aURI,
in uint32_t aFlags);
in uint32_t aFlags,
[optional] in boolean force);
/**
* See isSecureURI

View file

@ -330,21 +330,22 @@ nsSiteSecurityService::SetHSTSState(uint32_t aType,
uint32_t flags,
SecurityPropertyState aHSTSState)
{
// If max-age is zero, that's an indication to immediately remove the
// security state, so here's a shortcut.
if (!maxage) {
return RemoveState(aType, aSourceURI, flags);
// Exit early if STS not enabled
if (!mUseStsService) {
return NS_OK;
}
// If max-age is zero, the host is no longer considered HSTS. If the host was
// preloaded, we store an entry indicating that this host is not HSTS, causing
// the preloaded information to be ignored.
if (maxage == 0) {
return RemoveState(aType, aSourceURI, flags, true);
}
MOZ_ASSERT((aHSTSState == SecurityPropertySet ||
aHSTSState == SecurityPropertyNegative),
"HSTS State must be SecurityPropertySet or SecurityPropertyNegative");
// Exit early if STS not enabled
if (!mUseStsService) {
return NS_OK;
}
int64_t expiretime = ExpireTimeFromMaxAge(maxage);
SiteHSTSState siteState(expiretime, aHSTSState, includeSubdomains);
nsAutoCString stateString;
@ -367,7 +368,7 @@ nsSiteSecurityService::SetHSTSState(uint32_t aType,
NS_IMETHODIMP
nsSiteSecurityService::RemoveState(uint32_t aType, nsIURI* aURI,
uint32_t aFlags)
uint32_t aFlags, bool force = false)
{
// Child processes are not allowed direct access to this.
if (!XRE_IsParentProcess()) {
@ -387,8 +388,9 @@ nsSiteSecurityService::RemoveState(uint32_t aType, nsIURI* aURI,
mozilla::DataStorageType storageType = isPrivate
? mozilla::DataStorage_Private
: mozilla::DataStorage_Persistent;
// If this host is in the preload list, we have to store a knockout entry.
if (GetPreloadListEntry(hostname.get())) {
// If this host is in the preload list, we have to store a knockout entry
// if it's explicitly forced to not be HSTS anymore
if (force && GetPreloadListEntry(hostname.get())) {
SSSLOG(("SSS: storing knockout entry for %s", hostname.get()));
SiteHSTSState siteState(0, SecurityPropertyKnockout, false);
nsAutoCString stateString;
@ -769,7 +771,10 @@ nsSiteSecurityService::ProcessPKPHeader(nsIURI* aSourceURI,
return NS_ERROR_FAILURE;
}
// if maxAge == 0 we must delete all state, for now no hole-punching
// If maxAge == 0, we remove dynamic HPKP state for this host. Due to
// architectural constraints, if this host was preloaded, any future lookups
// will use the preloaded state (i.e. we can't store a "this host is not HPKP"
// entry like we can for HSTS).
if (maxAge == 0) {
return RemoveState(aType, aSourceURI, aFlags);
}

View file

@ -112,7 +112,9 @@ nsThreadPool::PutEvent(already_AddRefed<nsIRunnable> aEvent, uint32_t aFlags)
bool killThread = false;
{
MutexAutoLock lock(mMutex);
if (mThreads.Count() < (int32_t)mThreadLimit) {
if (mShutdown) {
killThread = true; // we're in shutdown, kill the thread
} else if (mThreads.Count() < (int32_t)mThreadLimit) {
mThreads.AppendObject(thread);
} else {
killThread = true; // okay, we don't need this thread anymore