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

- Bug 1208937 - Remove gfxPattern::GraphicsPatternType. r=jwatt. (eeb6dec919)
- Bug 1196927 - Force plugin BGRX image surface data to always have valid alpha. r=jrmuizel, r=BenWa (80667ce488)
- Bug 1156800: Post a task to send async NPP_New result from child to parent; r=jimm (81c40319a5)
- Bug 1194955 - Fix -Wunreachable-code warnings in dom/ipc and dom/plugins. r=jimm (939ae937a8)
- Bug 1151694 - Part 3: Manage mIsRunningOnCompositor flags for each properties respectively. r=bbirtles (3146a696cc)
- Bug 1182931 - Expose assert_unreached in subwindows. r=bbirtles (1b2e6f05b5)
- Bug 1151694 - Part 4 - Able to use testcommon.js in the window which has no opener. r=bbirtles (82bc744d44)
- Bug 1151694 - Part 0: Rewrite test_running_on_compositor.html with add_task(). r=bbirtles (2e209051e3)
- Bug 1151694 - Part 5 - Additional tests for Animation.IsRunningOnCompositor. r=bbirtles (de9858a004)
- Bug 1151694 - Part 6 - A test case of Animation.isRunningOnCompositor for transition. r=bbirtles (54bd2a22ea)
- Bug 1184377 - Move nsDocShell::PopProfileTimelineMarkers logic to ObservedDocShell, r=smaug (31e96712ac)
- Bug 1190826 - Rename "AddMarkerTo*" to "AddMarkerFor*" to reflect the new philosophy behind markers, r=tromey (b7d5ae6314)
- Bug 1152080 - Plugin configuration clip rects should be treated as visible rects. r=roc (4a18e0bd33)
- Bug 1050498 - Record compositing operations, r=jsantell,smaug,tromey (4efa28f063)
- Bug 1161900 - Use ICU normalization support during shaping if available, to support decomposable characters in more recently-encoded scripts. r=jdaggett,gps (d687a634cf)
- Bug 1164835 - Use vertical presentation forms (where available) in vertical-upright text as fallback if the font does not support the 'vert' feature. r=jdaggett (983a6f0c20)
- Bug 1139646 - Ensure gfxHarfBuzzShaper only loads the vmtx table once, to avoid leaking it. r=smontagu (72b5e2a698)
- Bug 1139888 - Check for missing glyph metrics tables. r=jdaggett (7574fdcf7b)
- Bug 1137588 - patch 1 - Read the second array in 'vmtx' correctly to get glyph vertical origins. r=jdaggett (c835835237)
- Bug 1137588 - patch 2 - Use a better default vOrigin in fonts without real vertical metrics. r=jdaggett (ad1e27029e)
- Bug 1187145 - Replace nsBaseHashtable::Enumerate() calls in gfx/ with iterators r=njn (597ff872bc)
- Bug 729993 - Use finer HarfBuzz cluster level. r=jfkthame (9b99d11def)
- missing of Bug 1148660 - Correct the handling of glyph positioning offsets in vertical-upright mode. r=jdaggett (b32d14d197)
- Bug 1178753 - Always enable async-video when OMTC is enabled. r=sotaro (c61f2a0be3)
- Bug 1164735 - Move gPrefLangToLangGroups[] inside a function to avoid a static constructor. r=jdaggett (a6a4060db9)
- Bug 1163488 - use the preprocessor to keep font lang arrays in sync. r=m_kato (6d9747d144)
- Bug 1188995 - Increase tile size to 512/1024 on OSX. r=jrmuizel,mstange (e94187af4b)
- Bug 1186661 - Use monitors-changed signal to update screen manager on GTK. r=karlt (97e0393eb6)
- Bug 1191040 - Ensure that we only compute the tile size once. r=BenWa (b954ce41ac)
- Bug 1182665 - Add gfxPlatform::GetScreenSize() and use nsIScreen for gfxPlatform::GetScreenDepth() r=nical (91a24e82ec)
- Bug 1182665 - Adjust tile sizes depending on the screen size r=nical (319945c03a)
- Bug 1173579 - Take the first valid default font. r=jdagget (d03c594b94)
- Bug 1189158 - shutdown font loader thread in separate event. r=m_kato (c497e32155)
- Bug 1189129 - annotate no default font aborts. r=bas (c20fc90269)
- Bug 1204400 - Fix -Wshadow warnings in gfx/thebes and suppress those from Skia headers. r=BenWa (435b12fbb2)
- Bug 1192699 - eliminate the two-stage system fontlist initialization under DirectWrite. r=m_kato (eb458720a1)
- Bug 1194707 - Remove the docshell param from TimelineMarker constructors, r=tromey (c77c934021)
- Bug 1195838 - Maintain all the TimelineMarker subclasses in a single place, r=tromey (c2da168977)
- Bug 697981 - Prevent reloading of spelling dictionary on unfocused editors; r=roc (ec2ed87554)
- Bug 1184249 - Remove warning if rootContent is null in nsEditorSpellCheck::UpdateCurrentDictionary. r=ehsan (8a828662d6)
- Bug 717433 - Make selected language stick, regardless of whether it partly matches (test). r=roc (38a92a487f)
- adapt Bug 717433 - Make selected language stick, regardless of whether it partly matches. r=roc (6a0d7f2a8b)
- extended Bug 1200533 - Fix spellchecker dictionary logic. r=smaug (39228d4225)
- Bug 1204147 - Prevent content preferences being written when they shouldn't. r=roc (bff4c98f6d)
- Bug 1193293 - Don't pick a new dictionary which checking. r=roc (021da43b73)
- Bug 1205983 - Remove all observer code from nsEditor. r=ehsan (aaf27ca6dc)
- Bug 1205796 - "Coverity 1323784 indicates a useless passed-by-value argument in nsEditorSpellCheck::TryDictionary". r=smaug (a60feb5f61)
- Bug 309731 - Allow document.execCommand('inserthtml') with an empty string parameter. r=ehsan (4956ee404b)
This commit is contained in:
2022-08-29 09:53:04 +08:00
parent f39d19c93e
commit 71cc47fa2f
122 changed files with 2359 additions and 1632 deletions
+10 -169
View File
@@ -95,6 +95,7 @@
#include "nsSHistory.h"
#include "nsDocShellEditorData.h"
#include "GeckoProfiler.h"
#include "timeline/JavascriptTimelineMarker.h"
// Helper Classes
#include "nsError.h"
@@ -1617,7 +1618,7 @@ nsDocShell::LoadStream(nsIInputStream* aStream, nsIURI* aURI,
(void)aLoadInfo->GetLoadType(&lt);
// Get the appropriate LoadType from nsIDocShellLoadInfo type
loadType = ConvertDocShellLoadInfoToLoadType(lt);
nsCOMPtr<nsISupports> owner;
aLoadInfo->GetOwner(getter_AddRefs(owner));
requestingPrincipal = do_QueryInterface(owner);
@@ -2861,129 +2862,16 @@ nsDocShell::GetRecordProfileTimelineMarkers(bool* aValue)
nsresult
nsDocShell::PopProfileTimelineMarkers(
JSContext* aCx,
JS::MutableHandle<JS::Value> aProfileTimelineMarkers)
JS::MutableHandle<JS::Value> aOut)
{
// Looping over all markers gathered so far at the docShell level, whenever a
// START marker is found, look for the corresponding END marker and build a
// {name,start,end} JS object.
// Paint markers are different because paint is handled at root docShell level
// in the information that a paint was done is then stored at each sub
// docShell level but we can only be sure that a paint did happen in a
// docShell if an Layer marker type was recorded too.
nsTArray<dom::ProfileTimelineMarker> store;
SequenceRooter<dom::ProfileTimelineMarker> rooter(aCx, &store);
nsTArray<mozilla::dom::ProfileTimelineMarker> profileTimelineMarkers;
SequenceRooter<mozilla::dom::ProfileTimelineMarker> rooter(
aCx, &profileTimelineMarkers);
if (!IsObserved()) {
if (!ToJSValue(aCx, profileTimelineMarkers, aProfileTimelineMarkers)) {
JS_ClearPendingException(aCx);
return NS_ERROR_UNEXPECTED;
}
return NS_OK;
if (IsObserved()) {
mObserved->PopMarkers(aCx, store);
}
nsTArray<UniquePtr<TimelineMarker>>& markersStore = mObserved.get()->mTimelineMarkers;
// If we see an unpaired START, we keep it around for the next call
// to PopProfileTimelineMarkers. We store the kept START objects in
// this array.
nsTArray<UniquePtr<TimelineMarker>> keptMarkers;
for (uint32_t i = 0; i < markersStore.Length(); ++i) {
UniquePtr<TimelineMarker>& startPayload = markersStore[i];
const char* startMarkerName = startPayload->GetName();
bool hasSeenPaintedLayer = false;
bool isPaint = strcmp(startMarkerName, "Paint") == 0;
// If we are processing a Paint marker, we append information from
// all the embedded Layer markers to this array.
dom::Sequence<dom::ProfileTimelineLayerRect> layerRectangles;
// If this is a TRACING_TIMESTAMP marker, there's no corresponding "end"
// marker, as it's a single unit of time, not a duration, create the final
// marker here.
if (startPayload->GetMetaData() == TRACING_TIMESTAMP) {
mozilla::dom::ProfileTimelineMarker* marker =
profileTimelineMarkers.AppendElement();
marker->mName = NS_ConvertUTF8toUTF16(startPayload->GetName());
marker->mStart = startPayload->GetTime();
marker->mEnd = startPayload->GetTime();
marker->mStack = startPayload->GetStack();
startPayload->AddDetails(aCx, *marker);
continue;
}
if (startPayload->GetMetaData() == TRACING_INTERVAL_START) {
bool hasSeenEnd = false;
// DOM events can be nested, so we must take care when searching
// for the matching end. It doesn't hurt to apply this logic to
// all event types.
uint32_t markerDepth = 0;
// The assumption is that the devtools timeline flushes markers frequently
// enough for the amount of markers to always be small enough that the
// nested for loop isn't going to be a performance problem.
for (uint32_t j = i + 1; j < markersStore.Length(); ++j) {
UniquePtr<TimelineMarker>& endPayload = markersStore[j];
const char* endMarkerName = endPayload->GetName();
// Look for Layer markers to stream out paint markers.
if (isPaint && strcmp(endMarkerName, "Layer") == 0) {
hasSeenPaintedLayer = true;
endPayload->AddLayerRectangles(layerRectangles);
}
if (!startPayload->Equals(*endPayload)) {
continue;
}
// Pair start and end markers.
if (endPayload->GetMetaData() == TRACING_INTERVAL_START) {
++markerDepth;
} else if (endPayload->GetMetaData() == TRACING_INTERVAL_END) {
if (markerDepth > 0) {
--markerDepth;
} else {
// But ignore paint start/end if no layer has been painted.
if (!isPaint || (isPaint && hasSeenPaintedLayer)) {
mozilla::dom::ProfileTimelineMarker* marker =
profileTimelineMarkers.AppendElement();
marker->mName = NS_ConvertUTF8toUTF16(startPayload->GetName());
marker->mStart = startPayload->GetTime();
marker->mEnd = endPayload->GetTime();
marker->mStack = startPayload->GetStack();
if (isPaint) {
marker->mRectangles.Construct(layerRectangles);
}
startPayload->AddDetails(aCx, *marker);
endPayload->AddDetails(aCx, *marker);
}
// We want the start to be dropped either way.
hasSeenEnd = true;
break;
}
}
}
// If we did not see the corresponding END, keep the START.
if (!hasSeenEnd) {
keptMarkers.AppendElement(Move(markersStore[i]));
markersStore.RemoveElementAt(i);
--i;
}
}
}
markersStore.SwapElements(keptMarkers);
if (!ToJSValue(aCx, profileTimelineMarkers, aProfileTimelineMarkers)) {
if (!ToJSValue(aCx, store, aOut)) {
JS_ClearPendingException(aCx);
return NS_ERROR_UNEXPECTED;
}
@@ -14067,51 +13955,6 @@ nsDocShell::GetOpener()
return opener;
}
class JavascriptTimelineMarker : public TimelineMarker
{
public:
JavascriptTimelineMarker(nsDocShell* aDocShell, const char* aName,
const char* aReason,
const char16_t* aFunctionName,
const char16_t* aFileName,
uint32_t aLineNumber)
: TimelineMarker(aDocShell, aName, TRACING_INTERVAL_START,
NS_ConvertUTF8toUTF16(aReason),
NO_STACK)
, mFunctionName(aFunctionName)
, mFileName(aFileName)
, mLineNumber(aLineNumber)
{
}
void AddDetails(JSContext* aCx, mozilla::dom::ProfileTimelineMarker& aMarker)
override
{
aMarker.mCauseName.Construct(GetCause());
if (!mFunctionName.IsEmpty() || !mFileName.IsEmpty()) {
RootedDictionary<ProfileTimelineStackFrame> stackFrame(aCx);
stackFrame.mLine.Construct(mLineNumber);
stackFrame.mSource.Construct(mFileName);
stackFrame.mFunctionDisplayName.Construct(mFunctionName);
JS::Rooted<JS::Value> newStack(aCx);
if (ToJSValue(aCx, stackFrame, &newStack)) {
if (newStack.isObject()) {
aMarker.mStack = &newStack.toObject();
}
} else {
JS_ClearPendingException(aCx);
}
}
}
private:
nsString mFunctionName;
nsString mFileName;
uint32_t mLineNumber;
};
void
nsDocShell::NotifyJSRunToCompletionStart(const char* aReason,
const char16_t* aFunctionName,
@@ -14122,10 +13965,8 @@ nsDocShell::NotifyJSRunToCompletionStart(const char* aReason,
// If first start, mark interval start.
if (timelineOn && mJSRunToCompletionDepth == 0) {
mozilla::UniquePtr<TimelineMarker> marker =
MakeUnique<JavascriptTimelineMarker>(this, "Javascript", aReason,
aFunctionName, aFilename,
aLineNumber);
UniquePtr<TimelineMarker> marker = MakeUnique<JavascriptTimelineMarker>(
aReason, aFunctionName, aFilename, aLineNumber, TRACING_INTERVAL_START);
TimelineConsumers::AddMarkerForDocShell(this, Move(marker));
}
mJSRunToCompletionDepth++;
+6 -4
View File
@@ -34,9 +34,9 @@
#include "nsAutoPtr.h"
#include "nsThreadUtils.h"
#include "nsContentUtils.h"
#include "timeline/TimelineMarker.h"
#include "timeline/TimelineConsumers.h"
#include "timeline/ObservedDocShell.h"
#include "timeline/TimelineConsumers.h"
#include "timeline/TimelineMarker.h"
// Threshold value in ms for META refresh based redirects
#define REFRESH_REDIRECT_TIMER 15000
@@ -285,10 +285,12 @@ private:
// is stored on docshells directly.
friend void mozilla::TimelineConsumers::AddConsumer(nsDocShell* aDocShell);
friend void mozilla::TimelineConsumers::RemoveConsumer(nsDocShell* aDocShell);
friend void mozilla::TimelineConsumers::AddMarkerForDocShell(
nsDocShell* aDocShell, UniquePtr<TimelineMarker>&& aMarker);
friend void mozilla::TimelineConsumers::AddMarkerForDocShell(
nsDocShell* aDocShell, const char* aName, TracingMetadata aMetaData);
friend void mozilla::TimelineConsumers::AddMarkerForDocShell(
nsDocShell* aDocShell, const char* aName, const TimeStamp& aTime, TracingMetadata aMetaData);
friend void mozilla::TimelineConsumers::AddMarkerForDocShell(
nsDocShell* aDocShell, UniquePtr<TimelineMarker>&& aMarker);
public:
// Tell the favicon service that aNewURI has the same favicon as aOldURI.
@@ -6,7 +6,7 @@
#include "mozilla/AutoGlobalTimelineMarker.h"
#include "mozilla/TimelineConsumers.h"
#include "TimelineConsumers.h"
#include "MainThreadUtils.h"
namespace mozilla {
@@ -22,7 +22,7 @@ AutoGlobalTimelineMarker::AutoGlobalTimelineMarker(const char* aName
return;
}
TimelineConsumers::AddMarkerToAllObservedDocShells(mName, TRACING_INTERVAL_START);
TimelineConsumers::AddMarkerForAllObservedDocShells(mName, TRACING_INTERVAL_START);
}
AutoGlobalTimelineMarker::~AutoGlobalTimelineMarker()
@@ -31,7 +31,7 @@ AutoGlobalTimelineMarker::~AutoGlobalTimelineMarker()
return;
}
TimelineConsumers::AddMarkerToAllObservedDocShells(mName, TRACING_INTERVAL_END);
TimelineConsumers::AddMarkerForAllObservedDocShells(mName, TRACING_INTERVAL_END);
}
} // namespace mozilla
@@ -19,7 +19,7 @@ namespace mozilla {
// Similar to `AutoTimelineMarker`, but adds its traced marker to all docshells,
// not a single particular one. This is useful for operations that aren't
// associated with any one particular doc shell, or when it isn't clear which
// doc shell triggered the operation.
// docshell triggered the operation.
//
// Example usage:
//
@@ -6,7 +6,7 @@
#include "mozilla/AutoTimelineMarker.h"
#include "mozilla/TimelineConsumers.h"
#include "TimelineConsumers.h"
#include "MainThreadUtils.h"
#include "nsDocShell.h"
@@ -0,0 +1,50 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_ConsoleTimelineMarker_h_
#define mozilla_ConsoleTimelineMarker_h_
#include "TimelineMarker.h"
#include "mozilla/dom/ProfileTimelineMarkerBinding.h"
namespace mozilla {
class ConsoleTimelineMarker : public TimelineMarker
{
public:
explicit ConsoleTimelineMarker(const nsAString& aCause,
TracingMetadata aMetaData)
: TimelineMarker("ConsoleTime", aCause, aMetaData)
{
// Stack is captured by default on the "start" marker. Explicitly also
// capture stack on the "end" marker.
if (aMetaData == TRACING_INTERVAL_END) {
CaptureStack();
}
}
virtual bool Equals(const TimelineMarker& aOther) override
{
if (!TimelineMarker::Equals(aOther)) {
return false;
}
// Console markers must have matching causes as well.
return GetCause() == aOther.GetCause();
}
virtual void AddDetails(JSContext* aCx, dom::ProfileTimelineMarker& aMarker) override
{
if (GetMetaData() == TRACING_INTERVAL_START) {
aMarker.mCauseName.Construct(GetCause());
} else {
aMarker.mEndStack = GetStack();
}
}
};
} // namespace mozilla
#endif // mozilla_ConsoleTimelineMarker_h_
@@ -0,0 +1,39 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_EventTimelineMarker_h_
#define mozilla_EventTimelineMarker_h_
#include "TimelineMarker.h"
#include "mozilla/dom/ProfileTimelineMarkerBinding.h"
namespace mozilla {
class EventTimelineMarker : public TimelineMarker
{
public:
explicit EventTimelineMarker(const nsAString& aCause,
uint16_t aPhase,
TracingMetadata aMetaData)
: TimelineMarker("DOMEvent", aCause, aMetaData)
, mPhase(aPhase)
{}
virtual void AddDetails(JSContext* aCx, dom::ProfileTimelineMarker& aMarker) override
{
if (GetMetaData() == TRACING_INTERVAL_START) {
aMarker.mType.Construct(GetCause());
aMarker.mEventPhase.Construct(mPhase);
}
}
private:
uint16_t mPhase;
};
} // namespace mozilla
#endif // mozilla_EventTimelineMarker_h_
@@ -0,0 +1,60 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_JavascriptTimelineMarker_h_
#define mozilla_JavascriptTimelineMarker_h_
#include "TimelineMarker.h"
#include "mozilla/dom/ProfileTimelineMarkerBinding.h"
#include "mozilla/dom/RootedDictionary.h"
#include "mozilla/dom/ToJSValue.h"
namespace mozilla {
class JavascriptTimelineMarker : public TimelineMarker
{
public:
explicit JavascriptTimelineMarker(const char* aReason,
const char16_t* aFunctionName,
const char16_t* aFileName,
uint32_t aLineNumber,
TracingMetadata aMetaData)
: TimelineMarker("Javascript", NS_ConvertUTF8toUTF16(aReason), aMetaData, NO_STACK)
, mFunctionName(aFunctionName)
, mFileName(aFileName)
, mLineNumber(aLineNumber)
{}
virtual void AddDetails(JSContext* aCx, dom::ProfileTimelineMarker& aMarker) override
{
aMarker.mCauseName.Construct(GetCause());
if (!mFunctionName.IsEmpty() || !mFileName.IsEmpty()) {
dom::RootedDictionary<dom::ProfileTimelineStackFrame> stackFrame(aCx);
stackFrame.mLine.Construct(mLineNumber);
stackFrame.mSource.Construct(mFileName);
stackFrame.mFunctionDisplayName.Construct(mFunctionName);
JS::Rooted<JS::Value> newStack(aCx);
if (ToJSValue(aCx, stackFrame, &newStack)) {
if (newStack.isObject()) {
aMarker.mStack = &newStack.toObject();
}
} else {
JS_ClearPendingException(aCx);
}
}
}
private:
nsString mFunctionName;
nsString mFileName;
uint32_t mLineNumber;
};
} // namespace mozilla
#endif // mozilla_JavascriptTimelineMarker_h_
@@ -0,0 +1,45 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_LayerTimelineMarker_h_
#define mozilla_LayerTimelineMarker_h_
#include "TimelineMarker.h"
#include "mozilla/dom/ProfileTimelineMarkerBinding.h"
namespace mozilla {
class LayerTimelineMarker : public TimelineMarker
{
public:
explicit LayerTimelineMarker(const nsIntRegion& aRegion)
: TimelineMarker("Layer", TRACING_EVENT)
, mRegion(aRegion)
{}
~LayerTimelineMarker()
{}
void AddLayerRectangles(dom::Sequence<dom::ProfileTimelineLayerRect>& aRectangles)
{
nsIntRegionRectIterator it(mRegion);
while (const nsIntRect* iterRect = it.Next()) {
dom::ProfileTimelineLayerRect rect;
rect.mX = iterRect->X();
rect.mY = iterRect->Y();
rect.mWidth = iterRect->Width();
rect.mHeight = iterRect->Height();
aRectangles.AppendElement(rect, fallible);
}
}
private:
nsIntRegion mRegion;
};
} // namespace mozilla
#endif // mozilla_LayerTimelineMarker_h_
+99 -7
View File
@@ -7,6 +7,7 @@
#include "ObservedDocShell.h"
#include "TimelineMarker.h"
#include "LayerTimelineMarker.h"
#include "mozilla/Move.h"
namespace mozilla {
@@ -15,13 +16,6 @@ ObservedDocShell::ObservedDocShell(nsDocShell* aDocShell)
: mDocShell(aDocShell)
{}
void
ObservedDocShell::AddMarker(const char* aName, TracingMetadata aMetaData)
{
TimelineMarker* marker = new TimelineMarker(mDocShell, aName, aMetaData);
mTimelineMarkers.AppendElement(marker);
}
void
ObservedDocShell::AddMarker(UniquePtr<TimelineMarker>&& aMarker)
{
@@ -34,4 +28,102 @@ ObservedDocShell::ClearMarkers()
mTimelineMarkers.Clear();
}
void
ObservedDocShell::PopMarkers(JSContext* aCx,
nsTArray<dom::ProfileTimelineMarker>& aStore)
{
// If we see an unpaired START, we keep it around for the next call
// to ObservedDocShell::PopMarkers. We store the kept START objects here.
nsTArray<UniquePtr<TimelineMarker>> keptStartMarkers;
for (uint32_t i = 0; i < mTimelineMarkers.Length(); ++i) {
UniquePtr<TimelineMarker>& startPayload = mTimelineMarkers[i];
// If this is a TRACING_TIMESTAMP marker, there's no corresponding END
// as it's a single unit of time, not a duration.
if (startPayload->GetMetaData() == TRACING_TIMESTAMP) {
dom::ProfileTimelineMarker* marker = aStore.AppendElement();
marker->mName = NS_ConvertUTF8toUTF16(startPayload->GetName());
marker->mStart = startPayload->GetTime();
marker->mEnd = startPayload->GetTime();
marker->mStack = startPayload->GetStack();
startPayload->AddDetails(aCx, *marker);
continue;
}
// Whenever a START marker is found, look for the corresponding END
// and build a {name,start,end} JS object.
if (startPayload->GetMetaData() == TRACING_INTERVAL_START) {
bool hasSeenEnd = false;
// "Paint" markers are different because painting is handled at root
// docshell level. The information that a paint was done is stored at
// sub-docshell level, but we can only be sure that a paint did actually
// happen in if a "Layer" marker was recorded too.
bool startIsPaintType = strcmp(startPayload->GetName(), "Paint") == 0;
bool hasSeenLayerType = false;
// If we are processing a "Paint" marker, we append information from
// all the embedded "Layer" markers to this array.
dom::Sequence<dom::ProfileTimelineLayerRect> layerRectangles;
// DOM events can be nested, so we must take care when searching
// for the matching end. It doesn't hurt to apply this logic to
// all event types.
uint32_t markerDepth = 0;
// The assumption is that the devtools timeline flushes markers frequently
// enough for the amount of markers to always be small enough that the
// nested for loop isn't going to be a performance problem.
for (uint32_t j = i + 1; j < mTimelineMarkers.Length(); ++j) {
UniquePtr<TimelineMarker>& endPayload = mTimelineMarkers[j];
bool endIsLayerType = strcmp(endPayload->GetName(), "Layer") == 0;
// Look for "Layer" markers to stream out "Paint" markers.
if (startIsPaintType && endIsLayerType) {
LayerTimelineMarker* layerPayload = static_cast<LayerTimelineMarker*>(endPayload.get());
layerPayload->AddLayerRectangles(layerRectangles);
hasSeenLayerType = true;
}
if (!startPayload->Equals(*endPayload)) {
continue;
}
if (endPayload->GetMetaData() == TRACING_INTERVAL_START) {
++markerDepth;
continue;
}
if (endPayload->GetMetaData() == TRACING_INTERVAL_END) {
if (markerDepth > 0) {
--markerDepth;
continue;
}
if (!startIsPaintType || (startIsPaintType && hasSeenLayerType)) {
dom::ProfileTimelineMarker* marker = aStore.AppendElement();
marker->mName = NS_ConvertUTF8toUTF16(startPayload->GetName());
marker->mStart = startPayload->GetTime();
marker->mEnd = endPayload->GetTime();
marker->mStack = startPayload->GetStack();
if (hasSeenLayerType) {
marker->mRectangles.Construct(layerRectangles);
}
startPayload->AddDetails(aCx, *marker);
endPayload->AddDetails(aCx, *marker);
}
hasSeenEnd = true;
break;
}
}
// If we did not see the corresponding END, keep the START.
if (!hasSeenEnd) {
keptStartMarkers.AppendElement(Move(mTimelineMarkers[i]));
mTimelineMarkers.RemoveElementAt(i);
--i;
}
}
}
mTimelineMarkers.SwapElements(keptStartMarkers);
}
} // namespace mozilla
+10 -10
View File
@@ -4,17 +4,20 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef ObservedDocShell_h_
#define ObservedDocShell_h_
#ifndef mozilla_ObservedDocShell_h_
#define mozilla_ObservedDocShell_h_
#include "GeckoProfiler.h"
#include "nsTArray.h"
#include "mozilla/nsRefPtr.h"
class nsDocShell;
class TimelineMarker;
namespace mozilla {
class TimelineMarker;
namespace dom {
struct ProfileTimelineMarker;
}
// # ObservedDocShell
//
@@ -24,20 +27,17 @@ class ObservedDocShell : public LinkedListElement<ObservedDocShell>
{
private:
nsRefPtr<nsDocShell> mDocShell;
public:
// FIXME: make this private once all marker-specific logic has been
// moved out of nsDocShell.
nsTArray<UniquePtr<TimelineMarker>> mTimelineMarkers;
public:
explicit ObservedDocShell(nsDocShell* aDocShell);
nsDocShell* operator*() const { return mDocShell.get(); }
void AddMarker(const char* aName, TracingMetadata aMetaData);
void AddMarker(UniquePtr<TimelineMarker>&& aMarker);
void ClearMarkers();
void PopMarkers(JSContext* aCx, nsTArray<dom::ProfileTimelineMarker>& aStore);
};
} // namespace mozilla
#endif /* ObservedDocShell_h_ */
#endif /* mozilla_ObservedDocShell_h_ */
@@ -0,0 +1,40 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_RestyleTimelineMarker_h_
#define mozilla_RestyleTimelineMarker_h_
#include "TimelineMarker.h"
#include "mozilla/dom/ProfileTimelineMarkerBinding.h"
namespace mozilla {
class RestyleTimelineMarker : public TimelineMarker
{
public:
explicit RestyleTimelineMarker(nsRestyleHint aRestyleHint,
TracingMetadata aMetaData)
: TimelineMarker("Styles", aMetaData)
{
if (aRestyleHint) {
mRestyleHint.AssignWithConversion(RestyleManager::RestyleHintToString(aRestyleHint));
}
}
virtual void AddDetails(JSContext* aCx, dom::ProfileTimelineMarker& aMarker) override
{
if (GetMetaData() == TRACING_INTERVAL_START) {
aMarker.mRestyleHint.Construct(mRestyleHint);
}
}
private:
nsAutoString mRestyleHint;
};
} // namespace mozilla
#endif // mozilla_RestyleTimelineMarker_h_
+47 -9
View File
@@ -65,6 +65,27 @@ TimelineConsumers::GetKnownDocShells(Vector<nsRefPtr<nsDocShell>>& aStore)
return true;
}
void
TimelineConsumers::AddMarkerForDocShell(nsDocShell* aDocShell,
const char* aName,
TracingMetadata aMetaData)
{
if (aDocShell->IsObserved()) {
aDocShell->mObserved->AddMarker(Move(MakeUnique<TimelineMarker>(aName, aMetaData)));
}
}
void
TimelineConsumers::AddMarkerForDocShell(nsDocShell* aDocShell,
const char* aName,
const TimeStamp& aTime,
TracingMetadata aMetaData)
{
if (aDocShell->IsObserved()) {
aDocShell->mObserved->AddMarker(Move(MakeUnique<TimelineMarker>(aName, aTime, aMetaData)));
}
}
void
TimelineConsumers::AddMarkerForDocShell(nsDocShell* aDocShell,
UniquePtr<TimelineMarker>&& aMarker)
@@ -75,17 +96,33 @@ TimelineConsumers::AddMarkerForDocShell(nsDocShell* aDocShell,
}
void
TimelineConsumers::AddMarkerForDocShell(nsDocShell* aDocShell,
const char* aName, TracingMetadata aMetaData)
TimelineConsumers::AddMarkerForDocShell(nsIDocShell* aDocShell,
const char* aName,
TracingMetadata aMetaData)
{
if (aDocShell->IsObserved()) {
aDocShell->mObserved->AddMarker(aName, aMetaData);
}
AddMarkerForDocShell(static_cast<nsDocShell*>(aDocShell), aName, aMetaData);
}
void
TimelineConsumers::AddMarkerToDocShellsList(Vector<nsRefPtr<nsDocShell>>& aDocShells,
const char* aName, TracingMetadata aMetaData)
TimelineConsumers::AddMarkerForDocShell(nsIDocShell* aDocShell,
const char* aName,
const TimeStamp& aTime,
TracingMetadata aMetaData)
{
AddMarkerForDocShell(static_cast<nsDocShell*>(aDocShell), aName, aTime, aMetaData);
}
void
TimelineConsumers::AddMarkerForDocShell(nsIDocShell* aDocShell,
UniquePtr<TimelineMarker>&& aMarker)
{
AddMarkerForDocShell(static_cast<nsDocShell*>(aDocShell), Move(aMarker));
}
void
TimelineConsumers::AddMarkerForDocShellsList(Vector<nsRefPtr<nsDocShell>>& aDocShells,
const char* aName,
TracingMetadata aMetaData)
{
for (Vector<nsRefPtr<nsDocShell>>::Range range = aDocShells.all();
!range.empty();
@@ -95,7 +132,8 @@ TimelineConsumers::AddMarkerToDocShellsList(Vector<nsRefPtr<nsDocShell>>& aDocSh
}
void
TimelineConsumers::AddMarkerToAllObservedDocShells(const char* aName, TracingMetadata aMetaData)
TimelineConsumers::AddMarkerForAllObservedDocShells(const char* aName,
TracingMetadata aMetaData)
{
Vector<nsRefPtr<nsDocShell>> docShells;
if (!GetKnownDocShells(docShells)) {
@@ -104,7 +142,7 @@ TimelineConsumers::AddMarkerToAllObservedDocShells(const char* aName, TracingMet
return;
}
AddMarkerToDocShellsList(docShells, aName, aMetaData);
AddMarkerForDocShellsList(docShells, aName, aMetaData);
}
} // namespace mozilla
+44 -8
View File
@@ -10,11 +10,14 @@
#include "mozilla/UniquePtr.h"
#include "mozilla/LinkedList.h"
#include "mozilla/Vector.h"
#include "timeline/ObservedDocShell.h"
#include "GeckoProfiler.h"
class nsDocShell;
class nsIDocShell;
namespace mozilla {
class ObservedDocShell;
class TimelineMarker;
class TimelineConsumers
{
@@ -30,16 +33,49 @@ public:
static bool IsEmpty();
static bool GetKnownDocShells(Vector<nsRefPtr<nsDocShell>>& aStore);
// Methods for adding markers to appropriate docshells. These will only add
// markers if the docshell is currently being observed by a timeline.
// Methods for adding markers relevant for particular docshells, or generic
// (meaning that they either can't be tied to a particular docshell, or one
// wasn't accessible in the part of the codebase where they're instantiated).
// These will only add markers if at least one docshell is currently being
// observed by a timeline. Markers tied to a particular docshell won't be
// created unless that docshell is specifically being currently observed.
// See nsIDocShell::recordProfileTimelineMarkers
// These methods create a custom marker from a name and some metadata,
// relevant for a specific docshell.
static void AddMarkerForDocShell(nsDocShell* aDocShell,
const char* aName,
TracingMetadata aMetaData);
static void AddMarkerForDocShell(nsIDocShell* aDocShell,
const char* aName,
TracingMetadata aMetaData);
static void AddMarkerForDocShell(nsDocShell* aDocShell,
const char* aName,
const TimeStamp& aTime,
TracingMetadata aMetaData);
static void AddMarkerForDocShell(nsIDocShell* aDocShell,
const char* aName,
const TimeStamp& aTime,
TracingMetadata aMetaData);
// These methods register and receive ownership of an already created marker,
// relevant for a specific docshell.
static void AddMarkerForDocShell(nsDocShell* aDocShell,
UniquePtr<TimelineMarker>&& aMarker);
static void AddMarkerForDocShell(nsDocShell* aDocShell,
const char* aName, TracingMetadata aMetaData);
static void AddMarkerToDocShellsList(Vector<nsRefPtr<nsDocShell>>& aDocShells,
const char* aName, TracingMetadata aMetaData);
static void AddMarkerToAllObservedDocShells(const char* aName, TracingMetadata aMetaData);
static void AddMarkerForDocShell(nsIDocShell* aDocShell,
UniquePtr<TimelineMarker>&& aMarker);
// This method creates custom markers, relevant for a list of docshells.
static void AddMarkerForDocShellsList(Vector<nsRefPtr<nsDocShell>>& aDocShells,
const char* aName,
TracingMetadata aMetaData);
// This method creates custom markers, none of which have to be tied to a
// particular docshell.
static void AddMarkerForAllObservedDocShells(const char* aName,
TracingMetadata aMetaData);
};
} // namespace mozilla
+76 -21
View File
@@ -4,33 +4,91 @@
* 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 "nsDocShell.h"
#include "TimelineMarker.h"
TimelineMarker::TimelineMarker(nsDocShell* aDocShell, const char* aName,
TracingMetadata aMetaData)
: mName(aName)
, mMetaData(aMetaData)
{
MOZ_COUNT_CTOR(TimelineMarker);
MOZ_ASSERT(aName);
aDocShell->Now(&mTime);
if (aMetaData == TRACING_INTERVAL_START || aMetaData == TRACING_TIMESTAMP) {
CaptureStack();
}
}
namespace mozilla {
TimelineMarker::TimelineMarker(nsDocShell* aDocShell, const char* aName,
TimelineMarker::TimelineMarker(const char* aName,
TracingMetadata aMetaData,
const nsAString& aCause,
TimelineStackRequest aStackRequest)
: mName(aName)
, mMetaData(aMetaData)
, mCause(aCause)
{
MOZ_COUNT_CTOR(TimelineMarker);
MOZ_ASSERT(aName);
aDocShell->Now(&mTime);
SetCurrentTime();
CaptureStackIfNecessary(aMetaData, aStackRequest);
}
TimelineMarker::TimelineMarker(const char* aName,
const TimeStamp& aTime,
TracingMetadata aMetaData,
TimelineStackRequest aStackRequest)
: mName(aName)
, mMetaData(aMetaData)
{
MOZ_COUNT_CTOR(TimelineMarker);
MOZ_ASSERT(aName);
SetCustomTime(aTime);
CaptureStackIfNecessary(aMetaData, aStackRequest);
}
TimelineMarker::TimelineMarker(const char* aName,
const nsAString& aCause,
TracingMetadata aMetaData,
TimelineStackRequest aStackRequest)
: mName(aName)
, mCause(aCause)
, mMetaData(aMetaData)
{
MOZ_COUNT_CTOR(TimelineMarker);
MOZ_ASSERT(aName);
SetCurrentTime();
CaptureStackIfNecessary(aMetaData, aStackRequest);
}
TimelineMarker::TimelineMarker(const char* aName,
const nsAString& aCause,
const TimeStamp& aTime,
TracingMetadata aMetaData,
TimelineStackRequest aStackRequest)
: mName(aName)
, mCause(aCause)
, mMetaData(aMetaData)
{
MOZ_COUNT_CTOR(TimelineMarker);
MOZ_ASSERT(aName);
SetCustomTime(aTime);
CaptureStackIfNecessary(aMetaData, aStackRequest);
}
TimelineMarker::~TimelineMarker()
{
MOZ_COUNT_DTOR(TimelineMarker);
}
void
TimelineMarker::SetCurrentTime()
{
TimeStamp now = TimeStamp::Now();
SetCustomTime(now);
}
void
TimelineMarker::SetCustomTime(const TimeStamp& aTime)
{
bool isInconsistent = false;
mTime = (aTime - TimeStamp::ProcessCreation(isInconsistent)).ToMilliseconds();
}
void
TimelineMarker::CaptureStackIfNecessary(TracingMetadata aMetaData,
TimelineStackRequest aStackRequest)
{
if ((aMetaData == TRACING_INTERVAL_START ||
aMetaData == TRACING_TIMESTAMP) &&
aStackRequest != NO_STACK) {
@@ -38,7 +96,4 @@ TimelineMarker::TimelineMarker(nsDocShell* aDocShell, const char* aName,
}
}
TimelineMarker::~TimelineMarker()
{
MOZ_COUNT_DTOR(TimelineMarker);
}
} // namespace mozilla
+46 -33
View File
@@ -4,62 +4,68 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef TimelineMarker_h_
#define TimelineMarker_h_
#ifndef mozilla_TimelineMarker_h_
#define mozilla_TimelineMarker_h_
#include "nsString.h"
#include "GeckoProfiler.h"
#include "mozilla/dom/ProfileTimelineMarkerBinding.h"
#include "nsContentUtils.h"
#include "jsapi.h"
#include "GeckoProfiler.h"
class nsDocShell;
// Objects of this type can be added to the timeline. The class can
// also be subclassed to let a given marker creator provide custom
// details.
namespace mozilla {
namespace dom {
struct ProfileTimelineMarker;
}
// Objects of this type can be added to the timeline if there is an interested
// consumer. The class can also be subclassed to let a given marker creator
// provide custom details.
class TimelineMarker
{
public:
enum TimelineStackRequest { STACK, NO_STACK };
TimelineMarker(nsDocShell* aDocShell, const char* aName,
TracingMetadata aMetaData);
TimelineMarker(nsDocShell* aDocShell, const char* aName,
TimelineMarker(const char* aName,
TracingMetadata aMetaData,
TimelineStackRequest aStackRequest = STACK);
TimelineMarker(const char* aName,
const TimeStamp& aTime,
TracingMetadata aMetaData,
TimelineStackRequest aStackRequest = STACK);
TimelineMarker(const char* aName,
const nsAString& aCause,
TracingMetadata aMetaData,
TimelineStackRequest aStackRequest = STACK);
TimelineMarker(const char* aName,
const nsAString& aCause,
const TimeStamp& aTime,
TracingMetadata aMetaData,
TimelineStackRequest aStackRequest = STACK);
virtual ~TimelineMarker();
// Check whether two markers should be considered the same,
// for the purpose of pairing start and end markers. Normally
// this definition suffices.
// Check whether two markers should be considered the same, for the purpose
// of pairing start and end markers. Normally this definition suffices.
virtual bool Equals(const TimelineMarker& aOther)
{
return strcmp(mName, aOther.mName) == 0;
}
// Add details specific to this marker type to aMarker. The
// standard elements have already been set. This method is
// called on both the starting and ending markers of a pair.
// Ordinarily the ending marker doesn't need to do anything
// here.
virtual void AddDetails(JSContext* aCx,
mozilla::dom::ProfileTimelineMarker& aMarker)
// Add details specific to this marker type to aMarker. The standard elements
// have already been set. This method is called on both the starting and
// ending markers of a pair. Ordinarily the ending marker doesn't need to do
// anything here.
virtual void AddDetails(JSContext* aCx, dom::ProfileTimelineMarker& aMarker)
{}
virtual void AddLayerRectangles(
mozilla::dom::Sequence<mozilla::dom::ProfileTimelineLayerRect>&)
{
MOZ_ASSERT_UNREACHABLE("can only be called on layer markers");
}
const char* GetName() const { return mName; }
TracingMetadata GetMetaData() const { return mMetaData; }
DOMHighResTimeStamp GetTime() const { return mTime; }
const nsString& GetCause() const { return mCause; }
DOMHighResTimeStamp GetTime() const { return mTime; }
TracingMetadata GetMetaData() const { return mMetaData; }
JSObject* GetStack()
{
@@ -85,15 +91,22 @@ protected:
private:
const char* mName;
TracingMetadata mMetaData;
DOMHighResTimeStamp mTime;
nsString mCause;
DOMHighResTimeStamp mTime;
TracingMetadata mMetaData;
// While normally it is not a good idea to make a persistent root,
// in this case changing nsDocShell to participate in cycle
// collection was deemed too invasive, and the markers are only held
// here temporarily to boot.
JS::PersistentRooted<JSObject*> mStackTrace;
void SetCurrentTime();
void SetCustomTime(const TimeStamp& aTime);
void CaptureStackIfNecessary(TracingMetadata aMetaData,
TimelineStackRequest aStackRequest);
};
#endif /* TimelineMarker_h_ */
} // namespace mozilla
#endif /* mozilla_TimelineMarker_h_ */
@@ -0,0 +1,32 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_TimestampTimelineMarker_h_
#define mozilla_TimestampTimelineMarker_h_
#include "TimelineMarker.h"
#include "mozilla/dom/ProfileTimelineMarkerBinding.h"
namespace mozilla {
class TimestampTimelineMarker : public TimelineMarker
{
public:
explicit TimestampTimelineMarker(const nsAString& aCause)
: TimelineMarker("TimeStamp", aCause, TRACING_TIMESTAMP)
{}
virtual void AddDetails(JSContext* aCx, dom::ProfileTimelineMarker& aMarker) override
{
if (!GetCause().IsEmpty()) {
aMarker.mCauseName.Construct(GetCause());
}
}
};
} // namespace mozilla
#endif // mozilla_TimestampTimelineMarker_h_
+8
View File
@@ -7,7 +7,15 @@
EXPORTS.mozilla += [
'AutoGlobalTimelineMarker.h',
'AutoTimelineMarker.h',
'ConsoleTimelineMarker.h',
'EventTimelineMarker.h',
'JavascriptTimelineMarker.h',
'LayerTimelineMarker.h',
'ObservedDocShell.h',
'RestyleTimelineMarker.h',
'TimelineConsumers.h',
'TimelineMarker.h',
'TimestampTimelineMarker.h',
]
UNIFIED_SOURCES += [
+7 -6
View File
@@ -569,7 +569,7 @@ Animation::CanThrottle() const
return true;
}
return mIsRunningOnCompositor;
return IsRunningOnCompositor();
}
void
@@ -764,11 +764,6 @@ Animation::DoPause(ErrorResult& aRv)
reuseReadyPromise = true;
}
// Mark this as no longer running on the compositor so that next time
// we update animations we won't throttle them and will have a chance
// to remove the animation from any layer it might be on.
mIsRunningOnCompositor = false;
if (!reuseReadyPromise) {
// Clear ready promise. We'll create a new one lazily.
mReady = nullptr;
@@ -1164,5 +1159,11 @@ Animation::DispatchPlaybackEvent(const nsAString& aName)
asyncDispatcher->PostDOMEvent();
}
bool
Animation::IsRunningOnCompositor() const
{
return mEffect && mEffect->IsRunningOnCompositor();
}
} // namespace dom
} // namespace mozilla
+1 -5
View File
@@ -58,7 +58,6 @@ public:
, mPlaybackRate(1.0)
, mPendingState(PendingState::NotPending)
, mAnimationIndex(sNextAnimationIndex++)
, mIsRunningOnCompositor(false)
, mFinishedAtLastComposeStyle(false)
, mIsRelevant(false)
, mFinishedIsResolved(false)
@@ -109,7 +108,7 @@ public:
virtual void Play(ErrorResult& aRv, LimitBehavior aLimitBehavior);
virtual void Pause(ErrorResult& aRv);
virtual void Reverse(ErrorResult& aRv);
bool IsRunningOnCompositor() const { return mIsRunningOnCompositor; }
bool IsRunningOnCompositor() const;
IMPL_EVENT_HANDLER(finish);
IMPL_EVENT_HANDLER(cancel);
@@ -269,8 +268,6 @@ public:
*/
virtual bool HasLowerCompositeOrderThan(const Animation& aOther) const;
void SetIsRunningOnCompositor() { mIsRunningOnCompositor = true; }
void ClearIsRunningOnCompositor() { mIsRunningOnCompositor = false; }
/**
* Returns true if this animation does not currently need to update
* style on the main thread (e.g. because it is empty, or is
@@ -408,7 +405,6 @@ protected:
// possible for two different objects to have the same index.
uint64_t mAnimationIndex;
bool mIsRunningOnCompositor;
bool mFinishedAtLastComposeStyle;
// Indicates that the animation should be exposed in an element's
// getAnimations() list.
+60
View File
@@ -9,6 +9,7 @@
#include "mozilla/FloatingPoint.h"
#include "AnimationCommon.h"
#include "nsCSSPropertySet.h"
#include "nsCSSProps.h" // For nsCSSProps::PropHasFlags
namespace mozilla {
@@ -74,6 +75,20 @@ NS_INTERFACE_MAP_END_INHERITING(AnimationEffectReadOnly)
NS_IMPL_ADDREF_INHERITED(KeyframeEffectReadOnly, AnimationEffectReadOnly)
NS_IMPL_RELEASE_INHERITED(KeyframeEffectReadOnly, AnimationEffectReadOnly)
KeyframeEffectReadOnly::KeyframeEffectReadOnly(
nsIDocument* aDocument,
Element* aTarget,
nsCSSPseudoElements::Type aPseudoType,
const AnimationTiming& aTiming)
: AnimationEffectReadOnly(aDocument)
, mTarget(aTarget)
, mTiming(aTiming)
, mPseudoType(aPseudoType)
{
MOZ_ASSERT(aTarget, "null animation target is not yet supported");
ResetIsRunningOnCompositor();
}
JSObject*
KeyframeEffectReadOnly::WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto)
@@ -397,5 +412,50 @@ KeyframeEffectReadOnly::ComposeStyle(nsRefPtr<AnimValuesStyleRule>& aStyleRule,
}
}
bool
KeyframeEffectReadOnly::IsRunningOnCompositor() const
{
// We consider animation is running on compositor if there is at least
// one property running on compositor.
// Animation.IsRunningOnCompotitor will return more fine grained
// information in bug 1196114.
for (bool isPropertyRunningOnCompositor : mIsPropertyRunningOnCompositor) {
if (isPropertyRunningOnCompositor) {
return true;
}
}
return false;
}
void
KeyframeEffectReadOnly::SetIsRunningOnCompositor(nsCSSProperty aProperty,
bool aIsRunning)
{
static_assert(
MOZ_ARRAY_LENGTH(LayerAnimationInfo::sRecords) ==
MOZ_ARRAY_LENGTH(mIsPropertyRunningOnCompositor),
"The length of mIsPropertyRunningOnCompositor should equal to"
"the length of LayserAnimationInfo::sRecords");
MOZ_ASSERT(nsCSSProps::PropHasFlags(aProperty,
CSS_PROPERTY_CAN_ANIMATE_ON_COMPOSITOR),
"Property being animated on compositor is a recognized "
"compositor-animatable property");
const auto& info = LayerAnimationInfo::sRecords;
for (size_t i = 0; i < ArrayLength(mIsPropertyRunningOnCompositor); i++) {
if (info[i].mProperty == aProperty) {
mIsPropertyRunningOnCompositor[i] = aIsRunning;
return;
}
}
}
void
KeyframeEffectReadOnly::ResetIsRunningOnCompositor()
{
for (bool& isPropertyRunningOnCompositor : mIsPropertyRunningOnCompositor) {
isPropertyRunningOnCompositor = false;
}
}
} // namespace dom
} // namespace mozilla
+16 -8
View File
@@ -13,6 +13,7 @@
#include "nsIDocument.h"
#include "nsWrapperCache.h"
#include "mozilla/Attributes.h"
#include "mozilla/LayerAnimationInfo.h" // LayerAnimations::kRecords
#include "mozilla/StickyTimeDuration.h"
#include "mozilla/StyleAnimationValue.h"
#include "mozilla/TimeStamp.h"
@@ -192,14 +193,7 @@ public:
KeyframeEffectReadOnly(nsIDocument* aDocument,
Element* aTarget,
nsCSSPseudoElements::Type aPseudoType,
const AnimationTiming &aTiming)
: AnimationEffectReadOnly(aDocument)
, mTarget(aTarget)
, mTiming(aTiming)
, mPseudoType(aPseudoType)
{
MOZ_ASSERT(aTarget, "null animation target is not yet supported");
}
const AnimationTiming& aTiming);
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(KeyframeEffectReadOnly,
@@ -309,9 +303,12 @@ public:
// Any updated properties are added to |aSetProperties|.
void ComposeStyle(nsRefPtr<AnimValuesStyleRule>& aStyleRule,
nsCSSPropertySet& aSetProperties);
bool IsRunningOnCompositor() const;
void SetIsRunningOnCompositor(nsCSSProperty aProperty, bool aIsRunning);
protected:
virtual ~KeyframeEffectReadOnly() { }
void ResetIsRunningOnCompositor();
nsCOMPtr<Element> mTarget;
Nullable<TimeDuration> mParentTime;
@@ -320,6 +317,17 @@ protected:
nsCSSPseudoElements::Type mPseudoType;
InfallibleTArray<AnimationProperty> mProperties;
// Parallel array corresponding to CommonAnimationManager::sLayerAnimationInfo
// such that mIsPropertyRunningOnCompositor[x] is true only if this effect has
// an animation of CommonAnimationManager::sLayerAnimationInfo[x].mProperty
// that is currently running on the compositor.
//
// Note that when the owning Animation requests a non-throttled restyle, in
// between calling RequestRestyle on its AnimationCollection and when the
// restyle is performed, this member may temporarily become false even if
// the animation remains on the layer after the restyle.
bool mIsPropertyRunningOnCompositor[LayerAnimationInfo::kRecords];
};
} // namespace dom
+6 -1
View File
@@ -1,3 +1,8 @@
[DEFAULT]
support-files =
testcommon.js
../../imptests/testharness.js
../../imptests/testharnessreport.js
[chrome/test_animation_observers.html]
[chrome/test_running_on_compositor.html]
skip-if = buildapp == 'b2g'
skip-if = buildapp == 'b2g'
@@ -3,17 +3,24 @@
<meta charset=utf-8>
<title>Bug 1045994 - Add a chrome-only property to inspect if an animation is
running on the compositor or not</title>
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css"
href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
<script type="application/javascript" src="../testharness.js"></script>
<script type="application/javascript" src="../testharnessreport.js"></script>
<script type="application/javascript" src="../testcommon.js"></script>
<style>
@keyframes anim {
to { transform: translate(100px) }
}
.target {
@keyframes background_and_translate {
to { background-color: red; transform: translate(100px); }
}
@keyframes background {
to { background-color: red; }
}
@keyframes rotate {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
div {
/* Element needs geometry to be eligible for layerization */
width: 100px;
height: 100px;
@@ -24,42 +31,241 @@
<body>
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1045994"
target="_blank">Mozilla Bug 1045994</a>
<div class="target"></div>
<div id="log"></div>
<script>
'use strict';
/** Test for bug 1045994 - Add a chrome-only property to inspect if an
animation is running on the compositor or not **/
SimpleTest.waitForExplicitFinish();
var div = document.querySelector('div.target');
const OMTAPrefKey = 'layers.offmainthreadcomposition.async-animations';
var omtaEnabled = SpecialPowers.DOMWindowUtils.layerManagerRemote &&
SpecialPowers.getBoolPref(OMTAPrefKey);
// FIXME: When we implement Element.animate, use that here instead of CSS
// so that we remove any dependency on the CSS mapping.
div.style.animation = 'anim 100s';
var animation = div.getAnimations()[0];
promise_test(function(t) {
// FIXME: When we implement Element.animate, use that here instead of CSS
// so that we remove any dependency on the CSS mapping.
var div = addDiv(t, { style: 'animation: anim 100s' });
var animation = div.getAnimations()[0];
animation.ready.then(function() {
is(animation.isRunningOnCompositor, omtaEnabled,
'Animation reports that it is running on the compositor'
+ ' during playback');
return animation.ready.then(t.step_func(function() {
assert_equals(animation.isRunningOnCompositor, omtaEnabled,
'Animation reports that it is running on the compositor'
+ ' during playback');
div.style.animationPlayState = 'paused';
window.getComputedStyle(div).animationPlayState;
div.style.animationPlayState = 'paused';
// FIXME: When we implement deferred pausing (bug 1109390), we should wait
// on animation.ready here.
window.requestAnimationFrame(function() {
is(animation.isRunningOnCompositor, false,
return animation.ready;
})).then(t.step_func(function() {
assert_equals(animation.isRunningOnCompositor, false,
'Animation reports that it is NOT running on the compositor'
+ ' when paused');
SimpleTest.finish();
});
});
}));
}, '');
promise_test(function(t) {
var div = addDiv(t, { style: 'animation: background 100s' });
var animation = div.getAnimations()[0];
return animation.ready.then(t.step_func(function() {
assert_equals(animation.isRunningOnCompositor, false,
'Animation reports that it is NOT running on the compositor'
+ ' for animation of "background"');
}));
}, 'isRunningOnCompositor is false for animation of "background"');
promise_test(function(t) {
var div = addDiv(t, { style: 'animation: background_and_translate 100s' });
var animation = div.getAnimations()[0];
return animation.ready.then(t.step_func(function() {
assert_equals(animation.isRunningOnCompositor, omtaEnabled,
'Animation reports that it is running on the compositor'
+ ' when the animation has two properties, where one can run'
+ ' on the compositor, the other cannot');
}));
}, 'isRunningOnCompositor is true if the animation has at least one ' +
'property can run on compositor');
promise_test(function(t) {
var div = addDiv(t, { style: 'animation: anim 100s' });
var animation = div.getAnimations()[0];
return animation.ready.then(t.step_func(function() {
animation.pause();
return animation.ready;
})).then(t.step_func(function() {
assert_equals(animation.isRunningOnCompositor, false,
'Animation reports that it is NOT running on the compositor'
+ ' when animation.pause() is called');
}));
}, 'isRunningOnCompositor is false when the animation.pause() is called');
promise_test(function(t) {
var div = addDiv(t, { style: 'animation: anim 100s' });
var animation = div.getAnimations()[0];
return animation.ready.then(t.step_func(function() {
animation.finish();
// We need to wait for two frames here to ensure isRunningOnCompositor
// flag is cleared. The first frame is for waking root refresh driver up,
// the second one is for clearing the flag.
// In most cases root refresh driver has been dormant because there is
// nothing to do for the root refresh driver (e.g. nothing change on
// chrome window). In the first frame document's refresh driver wakes the
// root refresh driver up as a result of animation's style changes.
// In the second frame the root refresh driver clears the flag as a
// result of a paint.
return waitForAnimationFrames(2);
})).then(t.step_func(function() {
assert_equals(animation.isRunningOnCompositor, false,
'Animation reports that it is NOT running on the compositor'
+ ' when animation.finish() is called');
}));
}, 'isRunningOnCompositor is false when the animation.finish() is called');
promise_test(function(t) {
var div = addDiv(t, { style: 'animation: anim 100s' });
var animation = div.getAnimations()[0];
return animation.ready.then(t.step_func(function() {
animation.currentTime = 100000; // 100s
// We need to wait for up to two frames here to ensure the "is running on
// compositor" flag is cleared.
// See the description in the 'isRunningOnCompositor is false when the
// animation.finish() is called' test for the rationale.
return waitForAnimationFrames(2);
})).then(t.step_func(function() {
assert_equals(animation.isRunningOnCompositor, false,
'Animation reports that it is NOT running on the compositor'
+ ' when manually seeking the animation to the end');
}));
}, 'isRunningOnCompositor is false when manually seeking the animation to ' +
'the end');
promise_test(function(t) {
var div = addDiv(t, { style: 'animation: anim 100s' });
var animation = div.getAnimations()[0];
return animation.ready.then(t.step_func(function() {
animation.cancel();
// We need to wait for up to two frames here to ensure the "is running on
// compositor" flag is cleared.
// See the description in the 'isRunningOnCompositor is false when the
// animation.finish() is called' test for the rationale.
return waitForAnimationFrames(2);
})).then(t.step_func(function() {
assert_equals(animation.isRunningOnCompositor, false,
'Animation reports that it is NOT running on the compositor'
+ ' when animation.cancel() is called');
}));
}, 'isRunningOnCompositor is false when animation.cancel() is called');
promise_test(function(t) {
var div = addDiv(t, { style: 'animation: anim 100s 100s' });
var animation = div.getAnimations()[0];
return animation.ready.then(t.step_func(function() {
assert_equals(animation.isRunningOnCompositor, false,
'Animation reports that it is NOT running on the compositor'
+ ' while in the delay phase');
}));
}, 'isRunningOnCompositor is false while in the delay phase');
// This is to test that we don't simply clobber the flag when ticking
// animations and then set it again during painting.
promise_test(function(t) {
var div = addDiv(t, { style: 'animation: anim 100s' });
var animation = div.getAnimations()[0];
return animation.ready.then(t.step_func(function() {
return new Promise(t.step_func(function(resolve) {
window.requestAnimationFrame(t.step_func(function() {
assert_equals(animation.isRunningOnCompositor, omtaEnabled,
'Animation reports that it is running on the compositor'
+ ' in requestAnimationFrame callback');
resolve();
}));
}));
}));
}, 'isRunningOnCompositor is true in requestAnimationFrame callback');
promise_test(function(t) {
var div = addDiv(t, { style: 'animation: anim 100s' });
var animation = div.getAnimations()[0];
return animation.ready.then(t.step_func(function() {
return new Promise(t.step_func(function(resolve) {
var observer = new MutationObserver(t.step_func(function(records) {
var changedAnimation;
records.forEach(function(record) {
changedAnimation =
record.changedAnimations.find(function(changedAnim) {
return changedAnim == animation;
});
});
assert_true(!!changedAnimation, 'The animation should be recorded '
+ 'as one of the changedAnimations');
assert_equals(animation.isRunningOnCompositor, omtaEnabled,
'Animation reports that it is running on the compositor'
+ ' in MutationObserver callback');
resolve();
}));
observer.observe(div, { animations: true, subtree: false });
div.style.animationDuration = "200s";
}));
}));
}, 'isRunningOnCompositor is true in MutationObserver callback');
// This is to test that we don't temporarily clear the flag when forcing
// an unthrottled sample.
promise_test(function(t) {
return new Promise(function(resolve) {
// Needs scrollbars to cause overflow.
SpecialPowers.pushPrefEnv({ set: [["ui.showHideScrollbars", 1]] },
resolve);
}).then(t.step_func(function() {
var div = addDiv(t, { style: 'animation: rotate 100s' });
var animation = div.getAnimations()[0];
return animation.ready.then(t.step_func(function() {
return new Promise(t.step_func(function(resolve) {
var timeAtStart = window.performance.now();
function handleFrame() {
assert_equals(animation.isRunningOnCompositor, omtaEnabled,
'Animation reports that it is running on the compositor'
+ ' in requestAnimationFrame callback');
// we have to wait at least 200ms because this animation is
// unthrottled on every 200ms.
// See http://hg.mozilla.org/mozilla-central/file/cafb1c90f794/layout/style/AnimationCommon.cpp#l863
if (window.performance.now() - timeAtStart > 200) {
resolve();
return;
}
window.requestAnimationFrame(handleFrame);
}
window.requestAnimationFrame(handleFrame);
}));
}));
}));
}, 'isRunningOnCompositor remains true in requestAnimationFrameCallback for ' +
'overflow animation');
promise_test(function(t) {
var div = addDiv(t, { style: 'transition: opacity 100s; opacity: 1' });
getComputedStyle(div).opacity;
div.style.opacity = 0;
var animation = div.getAnimations()[0];
return animation.ready.then(t.step_func(function() {
assert_equals(animation.isRunningOnCompositor, omtaEnabled,
'Transition reports that it is running on the compositor'
+ ' during playback for opacity transition');
}));
}, 'isRunningOnCompositor for transitions');
</script>
</body>
+16 -13
View File
@@ -60,19 +60,22 @@ function flushComputedStyle(elem) {
cs.marginLeft;
}
for (var funcName of ["async_test", "assert_not_equals", "assert_equals",
"assert_approx_equals", "assert_less_than",
"assert_less_than_equal", "assert_between_inclusive",
"assert_true", "assert_false",
"assert_class_string", "assert_throws", "test"]) {
window[funcName] = opener[funcName].bind(opener);
}
if (opener) {
for (var funcName of ["async_test", "assert_not_equals", "assert_equals",
"assert_approx_equals", "assert_less_than",
"assert_less_than_equal", "assert_between_inclusive",
"assert_true", "assert_false",
"assert_class_string", "assert_throws",
"assert_unreached", "test"]) {
window[funcName] = opener[funcName].bind(opener);
}
window.EventWatcher = opener.EventWatcher;
window.EventWatcher = opener.EventWatcher;
function done() {
opener.add_completion_callback(function() {
self.close();
});
opener.done();
function done() {
opener.add_completion_callback(function() {
self.close();
});
opener.done();
}
}
+6 -59
View File
@@ -26,6 +26,8 @@
#include "nsContentUtils.h"
#include "nsDocShell.h"
#include "nsProxyRelease.h"
#include "mozilla/ConsoleTimelineMarker.h"
#include "mozilla/TimestampTimelineMarker.h"
#include "nsIConsoleAPIStorage.h"
#include "nsIDOMWindowUtils.h"
@@ -983,59 +985,6 @@ ReifyStack(nsIStackFrame* aStack, nsTArray<ConsoleStackEntry>& aRefiedStack)
return NS_OK;
}
class ConsoleTimelineMarker : public TimelineMarker
{
public:
ConsoleTimelineMarker(nsDocShell* aDocShell,
TracingMetadata aMetaData,
const nsAString& aCause)
: TimelineMarker(aDocShell, "ConsoleTime", aMetaData, aCause)
{
if (aMetaData == TRACING_INTERVAL_END) {
CaptureStack();
}
}
virtual bool Equals(const TimelineMarker& aOther) override
{
if (!TimelineMarker::Equals(aOther)) {
return false;
}
// Console markers must have matching causes as well.
return GetCause() == aOther.GetCause();
}
virtual void AddDetails(JSContext* aCx,
mozilla::dom::ProfileTimelineMarker& aMarker) override
{
if (GetMetaData() == TRACING_INTERVAL_START) {
aMarker.mCauseName.Construct(GetCause());
} else {
aMarker.mEndStack = GetStack();
}
}
};
class TimestampTimelineMarker : public TimelineMarker
{
public:
TimestampTimelineMarker(nsDocShell* aDocShell,
TracingMetadata aMetaData,
const nsAString& aCause)
: TimelineMarker(aDocShell, "TimeStamp", aMetaData, aCause)
{
MOZ_ASSERT(aMetaData == TRACING_TIMESTAMP);
}
virtual void AddDetails(JSContext* aCx,
mozilla::dom::ProfileTimelineMarker& aMarker) override
{
if (!GetCause().IsEmpty()) {
aMarker.mCauseName.Construct(GetCause());
}
}
};
// Queue a call to a console method. See the CALL_DELAY constant.
void
Console::Method(JSContext* aCx, MethodName aMethodName,
@@ -1142,8 +1091,7 @@ Console::Method(JSContext* aCx, MethodName aMethodName,
key.init(aCx, jsString);
}
mozilla::UniquePtr<TimelineMarker> marker =
MakeUnique<TimestampTimelineMarker>(docShell, TRACING_TIMESTAMP, key);
UniquePtr<TimelineMarker> marker = MakeUnique<TimestampTimelineMarker>(key);
TimelineConsumers::AddMarkerForDocShell(docShell, Move(marker));
}
// For `console.time(foo)` and `console.timeEnd(foo)`
@@ -1153,10 +1101,9 @@ Console::Method(JSContext* aCx, MethodName aMethodName,
if (jsString) {
nsAutoJSString key;
if (key.init(aCx, jsString)) {
mozilla::UniquePtr<TimelineMarker> marker =
MakeUnique<ConsoleTimelineMarker>(docShell,
aMethodName == MethodTime ? TRACING_INTERVAL_START : TRACING_INTERVAL_END,
key);
UniquePtr<TimelineMarker> marker = MakeUnique<ConsoleTimelineMarker>(
key, aMethodName == MethodTime ? TRACING_INTERVAL_START
: TRACING_INTERVAL_END);
TimelineConsumers::AddMarkerForDocShell(docShell, Move(marker));
}
}
+3 -26
View File
@@ -24,6 +24,7 @@
#include "mozilla/dom/Element.h"
#include "mozilla/dom/Event.h"
#include "mozilla/TimelineConsumers.h"
#include "mozilla/EventTimelineMarker.h"
#include "EventListenerService.h"
#include "nsCOMArray.h"
@@ -1063,29 +1064,6 @@ EventListenerManager::GetDocShellForTarget()
return docShell;
}
class EventTimelineMarker : public TimelineMarker
{
public:
EventTimelineMarker(nsDocShell* aDocShell, TracingMetadata aMetaData,
uint16_t aPhase, const nsAString& aCause)
: TimelineMarker(aDocShell, "DOMEvent", aMetaData, aCause)
, mPhase(aPhase)
{
}
virtual void AddDetails(JSContext* aCx,
mozilla::dom::ProfileTimelineMarker& aMarker) override
{
if (GetMetaData() == TRACING_INTERVAL_START) {
aMarker.mType.Construct(GetCause());
aMarker.mEventPhase.Construct(mPhase);
}
}
private:
uint16_t mPhase;
};
/**
* Causes a check for event listeners and processing by them if they exist.
* @param an event listener
@@ -1156,9 +1134,8 @@ EventListenerManager::HandleEventInternal(nsPresContext* aPresContext,
(*aDOMEvent)->GetType(typeStr);
uint16_t phase;
(*aDOMEvent)->GetEventPhase(&phase);
mozilla::UniquePtr<TimelineMarker> marker =
MakeUnique<EventTimelineMarker>(ds, TRACING_INTERVAL_START,
phase, typeStr);
UniquePtr<TimelineMarker> marker = MakeUnique<EventTimelineMarker>(
typeStr, phase, TRACING_INTERVAL_START);
TimelineConsumers::AddMarkerForDocShell(ds, Move(marker));
}
}
@@ -185,9 +185,8 @@
"Command insertHorizontalRule, value \"id\": input event, canceled":true,
"Command insertHorizontalRule, value \"id\": beforeinput event, uncanceled":true,
"Command insertHorizontalRule, value \"id\": input event, uncanceled":true,
"Command insertHTML, value \"\": execCommand() must not throw, canceled":true,
"Command insertHTML, value \"\": beforeinput event, canceled":true,
"Command insertHTML, value \"\": execCommand() must not throw, uncanceled":true,
"Command insertHTML, value \"\": input event, canceled":true,
"Command insertHTML, value \"\": beforeinput event, uncanceled":true,
"Command insertHTML, value \"\": input event, uncanceled":true,
"Command insertHTML, value \"quasit\": beforeinput event, canceled":true,
@@ -3801,9 +3801,6 @@
"[[\"inserthtml\",\"<!--abc-->\"]] \"<p><br>{}</p>\" compare innerHTML":true,
"[[\"inserthtml\",\"<!--abc-->\"]] \"<p><!--foo--><span><br></span>{}<!--bar--></p>\" compare innerHTML":true,
"[[\"inserthtml\",\"<!--abc-->\"]] \"<p><span><!--foo--><br><!--bar--></span>{}</p>\" compare innerHTML":true,
"[[\"inserthtml\",\"\"]] \"foo[bar]baz\": execCommand(\"inserthtml\", false, \"\") return value":true,
"[[\"inserthtml\",\"\"]] \"foo[bar]baz\" compare innerHTML":true,
"[[\"inserthtml\",\"\\u0000\"]] \"foo[bar]baz\" compare innerHTML":true,
"[[\"stylewithcss\",\"true\"],[\"inserthtml\",\"<b>\"]] \"foo[bar]baz\" compare innerHTML":true,
"[[\"stylewithcss\",\"false\"],[\"inserthtml\",\"<b>\"]] \"foo[bar]baz\" compare innerHTML":true,
"[[\"defaultparagraphseparator\",\"div\"],[\"inserthtml\",\"<p>abc\"]] \"<p>foo[bar]baz\": execCommand(\"defaultparagraphseparator\", false, \"div\") return value":true,
-7
View File
@@ -2500,15 +2500,8 @@ ContentParent::InitInternal(ProcessPriority aInitialPriority,
DebugOnly<bool> opened = PCompositor::Open(this);
MOZ_ASSERT(opened);
#ifndef MOZ_WIDGET_GONK
if (gfxPrefs::AsyncVideoOOPEnabled()) {
opened = PImageBridge::Open(this);
MOZ_ASSERT(opened);
}
#else
opened = PImageBridge::Open(this);
MOZ_ASSERT(opened);
#endif
}
#ifdef MOZ_WIDGET_GONK
DebugOnly<bool> opened = PSharedBufferManager::Open(this);
+2 -2
View File
@@ -675,10 +675,10 @@ HangMonitoredProcess::GetHangType(uint32_t* aHangType)
*aHangType = PLUGIN_HANG;
break;
default:
MOZ_ASSERT(false);
MOZ_ASSERT_UNREACHABLE("Unexpected HangData type");
return NS_ERROR_UNEXPECTED;
break;
}
return NS_OK;
}
+4
View File
@@ -169,6 +169,10 @@ ScreenManagerParent::RecvScreenForBrowser(const TabId& aTabId,
bool
ScreenManagerParent::ExtractScreenDetails(nsIScreen* aScreen, ScreenDetails &aDetails)
{
if (!aScreen) {
return false;
}
uint32_t id;
nsresult rv = aScreen->GetId(&id);
NS_ENSURE_SUCCESS(rv, false);
+5 -3
View File
@@ -2928,7 +2928,9 @@ TabChild::GetFrom(uint64_t aLayersId)
}
void
TabChild::DidComposite(uint64_t aTransactionId)
TabChild::DidComposite(uint64_t aTransactionId,
const TimeStamp& aCompositeStart,
const TimeStamp& aCompositeEnd)
{
MOZ_ASSERT(mPuppetWidget);
MOZ_ASSERT(mPuppetWidget->GetLayerManager());
@@ -2937,8 +2939,8 @@ TabChild::DidComposite(uint64_t aTransactionId)
nsRefPtr<ClientLayerManager> manager =
static_cast<ClientLayerManager*>(mPuppetWidget->GetLayerManager());
manager->DidComposite(aTransactionId);
manager->DidComposite(aTransactionId, aCompositeStart, aCompositeEnd);
}
void
+4 -1
View File
@@ -460,7 +460,10 @@ public:
static TabChild* GetFrom(nsIPresShell* aPresShell);
static TabChild* GetFrom(uint64_t aLayersId);
void DidComposite(uint64_t aTransactionId);
void DidComposite(uint64_t aTransactionId,
const TimeStamp& aCompositeStart,
const TimeStamp& aCompositeEnd);
void ClearCachedResources();
static inline TabChild*
@@ -39,23 +39,6 @@ MediaSystemResourceManager::Shutdown()
}
}
/* static */ bool
MediaSystemResourceManager::IsMediaSystemResourceManagerEnabled()
{
#ifdef MOZ_WIDGET_GONK
return true;
#else
// XXX MediaSystemResourceManager is enabled only when ImageBridge is enabled.
// MediaSystemResourceManager uses ImageBridge's thread.
if (gfxPrefs::AsyncVideoOOPEnabled() &&
gfxPrefs::AsyncVideoEnabled()) {
return true;
} else {
return false;
}
#endif
}
class RunnableCallTask : public Task
{
public:
@@ -73,7 +56,6 @@ protected:
/* static */ void
MediaSystemResourceManager::Init()
{
MOZ_ASSERT(IsMediaSystemResourceManagerEnabled());
if (!ImageBridgeChild::IsCreated()) {
NS_WARNING("ImageBridge does not exist");
return;
@@ -57,8 +57,6 @@ private:
MediaSystemResourceManager();
virtual ~MediaSystemResourceManager();
static bool IsMediaSystemResourceManagerEnabled();
void OpenIPC();
void CloseIPC();
bool IsIpcClosed();
-1
View File
@@ -2678,7 +2678,6 @@ _getvalueforurl(NPP instance, NPNURLVariable variable, const char *url,
return NPERR_NO_ERROR;
}
break;
default:
// Fall through and return an error...
;
-1
View File
@@ -3471,7 +3471,6 @@ nsPluginHost::AddHeadersToChannel(const char *aHeadersData,
return rv;
}
}
return rv;
}
nsresult
+37 -21
View File
@@ -104,18 +104,14 @@ struct RunnableMethodTraits<PluginInstanceChild>
static RefPtr<DrawTarget>
CreateDrawTargetForSurface(gfxASurface *aSurface)
{
SurfaceFormat format;
if (aSurface->GetContentType() == gfxContentType::ALPHA) {
format = SurfaceFormat::A8;
} else if (aSurface->GetContentType() == gfxContentType::COLOR) {
format = SurfaceFormat::B8G8R8X8;
} else {
format = SurfaceFormat::B8G8R8A8;
}
SurfaceFormat format = aSurface->GetSurfaceFormat();
RefPtr<DrawTarget> drawTarget =
Factory::CreateDrawTargetForCairoSurface(aSurface->CairoSurface(),
aSurface->GetSize(),
&format);
if (!drawTarget) {
NS_RUNTIMEABORT("CreateDrawTargetForSurface failed in plugin");
}
aSurface->SetData(&kDrawTarget, drawTarget, nullptr);
return drawTarget;
}
@@ -2547,11 +2543,7 @@ PluginInstanceChild::RecvAsyncNPP_NewStream(PBrowserStreamChild* actor,
BrowserStreamChild* child = static_cast<BrowserStreamChild*>(actor);
NewStreamAsyncCall* task = new NewStreamAsyncCall(this, child, mimeType,
seekable);
{
MutexAutoLock lock(mAsyncCallMutex);
mPendingAsyncCalls.AppendElement(task);
}
MessageLoop::current()->PostTask(FROM_HERE, task);
PostChildAsyncCall(task);
return true;
}
@@ -3259,11 +3251,28 @@ PluginInstanceChild::PaintRectToSurface(const nsIntRect& aRect,
PaintRectToPlatformSurface(plPaintRect, renderSurface);
if (renderSurface != aSurface) {
RefPtr<DrawTarget> dt;
if (aSurface == mCurrentSurface &&
aSurface->GetType() == gfxSurfaceType::Image &&
aSurface->GetSurfaceFormat() == SurfaceFormat::B8G8R8X8) {
gfxImageSurface* imageSurface = static_cast<gfxImageSurface*>(aSurface);
// Bug 1196927 - Reinterpret target surface as BGRA to fill alpha with opaque.
// Certain backends (i.e. Skia) may not truly support BGRX formats, so they must
// be emulated by filling the alpha channel opaque as if it was BGRA data. Cairo
// leaves the alpha zeroed out for BGRX, so we cause Cairo to fill it as opaque
// by handling the copy target as a BGRA surface.
dt = Factory::CreateDrawTargetForData(BackendType::CAIRO,
imageSurface->Data(),
imageSurface->GetSize(),
imageSurface->Stride(),
SurfaceFormat::B8G8R8A8);
} else {
// Copy helper surface content to target
RefPtr<DrawTarget> dt = CreateDrawTargetForSurface(aSurface);
RefPtr<SourceSurface> surface =
gfxPlatform::GetSourceSurfaceForSurface(dt, renderSurface);
dt->CopySurface(surface, aRect, aRect.TopLeft());
dt = CreateDrawTargetForSurface(aSurface);
}
RefPtr<SourceSurface> surface =
gfxPlatform::GetSourceSurfaceForSurface(dt, renderSurface);
dt->CopySurface(surface, aRect, aRect.TopLeft());
}
}
@@ -3612,10 +3621,9 @@ PluginInstanceChild::ReadbackDifferenceRect(const nsIntRect& rect)
#elif defined(XP_WIN)
if (!SharedDIBSurface::IsSharedDIBSurface(mBackSurface))
return false;
#else
return false;
#endif
#if defined(MOZ_X11) || defined(XP_WIN)
if (mCurrentSurface->GetContentType() != mBackSurface->GetContentType())
return false;
@@ -3641,6 +3649,9 @@ PluginInstanceChild::ReadbackDifferenceRect(const nsIntRect& rect)
}
return true;
#else
return false;
#endif
}
void
@@ -3821,12 +3832,17 @@ void
PluginInstanceChild::AsyncCall(PluginThreadCallback aFunc, void* aUserData)
{
ChildAsyncCall* task = new ChildAsyncCall(this, aFunc, aUserData);
PostChildAsyncCall(task);
}
void
PluginInstanceChild::PostChildAsyncCall(ChildAsyncCall* aTask)
{
{
MutexAutoLock lock(mAsyncCallMutex);
mPendingAsyncCalls.AppendElement(task);
mPendingAsyncCalls.AppendElement(aTask);
}
ProcessChild::message_loop()->PostTask(FROM_HERE, task);
ProcessChild::message_loop()->PostTask(FROM_HERE, aTask);
}
void
+2
View File
@@ -254,6 +254,8 @@ public:
void UnscheduleTimer(uint32_t id);
void AsyncCall(PluginThreadCallback aFunc, void* aUserData);
// This function is a more general version of AsyncCall
void PostChildAsyncCall(ChildAsyncCall* aTask);
int GetQuirks();
+22 -1
View File
@@ -2150,6 +2150,26 @@ PluginModuleChild::AnswerSyncNPP_New(PPluginInstanceChild* aActor, NPError* rv)
return true;
}
class AsyncNewResultSender : public ChildAsyncCall
{
public:
AsyncNewResultSender(PluginInstanceChild* aInstance, NPError aResult)
: ChildAsyncCall(aInstance, nullptr, nullptr)
, mResult(aResult)
{
}
void Run() override
{
RemoveFromAsyncList();
DebugOnly<bool> sendOk = mInstance->SendAsyncNPP_NewResult(mResult);
MOZ_ASSERT(sendOk);
}
private:
NPError mResult;
};
bool
PluginModuleChild::RecvAsyncNPP_New(PPluginInstanceChild* aActor)
{
@@ -2158,7 +2178,8 @@ PluginModuleChild::RecvAsyncNPP_New(PPluginInstanceChild* aActor)
reinterpret_cast<PluginInstanceChild*>(aActor);
AssertPluginThread();
NPError rv = childInstance->DoNPP_New();
childInstance->SendAsyncNPP_NewResult(rv);
AsyncNewResultSender* task = new AsyncNewResultSender(childInstance, rv);
childInstance->PostChildAsyncCall(task);
return true;
}
+10 -5
View File
@@ -1311,7 +1311,15 @@ nsInsertHTMLCommand::IsCommandEnabled(const char * aCommandName,
NS_IMETHODIMP
nsInsertHTMLCommand::DoCommand(const char *aCommandName, nsISupports *refCon)
{
return NS_ERROR_NOT_IMPLEMENTED;
// If nsInsertHTMLCommand is called with no parameters, it was probably called with
// an empty string parameter ''. In this case, it should act the same as the delete command
NS_ENSURE_ARG_POINTER(refCon);
nsCOMPtr<nsIHTMLEditor> editor = do_QueryInterface(refCon);
NS_ENSURE_TRUE(editor, NS_ERROR_NOT_IMPLEMENTED);
nsString html = EmptyString();
return editor->InsertHTML(html);
}
NS_IMETHODIMP
@@ -1330,10 +1338,7 @@ nsInsertHTMLCommand::DoCommandParams(const char *aCommandName,
nsresult rv = aParams->GetStringValue(STATE_DATA, html);
NS_ENSURE_SUCCESS(rv, rv);
if (!html.IsEmpty())
return editor->InsertHTML(html);
return NS_OK;
return editor->InsertHTML(html);
}
NS_IMETHODIMP
+199 -123
View File
@@ -590,8 +590,8 @@ nsEditorSpellCheck::SetCurrentDictionary(const nsAString& aDictionary)
// The purpose of mUpdateDictionaryRunning is to avoid doing all of this if
// UpdateCurrentDictionary's helper method DictionaryFetched, which calls us,
// is on the stack (meaning: only do this if the user manually selected a
// dictionary to use)
// is on the stack. In other words: Only do this, if the user manually selected a
// dictionary to use.
if (!mUpdateDictionaryRunning) {
// Ignore pending dictionary fetchers by increasing this number.
@@ -600,51 +600,42 @@ nsEditorSpellCheck::SetCurrentDictionary(const nsAString& aDictionary)
uint32_t flags = 0;
mEditor->GetFlags(&flags);
if (!(flags & nsIPlaintextEditor::eEditorMailMask)) {
if (mPreferredLang.IsEmpty() ||
!mPreferredLang.Equals(aDictionary, nsCaseInsensitiveStringComparator())) {
if (!aDictionary.IsEmpty() && (mPreferredLang.IsEmpty() ||
!mPreferredLang.Equals(aDictionary,
nsCaseInsensitiveStringComparator()))) {
// When user sets dictionary manually, we store this value associated
// with editor url.
// with editor url, if it doesn't match the document language exactly.
// For example on "en" sites, we need to store "en-GB", otherwise
// the language might jump back to en-US although the user explicitly
// chose otherwise.
StoreCurrentDictionary(mEditor, aDictionary);
#ifdef DEBUG_DICT
printf("***** Writing content preferences for |%s|\n",
NS_ConvertUTF16toUTF8(aDictionary).get());
#endif
} else {
// If user sets a dictionary matching (even partially), lang defined by
// If user sets a dictionary matching the language defined by
// document, we consider content pref has been canceled, and we clear it.
ClearCurrentDictionary(mEditor);
#ifdef DEBUG_DICT
printf("***** Clearing content preferences for |%s|\n",
NS_ConvertUTF16toUTF8(aDictionary).get());
#endif
}
// Also store it in as a preference. It will be used as a default value
// when everything else fails but we don't want this for mail composer
// because it has spellchecked dictionary settings in Preferences.
// Also store it in as a preference, so we can use it as a fallback.
// We don't want this for mail composer because it uses
// "spellchecker.dictionary" as a preference.
Preferences::SetString("spellchecker.dictionary", aDictionary);
#ifdef DEBUG_DICT
printf("***** Storing spellchecker.dictionary |%s|\n",
NS_ConvertUTF16toUTF8(aDictionary).get());
#endif
}
}
return mSpellChecker->SetCurrentDictionary(aDictionary);
}
NS_IMETHODIMP
nsEditorSpellCheck::CheckCurrentDictionary()
{
mSpellChecker->CheckCurrentDictionary();
// Check if our current dictionary is still available.
nsAutoString currentDictionary;
nsresult rv = GetCurrentDictionary(currentDictionary);
if (NS_SUCCEEDED(rv) && !currentDictionary.IsEmpty()) {
return NS_OK;
}
// If our preferred current dictionary has gone, pick another one.
nsTArray<nsString> dictList;
rv = mSpellChecker->GetDictionaryList(&dictList);
NS_ENSURE_SUCCESS(rv, rv);
if (dictList.Length() > 0) {
rv = SetCurrentDictionary(dictList[0]);
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
}
NS_IMETHODIMP
nsEditorSpellCheck::UninitSpellChecker()
{
@@ -704,7 +695,10 @@ nsEditorSpellCheck::UpdateCurrentDictionary(nsIEditorSpellCheckCallback* aCallba
rootContent = do_QueryInterface(parentDoc->GetDocumentElement());
}
}
NS_ENSURE_TRUE(rootContent, NS_ERROR_FAILURE);
if (!rootContent) {
return NS_ERROR_FAILURE;
}
nsRefPtr<DictionaryFetcher> fetcher =
new DictionaryFetcher(this, aCallback, mDictionaryFetcherGroup);
@@ -719,6 +713,44 @@ nsEditorSpellCheck::UpdateCurrentDictionary(nsIEditorSpellCheckCallback* aCallba
return NS_OK;
}
// Helper function that iterates over the list of dictionaries and sets the one
// that matches based on a given comparison type.
nsresult
nsEditorSpellCheck::TryDictionary(const nsAString& aDictName,
nsTArray<nsString>& aDictList,
enum dictCompare aCompareType)
{
nsresult rv = NS_ERROR_NOT_AVAILABLE;
for (uint32_t i = 0; i < aDictList.Length(); i++) {
nsAutoString dictStr(aDictList.ElementAt(i));
bool equals = false;
switch (aCompareType) {
case DICT_NORMAL_COMPARE:
equals = aDictName.Equals(dictStr);
break;
case DICT_COMPARE_CASE_INSENSITIVE:
equals = aDictName.Equals(dictStr, nsCaseInsensitiveStringComparator());
break;
case DICT_COMPARE_DASHMATCH:
equals = nsStyleUtil::DashMatchCompare(dictStr, aDictName, nsCaseInsensitiveStringComparator());
break;
}
if (equals) {
rv = mSpellChecker->SetCurrentDictionary(dictStr);
#ifdef DEBUG_DICT
if (NS_SUCCEEDED(rv))
printf("***** Set |%s|.\n", NS_ConvertUTF16toUTF8(dictStr).get());
#endif
// We always break here. We tried to set the dictionary to an existing
// dictionary from the list. This must work, if it doesn't, there is
// no point trying another one.
break;
}
}
return rv;
}
nsresult
nsEditorSpellCheck::DictionaryFetched(DictionaryFetcher* aFetcher)
{
@@ -738,16 +770,23 @@ nsEditorSpellCheck::DictionaryFetched(DictionaryFetcher* aFetcher)
/*
* We try to derive the dictionary to use based on the following priorities:
* 1) Content preference: the language the user set for the site before.
* 2) The value of "spellchecker.dictionary.override" which reflects a
* global choice of language explicitly set by the user.
* 3) Language set by the website, or any other dictionary that partly matches that.
* Eg. if the website is "en-GB", a user who only has "en-US" will get that.
* If the website is generic "en", the user will get one of the "en-*" installed,
* pretty much at random.
* 4) The user's locale
* 5) Leave the current dictionary set.
* 6) The content of the "LANG" environment variable (if set)
* 1) Content preference, so the language the user set for the site before.
* (Introduced in bug 678842 and corrected in bug 717433.)
* 2) Language set by the website, or any other dictionary that partly
* matches that. (Introduced in bug 338427.)
* Eg. if the website is "en-GB", a user who only has "en-US" will get
* that. If the website is generic "en", the user will get one of the
* "en-*" installed, (almost) at random.
* However, we prefer what is stored in "spellchecker.dictionary",
* so if the user chose "en-AU" before, they will get "en-AU" on a plain
* "en" site. (Introduced in bug 682564.)
* 3) The value of "spellchecker.dictionary" which reflects a previous
* language choice of the user (on another site).
* (This was the original behaviour before the aforementioned bugs
* landed).
* 4) The user's locale.
* 5) Use the current dictionary that is currently set.
* 6) The content of the "LANG" environment variable (if set).
* 7) The first spell check dictionary installed.
*/
@@ -755,23 +794,43 @@ nsEditorSpellCheck::DictionaryFetched(DictionaryFetcher* aFetcher)
// https://html.spec.whatwg.org/#attr-lang
// This is used in SetCurrentDictionary.
mPreferredLang.Assign(aFetcher->mRootContentLang);
#ifdef DEBUG_DICT
printf("***** mPreferredLang (element) |%s|\n",
NS_ConvertUTF16toUTF8(mPreferredLang).get());
#endif
// If no luck, try the "Content-Language" header.
if (mPreferredLang.IsEmpty()) {
mPreferredLang.Assign(aFetcher->mRootDocContentLang);
#ifdef DEBUG_DICT
printf("***** mPreferredLang (content-language) |%s|\n",
NS_ConvertUTF16toUTF8(mPreferredLang).get());
#endif
}
// Auxiliary status.
nsresult rv2;
// We obtain a list of available dictionaries.
nsTArray<nsString> dictList;
rv2 = mSpellChecker->GetDictionaryList(&dictList);
NS_ENSURE_SUCCESS(rv2, rv2);
// Priority 1:
// Get language from content prefs, if set.
// If we successfully fetched a dictionary from content prefs, do not go
// further. Use this exact dictionary.
// Don't use content preferences for editor with eEditorMailMask flag.
nsAutoString dictName;
uint32_t flags;
mEditor->GetFlags(&flags);
if (!(flags & nsIPlaintextEditor::eEditorMailMask)) {
dictName.Assign(aFetcher->mDictionary);
if (!dictName.IsEmpty()) {
if (NS_SUCCEEDED(SetCurrentDictionary(dictName))) {
if (NS_SUCCEEDED(TryDictionary(dictName, dictList, DICT_NORMAL_COMPARE))) {
#ifdef DEBUG_DICT
printf("***** Assigned from content preferences |%s|\n",
NS_ConvertUTF16toUTF8(dictName).get());
#endif
// We take an early exit here, so let's not forget to clear the word
// list.
@@ -785,50 +844,34 @@ nsEditorSpellCheck::DictionaryFetched(DictionaryFetcher* aFetcher)
}
// Priority 2:
// Get global preferred language from preferences, if set.
// After checking the content preferences, we use the language of the element
// or document.
dictName.Assign(mPreferredLang);
#ifdef DEBUG_DICT
printf("***** Assigned from element/doc |%s|\n",
NS_ConvertUTF16toUTF8(dictName).get());
#endif
// Get the preference value.
nsAutoString preferredDict;
preferredDict = Preferences::GetLocalizedString("spellchecker.dictionary.override");
if (!preferredDict.IsEmpty()) {
dictName.Assign(preferredDict);
}
preferredDict = Preferences::GetLocalizedString("spellchecker.dictionary");
// Priority 3:
// Get language from element/doc, if set.
if (dictName.IsEmpty() && !mPreferredLang.IsEmpty()) {
dictName.Assign(mPreferredLang);
}
// Auxiliary status value
nsresult rv2;
// Obtain a list of available dictionaries to check against.
nsTArray<nsString> dictList;
rv2 = mSpellChecker->GetDictionaryList(&dictList);
NS_ENSURE_SUCCESS(rv2, rv2);
int32_t i, dictCount = dictList.Length();
// The following will be driven by this status. Once we are able to set a
// The following will be driven by this status. Once we were able to set a
// dictionary successfully, we're done. So we start with a "failed" status.
nsresult rv = NS_ERROR_FAILURE;
if (!dictName.IsEmpty()) {
for (i = 0; i < dictCount; i++) {
nsAutoString dictStr(dictList.ElementAt(i));
if (dictName.Equals(dictStr, nsCaseInsensitiveStringComparator())) {
// First let's correct any problems due to non-matching case.
// This applies to both a user-set override and document language.
// RFC 5646 explicitly states that matches should be case-insensitive.
dictName.Assign(dictStr);
// Try to set it. Doing this inside this loop avoids trying to set a
// dictionary that isn't available.
rv = SetCurrentDictionary(dictName);
break;
}
}
nsresult rv = NS_ERROR_NOT_AVAILABLE;
if (!dictName.IsEmpty()) {
// RFC 5646 explicitly states that matches should be case-insensitive.
rv = TryDictionary (dictName, dictList, DICT_COMPARE_CASE_INSENSITIVE);
if (NS_FAILED(rv)) {
#ifdef DEBUG_DICT
printf("***** Setting of |%s| failed (or it wasn't available)\n",
NS_ConvertUTF16toUTF8(dictName).get());
#endif
if (NS_FAILED(rv)) {
// Required dictionary was not available. Try to get a dictionary
// matching at least the language part of dictName:
// matching at least language part of dictName.
nsAutoString langCode;
int32_t dashIdx = dictName.FindChar('-');
if (dashIdx != -1) {
@@ -837,23 +880,45 @@ nsEditorSpellCheck::DictionaryFetched(DictionaryFetcher* aFetcher)
langCode.Assign(dictName);
}
nsDefaultStringComparator comparator;
// Loop over available dictionaries; if we find one with the required
// language, use it.
for (i = 0; i < dictCount; i++) {
nsAutoString dictStr(dictList.ElementAt(i));
if (nsStyleUtil::DashMatchCompare(dictStr, langCode, comparator) &&
NS_SUCCEEDED(rv = SetCurrentDictionary(dictStr))) {
break;
}
// Try dictionary.spellchecker preference, if it starts with langCode,
// so we don't just get any random dictionary matching the language.
if (!preferredDict.IsEmpty() &&
nsStyleUtil::DashMatchCompare(preferredDict, langCode, nsDefaultStringComparator())) {
#ifdef DEBUG_DICT
printf("***** Trying preference value |%s| since it matches language code\n",
NS_ConvertUTF16toUTF8(preferredDict).get());
#endif
rv = TryDictionary (preferredDict, dictList,
DICT_COMPARE_CASE_INSENSITIVE);
}
if (NS_FAILED(rv)) {
// Use any dictionary with the required language.
#ifdef DEBUG_DICT
printf("***** Trying to find match for language code |%s|\n",
NS_ConvertUTF16toUTF8(langCode).get());
#endif
rv = TryDictionary (langCode, dictList, DICT_COMPARE_DASHMATCH);
}
}
}
// Priority 3:
// If the document didn't supply a dictionary or the setting failed,
// try the user preference next.
if (NS_FAILED(rv)) {
if (!preferredDict.IsEmpty()) {
#ifdef DEBUG_DICT
printf("***** Trying preference value |%s|\n",
NS_ConvertUTF16toUTF8(preferredDict).get());
#endif
rv = TryDictionary (preferredDict, dictList, DICT_NORMAL_COMPARE);
}
}
// Priority 4:
// Content prefs, override and document didn't give us a valid dictionary
// name, so we just get the current locale and try to use that.
if (NS_FAILED (rv)) {
// As next fallback, try the current locale.
if (NS_FAILED(rv)) {
nsCOMPtr<nsIXULChromeRegistry> packageRegistry =
mozilla::services::GetXULChromeRegistryService();
@@ -863,54 +928,66 @@ nsEditorSpellCheck::DictionaryFetched(DictionaryFetcher* aFetcher)
utf8DictName);
dictName.Assign(EmptyString());
AppendUTF8toUTF16(utf8DictName, dictName);
// Try to set it, if it's in the list.
for (i = 0; i < dictCount; i++) {
nsAutoString dictStr(dictList.ElementAt(i));
if (dictStr.Equals(dictName)) {
rv = SetCurrentDictionary(dictName);
break;
}
}
#ifdef DEBUG_DICT
printf("***** Trying locale |%s|\n",
NS_ConvertUTF16toUTF8(dictName).get());
#endif
rv = TryDictionary (dictName, dictList, DICT_COMPARE_CASE_INSENSITIVE);
}
}
if (NS_FAILED(rv)) {
// Still no success. Further fallback attempts required.
// Still no success.
// Priority 5:
// If we have a current dictionary, don't try anything else.
// Priority 5:
// If we have a current dictionary, don't try anything else.
nsAutoString currentDictionary;
rv2 = GetCurrentDictionary(currentDictionary);
#ifdef DEBUG_DICT
if (NS_SUCCEEDED(rv2))
printf("***** Retrieved current dict |%s|\n",
NS_ConvertUTF16toUTF8(currentDictionary).get());
#endif
if (NS_FAILED(rv2) || currentDictionary.IsEmpty()) {
// We don't have a current dictionary.
// Priority 6:
// Try to get current dictionary from environment variable LANG.
// LANG = language[_territory][.codeset]
// LANG = language[_territory][.charset]
char* env_lang = getenv("LANG");
if (env_lang != nullptr) {
nsString lang = NS_ConvertUTF8toUTF16(env_lang);
// Strip trailing charset, if there is any.
int32_t dot_pos = lang.FindChar('.');
if (dot_pos != -1) {
lang = Substring(lang, 0, dot_pos);
}
// Convert underscore to dash.
int32_t underScore = lang.FindChar('_');
if (underScore != -1) {
lang.Replace(underScore, 1, '-');
// Only attempt to set if a _territory is present.
rv = SetCurrentDictionary(lang);
#ifdef DEBUG_DICT
printf("***** Trying LANG from environment |%s|\n",
NS_ConvertUTF16toUTF8(lang).get());
#endif
nsAutoString lang2;
lang2.Assign(lang);
rv = TryDictionary(lang2, dictList, DICT_COMPARE_CASE_INSENSITIVE);
}
}
// Priority 7:
// If LANG does not work either, pick the first one.
// If it does not work, pick the first one.
if (NS_FAILED(rv)) {
if (dictList.Length() > 0) {
rv = SetCurrentDictionary(dictList[0]);
nsAutoString firstInList;
firstInList.Assign(dictList[0]);
rv = TryDictionary(firstInList, dictList, DICT_NORMAL_COMPARE);
#ifdef DEBUG_DICT
printf("***** Trying first of list |%s|\n",
NS_ConvertUTF16toUTF8(dictList[0]).get());
if (NS_SUCCEEDED(rv))
printf ("***** Setting worked.\n");
#endif
}
}
}
@@ -921,7 +998,6 @@ nsEditorSpellCheck::DictionaryFetched(DictionaryFetcher* aFetcher)
// up. The user can manually reset the language to their choice on
// the dialog if it is wrong.
// Dictionary has changed, so delete the suggested word list.
DeleteSuggestedWordList();
return NS_OK;
+9
View File
@@ -27,6 +27,12 @@ class nsITextServicesFilter;
class DictionaryFetcher;
enum dictCompare {
DICT_NORMAL_COMPARE,
DICT_COMPARE_CASE_INSENSITIVE,
DICT_COMPARE_DASHMATCH
};
class nsEditorSpellCheck final : public nsIEditorSpellCheck
{
friend class DictionaryFetcher;
@@ -64,6 +70,9 @@ protected:
bool mUpdateDictionaryRunning;
nsresult TryDictionary(const nsAString& aDictName, nsTArray<nsString>& aDictList,
enum dictCompare aCompareType);
nsresult DictionaryFetched(DictionaryFetcher* aFetchState);
public:
@@ -0,0 +1,8 @@
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<textarea id="textarea" lang="en"></textarea>
</body>
</html>
+1
View File
@@ -5,3 +5,4 @@ skip-if = buildapp == 'b2g'
[test_bug338427.html]
[test_bug434998.xul]
[test_bug678842.html]
[test_bug717433.html]
+2
View File
@@ -0,0 +1,2 @@
# Affix file for British English dictionary
# Fake file, nothing here.
+4
View File
@@ -0,0 +1,4 @@
3
Mary
Paul
Peter
+5 -1
View File
@@ -1,6 +1,10 @@
[DEFAULT]
skip-if = buildapp == 'b2g' || buildapp == 'mulet'
support-files = bug678842_subframe.html
support-files =
bug678842_subframe.html
bug717433_subframe.html
en-GB/en_GB.dic
en-GB/en_GB.aff
[test_bug348497.html]
[test_bug384147.html]
+98
View File
@@ -0,0 +1,98 @@
<!DOCTYPE html>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=717433
-->
<head>
<title>Test for Bug 717433</title>
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
</head>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=717433">Mozilla Bug 717433</a>
<p id="display"></p>
<iframe id="content"></iframe>
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
/** Test for Bug 717433 **/
SimpleTest.waitForExplicitFinish();
var content = document.getElementById('content');
// Load a subframe containing an editor with language "en". At first
// load, it will set the dictionary to en-GB or en-US. We set the other one.
// At second load, it will return the current dictionary. We can check that the
// dictionary is correctly remembered between loads.
var firstLoad = true;
var expected = "";
var en_GB;
var hunspell;
var loadListener = function(evt) {
Components.utils.import("resource://gre/modules/AsyncSpellCheckTestHelper.jsm");
if (firstLoad) {
var dir = Components.classes["@mozilla.org/file/directory_service;1"]
.getService(Components.interfaces.nsIProperties)
.get("CurWorkD", Components.interfaces.nsIFile);
dir.append("tests");
dir.append("editor");
dir.append("composer");
dir.append("test");
hunspell = Components.classes["@mozilla.org/spellchecker/engine;1"]
.getService(Components.interfaces.mozISpellCheckingEngine);
// Install en-GB dictionary.
en_GB = dir.clone();
en_GB.append("en-GB");
is(en_GB.exists(), true, "true expected (en-GB directory should exist)");
hunspell.addDirectory(en_GB);
}
var doc = evt.target.contentDocument;
var elem = doc.getElementById('textarea');
var editor = elem.QueryInterface(Components.interfaces.nsIDOMNSEditableElement).editor;
editor.setSpellcheckUserOverride(true);
var inlineSpellChecker = editor.getInlineSpellChecker(true);
onSpellCheck(elem, function () {
var spellchecker = inlineSpellChecker.spellChecker;
try {
var currentDictonary = spellchecker.GetCurrentDictionary();
} catch(e) {}
if (firstLoad) {
firstLoad = false;
// First time around, we get a random dictionary based on the language "en".
if (currentDictonary == "en-GB") {
spellchecker.SetCurrentDictionary("en-US");
expected = "en-US";
} else if (currentDictonary == "en-US") {
spellchecker.SetCurrentDictionary("en-GB");
expected = "en-GB";
} else {
is(true, false, "Neither en-US nor en-GB are current");
}
content.src = 'http://mochi.test:8888/tests/editor/composer/test/bug717433_subframe.html?firstload=false';
} else {
is(currentDictonary, expected, expected + " expected");
content.removeEventListener('load', loadListener, false);
// Remove the fake en-GB dictionary again, since it's otherwise picked up by later tests.
hunspell.removeDirectory(en_GB);
SimpleTest.finish();
}
});
}
content.addEventListener('load', loadListener, false);
content.src = 'http://mochi.test:8888/tests/editor/composer/test/bug717433_subframe.html?firstload=true';
</script>
</pre>
</body>
</html>
-44
View File
@@ -24,7 +24,6 @@
#include "PlaceholderTxn.h" // for PlaceholderTxn
#include "SplitNodeTxn.h" // for SplitNodeTxn
#include "mozFlushType.h" // for mozFlushType::Flush_Frames
#include "mozISpellCheckingEngine.h"
#include "mozInlineSpellChecker.h" // for mozInlineSpellChecker
#include "mozilla/CheckedInt.h" // for CheckedInt
#include "mozilla/IMEStateManager.h" // for IMEStateManager
@@ -79,7 +78,6 @@
#include "nsIInlineSpellChecker.h" // for nsIInlineSpellChecker, etc
#include "nsNameSpaceManager.h" // for kNameSpaceID_None, etc
#include "nsINode.h" // for nsINode, etc
#include "nsIObserverService.h" // for nsIObserverService
#include "nsIPlaintextEditor.h" // for nsIPlaintextEditor, etc
#include "nsIPresShell.h" // for nsIPresShell
#include "nsISelectionController.h" // for nsISelectionController, etc
@@ -210,7 +208,6 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsEditor)
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
NS_INTERFACE_MAP_ENTRY(nsIEditorIMESupport)
NS_INTERFACE_MAP_ENTRY(nsIEditor)
NS_INTERFACE_MAP_ENTRY(nsIObserver)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIEditor)
NS_INTERFACE_MAP_END
@@ -310,13 +307,6 @@ nsEditor::PostCreate()
// update the UI with our state
NotifyDocumentListeners(eDocumentCreated);
NotifyDocumentListeners(eDocumentStateChanged);
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
if (obs) {
obs->AddObserver(this,
SPELLCHECK_DICTIONARY_UPDATE_NOTIFICATION,
false);
}
}
// update nsTextStateManager and caret if we have focus
@@ -454,12 +444,6 @@ nsEditor::PreDestroy(bool aDestroyingFrames)
IMEStateManager::OnEditorDestroying(this);
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
if (obs) {
obs->RemoveObserver(this,
SPELLCHECK_DICTIONARY_UPDATE_NOTIFICATION);
}
// Let spellchecker clean up its observers etc. It is important not to
// actually free the spellchecker here, since the spellchecker could have
// caused flush notifications, which could have gotten here if a textbox
@@ -1317,34 +1301,6 @@ NS_IMETHODIMP nsEditor::GetInlineSpellChecker(bool autoCreate,
return NS_OK;
}
NS_IMETHODIMP nsEditor::Observe(nsISupports* aSubj, const char *aTopic,
const char16_t *aData)
{
NS_ASSERTION(!strcmp(aTopic,
SPELLCHECK_DICTIONARY_UPDATE_NOTIFICATION),
"Unexpected observer topic");
// When mozInlineSpellChecker::CanEnableInlineSpellChecking changes
SyncRealTimeSpell();
// When nsIEditorSpellCheck::GetCurrentDictionary changes
if (mInlineSpellChecker) {
// if the current dictionary is no longer available, find another one
nsCOMPtr<nsIEditorSpellCheck> editorSpellCheck;
mInlineSpellChecker->GetSpellChecker(getter_AddRefs(editorSpellCheck));
if (editorSpellCheck) {
// Note: This might change the current dictionary, which may call
// this observer recursively.
editorSpellCheck->CheckCurrentDictionary();
}
// update the inline spell checker to reflect the new current dictionary
mInlineSpellChecker->SpellCheckRange(nullptr); // causes recheck
}
return NS_OK;
}
NS_IMETHODIMP nsEditor::SyncRealTimeSpell()
{
bool enable = GetDesiredSpellCheckState();
-4
View File
@@ -140,7 +140,6 @@ inline bool operator!(const EditAction& aOp)
class nsEditor : public nsIEditor,
public nsIEditorIMESupport,
public nsSupportsWeakReference,
public nsIObserver,
public nsIPhonetic
{
public:
@@ -188,9 +187,6 @@ public:
/* ------------ nsIEditorIMESupport methods -------------- */
NS_DECL_NSIEDITORIMESUPPORT
/* ------------ nsIObserver methods -------------- */
NS_DECL_NSIOBSERVER
// nsIPhonetic
NS_DECL_NSIPHONETIC
+5
View File
@@ -303,6 +303,11 @@ nsHTMLEditor::DoInsertHTMLWithContext(const nsAString & aInputString,
streamEndParentNode, streamEndOffset);
if (nodeList.Length() == 0) {
// We aren't inserting anything, but if aDeleteSelection is set, we do want
// to delete everything.
if (aDeleteSelection) {
return DeleteSelection(eNone, eStrip);
}
return NS_OK;
}
+1
View File
@@ -17,6 +17,7 @@ support-files =
skip-if = os != "mac"
[test_bug290026.html]
[test_bug291780.html]
[test_bug309731.html]
[test_bug316447.html]
[test_bug318065.html]
[test_bug332636.html]
@@ -0,0 +1,58 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=309731
-->
<head>
<title>Test for Bug 309731</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=309731">Mozilla Bug 309731</a>
<p id="display"></p>
<div id="content">
<div id="input" contentEditable="true"></div>
</div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 309731 **/
function selectNode(node) {
getSelection().selectAllChildren(node);
}
function selectInNode(node) {
getSelection().collapse(node, 0);
}
function doTest() {
var input = document.getElementById("input");
is(input.textContent, "", "Input node starts empty");
selectInNode(input);
ok(document.execCommand("inserthtml", false, ""), "execCommand should return true");
is(input.textContent, "", "empty inserthtml with empty selection shouldn't change contents");
selectInNode(input);
ok(document.execCommand("inserthtml", false, "foo"), "execCommand should return true");
is(input.textContent, "foo", "'foo'inserthtml with empty selection should add foo to contents");
selectNode(input);
ok(document.execCommand("inserthtml", false, "bar"), "execCommand should return true");
is(input.textContent, "bar", "'bar' inserthtml with complete selection should replace contents with bar");
selectNode(input);
ok(document.execCommand("inserthtml", false, ""), "execCommand should return true");
is(input.textContent, "", "empty inserthtml with complete selection should delete everything");
}
doTest();
</script>
</pre>
</body>
</html>
+1 -8
View File
@@ -9,17 +9,10 @@ interface nsIEditor;
interface nsITextServicesFilter;
interface nsIEditorSpellCheckCallback;
[scriptable, uuid(dd32ef3b-a7d8-43d1-9617-5f2dddbe29eb)]
[scriptable, uuid(a171c25f-e4a8-4d08-adef-b797e6377bdc)]
interface nsIEditorSpellCheck : nsISupports
{
/**
* Call this on any change in installed dictionaries to ensure that the spell
* checker is not using a current dictionary which is no longer available.
* If the current dictionary is no longer available, then pick another one.
*/
void checkCurrentDictionary();
/**
* Returns true if we can enable spellchecking. If there are no available
* dictionaries, this will return false.
-6
View File
@@ -114,12 +114,6 @@ public:
* empty string, spellchecker will be disabled.
*/
NS_IMETHOD SetCurrentDictionary(const nsAString &aDictionary) = 0;
/**
* Call this on any change in installed dictionaries to ensure that the spell
* checker is not using a current dictionary which is no longer available.
*/
NS_IMETHOD CheckCurrentDictionary() = 0;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsISpellChecker, NS_ISPELLCHECKER_IID)
@@ -160,12 +160,6 @@ NS_IMETHODIMP mozHunspell::SetDictionary(const char16_t *aDictionary)
mDecoder = nullptr;
mEncoder = nullptr;
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
if (obs) {
obs->NotifyObservers(nullptr,
SPELLCHECK_DICTIONARY_UPDATE_NOTIFICATION,
nullptr);
}
return NS_OK;
}
@@ -226,13 +220,6 @@ NS_IMETHODIMP mozHunspell::SetDictionary(const char16_t *aDictionary)
else
mLanguage = Substring(mDictionary, 0, pos);
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
if (obs) {
obs->NotifyObservers(nullptr,
SPELLCHECK_DICTIONARY_UPDATE_NOTIFICATION,
nullptr);
}
return NS_OK;
}
@@ -613,5 +600,19 @@ NS_IMETHODIMP mozHunspell::RemoveDirectory(nsIFile *aDir)
{
mDynamicDirectories.RemoveObject(aDir);
LoadDictionaryList(true);
#ifdef MOZ_THUNDERBIRD
/*
* This notification is needed for Thunderbird. Thunderbird derives the dictionary
* from the document's "lang" attribute. If a dictionary is removed,
* we need to change the "lang" attribute.
*/
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
if (obs) {
obs->NotifyObservers(nullptr,
SPELLCHECK_DICTIONARY_REMOVE_NOTIFICATION,
nullptr);
}
#endif
return NS_OK;
}
@@ -102,6 +102,6 @@ interface mozISpellCheckingEngine : nsISupports {
#define DICTIONARY_SEARCH_DIRECTORY "DictD"
#define DICTIONARY_SEARCH_DIRECTORY_LIST "DictDL"
#define SPELLCHECK_DICTIONARY_UPDATE_NOTIFICATION \
"spellcheck-dictionary-update"
#define SPELLCHECK_DICTIONARY_REMOVE_NOTIFICATION \
"spellcheck-dictionary-remove"
%}
@@ -2021,10 +2021,8 @@ nsresult mozInlineSpellChecker::CurrentDictionaryUpdated()
currentDictionary.Truncate();
}
if (!mPreviousDictionary.Equals(currentDictionary)) {
nsresult rv = SpellCheckRange(nullptr);
NS_ENSURE_SUCCESS(rv, rv);
}
nsresult rv = SpellCheckRange(nullptr);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
@@ -428,31 +428,6 @@ mozSpellChecker::SetCurrentDictionary(const nsAString &aDictionary)
return NS_ERROR_NOT_AVAILABLE;
}
NS_IMETHODIMP
mozSpellChecker::CheckCurrentDictionary()
{
// If the current dictionary has been uninstalled, we need to stop using it.
// This happens when there is a current engine, but that engine has no
// current dictionary.
if (!mSpellCheckingEngine) {
// We didn't have a current dictionary
return NS_OK;
}
nsXPIDLString dictname;
mSpellCheckingEngine->GetDictionary(getter_Copies(dictname));
if (!dictname.IsEmpty()) {
// We still have a current dictionary
return NS_OK;
}
// We had a current dictionary, but it has gone, so we cannot use it anymore.
mSpellCheckingEngine = nullptr;
return NS_OK;
}
nsresult
mozSpellChecker::SetupDoc(int32_t *outBlockOffset)
{
@@ -48,7 +48,6 @@ public:
NS_IMETHOD GetDictionaryList(nsTArray<nsString> *aDictionaryList) override;
NS_IMETHOD GetCurrentDictionary(nsAString &aDictionary) override;
NS_IMETHOD SetCurrentDictionary(const nsAString &aDictionary) override;
NS_IMETHOD CheckCurrentDictionary() override;
void DeleteRemoteEngine() {
mEngine = nullptr;
+4 -4
View File
@@ -1538,15 +1538,15 @@ public:
AFTER_GL_CALL;
}
void fStencilFunc(GLenum func, GLint ref, GLuint mask) {
void fStencilFunc(GLenum func, GLint reference, GLuint mask) {
BEFORE_GL_CALL;
mSymbols.fStencilFunc(func, ref, mask);
mSymbols.fStencilFunc(func, reference, mask);
AFTER_GL_CALL;
}
void fStencilFuncSeparate(GLenum frontfunc, GLenum backfunc, GLint ref, GLuint mask) {
void fStencilFuncSeparate(GLenum frontfunc, GLenum backfunc, GLint reference, GLuint mask) {
BEFORE_GL_CALL;
mSymbols.fStencilFuncSeparate(frontfunc, backfunc, ref, mask);
mSymbols.fStencilFuncSeparate(frontfunc, backfunc, reference, mask);
AFTER_GL_CALL;
}
+7 -4
View File
@@ -110,7 +110,8 @@ ClientLayerManager::ClientLayerManager(nsIWidget* aWidget)
ClientLayerManager::~ClientLayerManager()
{
if (mTransactionIdAllocator) {
DidComposite(mLatestTransactionId);
TimeStamp now = TimeStamp::Now();
DidComposite(mLatestTransactionId, now, now);
}
mMemoryPressureObserver->Destroy();
ClearCachedResources();
@@ -384,16 +385,18 @@ ClientLayerManager::Composite()
}
void
ClientLayerManager::DidComposite(uint64_t aTransactionId)
ClientLayerManager::DidComposite(uint64_t aTransactionId,
const TimeStamp& aCompositeStart,
const TimeStamp& aCompositeEnd)
{
MOZ_ASSERT(mWidget);
nsIWidgetListener *listener = mWidget->GetWidgetListener();
if (listener) {
listener->DidCompositeWindow();
listener->DidCompositeWindow(aCompositeStart, aCompositeEnd);
}
listener = mWidget->GetAttachedWidgetListener();
if (listener) {
listener->DidCompositeWindow();
listener->DidCompositeWindow(aCompositeStart, aCompositeEnd);
}
mTransactionIdAllocator->NotifyTransactionCompleted(aTransactionId);
}
+3 -1
View File
@@ -203,7 +203,9 @@ public:
virtual bool RequestOverfill(mozilla::dom::OverfillCallback* aCallback) override;
virtual void RunOverfillCallback(const uint32_t aOverfill) override;
void DidComposite(uint64_t aTransactionId);
void DidComposite(uint64_t aTransactionId,
const mozilla::TimeStamp& aCompositeStart,
const mozilla::TimeStamp& aCompositeEnd);
virtual bool SupportsMixBlendModes(EnumSet<gfx::CompositionOp>& aMixBlendModes) override
{
+17 -20
View File
@@ -178,22 +178,17 @@ CompositorChild::AllocPLayerTransactionChild(const nsTArray<LayersBackend>& aBac
return c;
}
/*static*/ PLDHashOperator
CompositorChild::RemoveSharedMetricsForLayersId(const uint64_t& aKey,
nsAutoPtr<SharedFrameMetricsData>& aData,
void* aLayerTransactionChild)
{
uint64_t childId = static_cast<LayerTransactionChild*>(aLayerTransactionChild)->GetId();
if (aData->GetLayersId() == childId) {
return PLDHashOperator::PL_DHASH_REMOVE;
}
return PLDHashOperator::PL_DHASH_NEXT;
}
bool
CompositorChild::DeallocPLayerTransactionChild(PLayerTransactionChild* actor)
{
mFrameMetricsTable.Enumerate(RemoveSharedMetricsForLayersId, actor);
uint64_t childId = static_cast<LayerTransactionChild*>(actor)->GetId();
for (auto iter = mFrameMetricsTable.Iter(); !iter.Done(); iter.Next()) {
nsAutoPtr<SharedFrameMetricsData>& data = iter.Data();
if (data->GetLayersId() == childId) {
iter.Remove();
}
}
static_cast<LayerTransactionChild*>(actor)->ReleaseIPDLReference();
return true;
}
@@ -217,14 +212,14 @@ static void CalculatePluginClip(const gfx::IntRect& aBounds,
bool& aPluginIsVisible)
{
aPluginIsVisible = true;
// aBounds (content origin)
nsIntRegion contentVisibleRegion(aBounds);
// aPluginClipRects (plugin widget origin)
nsIntRegion contentVisibleRegion;
// aPluginClipRects (plugin widget origin) - contains *visible* rects
for (uint32_t idx = 0; idx < aPluginClipRects.Length(); idx++) {
gfx::IntRect rect = aPluginClipRects[idx];
// shift to content origin
rect.MoveBy(aBounds.x, aBounds.y);
contentVisibleRegion.AndWith(rect);
// accumulate visible rects
contentVisibleRegion.OrWith(rect);
}
// apply layers clip (window origin)
nsIntRegion region = aParentLayerVisibleRegion;
@@ -345,16 +340,18 @@ CompositorChild::RecvUpdatePluginVisibility(const uintptr_t& aOwnerWidget,
}
bool
CompositorChild::RecvDidComposite(const uint64_t& aId, const uint64_t& aTransactionId)
CompositorChild::RecvDidComposite(const uint64_t& aId, const uint64_t& aTransactionId,
const TimeStamp& aCompositeStart,
const TimeStamp& aCompositeEnd)
{
if (mLayerManager) {
MOZ_ASSERT(aId == 0);
nsRefPtr<ClientLayerManager> m = mLayerManager;
m->DidComposite(aTransactionId);
m->DidComposite(aTransactionId, aCompositeStart, aCompositeEnd);
} else if (aId != 0) {
nsRefPtr<dom::TabChild> child = dom::TabChild::GetFrom(aId);
if (child) {
child->DidComposite(aTransactionId);
child->DidComposite(aTransactionId, aCompositeStart, aCompositeEnd);
}
}
return true;
+3 -5
View File
@@ -74,7 +74,9 @@ public:
RecvClearCachedResources(const uint64_t& id) override;
virtual bool
RecvDidComposite(const uint64_t& aId, const uint64_t& aTransactionId) override;
RecvDidComposite(const uint64_t& aId, const uint64_t& aTransactionId,
const TimeStamp& aCompositeStart,
const TimeStamp& aCompositeEnd) override;
virtual bool
RecvInvalidateAll() override;
@@ -173,10 +175,6 @@ private:
uint32_t mAPZCId;
};
static PLDHashOperator RemoveSharedMetricsForLayersId(const uint64_t& aKey,
nsAutoPtr<SharedFrameMetricsData>& aData,
void* aLayerTransactionChild);
nsRefPtr<ClientLayerManager> mLayerManager;
// When not multi-process, hold a reference to the CompositorParent to keep it
// alive. This reference should be null in multi-process.
+25 -15
View File
@@ -679,8 +679,6 @@ CompositorParent::CompositorParent(nsIWidget* aWidget,
mCompositorScheduler = new CompositorSoftwareTimerScheduler(this);
}
gfxPlatform::GetPlatform()->ComputeTileSize();
LayerScope::SetPixelScale(mWidget->GetDefaultScale().scale);
}
@@ -929,7 +927,9 @@ CompositorParent::PauseComposition()
mPaused = true;
mCompositor->Pause();
DidComposite();
TimeStamp now = TimeStamp::Now();
DidComposite(now, now);
}
// if anyone's waiting to make sure that composition really got paused, tell them
@@ -1132,7 +1132,8 @@ CompositorParent::CompositeToTarget(DrawTarget* aTarget, const gfx::IntRect* aRe
#endif
if (!CanComposite()) {
DidComposite();
TimeStamp end = TimeStamp::Now();
DidComposite(start, end);
return;
}
@@ -1175,7 +1176,8 @@ CompositorParent::CompositeToTarget(DrawTarget* aTarget, const gfx::IntRect* aRe
mLayerManager->EndTransaction(time);
if (!aTarget) {
DidComposite();
TimeStamp end = TimeStamp::Now();
DidComposite(start, end);
}
// We're not really taking advantage of the stored composite-again-time here.
@@ -1291,7 +1293,8 @@ CompositorParent::ShadowLayersUpdated(LayerTransactionParent* aLayerTree,
if (aScheduleComposite) {
ScheduleComposition();
if (mPaused) {
DidComposite();
TimeStamp now = TimeStamp::Now();
DidComposite(now, now);
}
}
mLayerManager->NotifyShadowTreeTransaction();
@@ -1324,7 +1327,8 @@ CompositorParent::SetTestSampleTime(LayerTransactionParent* aLayerTree,
if (!requestNextFrame) {
CancelCurrentCompositeTask();
// Pretend we composited in case someone is wating for this event.
DidComposite();
TimeStamp now = TimeStamp::Now();
DidComposite(now, now);
}
}
@@ -1356,7 +1360,8 @@ CompositorParent::ApplyAsyncProperties(LayerTransactionParent* aLayerTree)
if (!requestNextFrame) {
CancelCurrentCompositeTask();
// Pretend we composited in case someone is waiting for this event.
DidComposite();
TimeStamp now = TimeStamp::Now();
DidComposite(now, now);
}
}
}
@@ -1727,7 +1732,6 @@ public:
, mNotifyAfterRemotePaint(false)
{
MOZ_ASSERT(NS_IsMainThread());
gfxPlatform::GetPlatform()->ComputeTileSize();
}
// IToplevelProtocol::CloneToplevel()
@@ -1810,7 +1814,9 @@ public:
virtual AsyncCompositionManager* GetCompositionManager(LayerTransactionParent* aParent) override;
void DidComposite(uint64_t aId);
void DidComposite(uint64_t aId,
TimeStamp& aCompositeStart,
TimeStamp& aCompositeEnd);
private:
// Private destructor, to discourage deletion outside of Release():
@@ -1831,10 +1837,11 @@ private:
};
void
CompositorParent::DidComposite()
CompositorParent::DidComposite(TimeStamp& aCompositeStart,
TimeStamp& aCompositeEnd)
{
if (mPendingTransaction) {
unused << SendDidComposite(0, mPendingTransaction);
unused << SendDidComposite(0, mPendingTransaction, aCompositeStart, aCompositeEnd);
mPendingTransaction = 0;
}
if (mLayerManager) {
@@ -1850,7 +1857,8 @@ CompositorParent::DidComposite()
it != sIndirectLayerTrees.end(); it++) {
LayerTreeState* lts = &it->second;
if (lts->mParent == this && lts->mCrossProcessParent) {
static_cast<CrossProcessCompositorParent*>(lts->mCrossProcessParent)->DidComposite(it->first);
static_cast<CrossProcessCompositorParent*>(lts->mCrossProcessParent)->DidComposite(
it->first, aCompositeStart, aCompositeEnd);
}
}
}
@@ -2134,12 +2142,14 @@ UpdatePluginWindowState(uint64_t aId)
#endif // #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
void
CrossProcessCompositorParent::DidComposite(uint64_t aId)
CrossProcessCompositorParent::DidComposite(uint64_t aId,
TimeStamp& aCompositeStart,
TimeStamp& aCompositeEnd)
{
sIndirectLayerTreesLock->AssertCurrentThreadOwns();
LayerTransactionParent *layerTree = sIndirectLayerTrees[aId].mLayerTree;
if (layerTree && layerTree->GetPendingTransactionId()) {
unused << SendDidComposite(aId, layerTree->GetPendingTransactionId());
unused << SendDidComposite(aId, layerTree->GetPendingTransactionId(), aCompositeStart, aCompositeEnd);
layerTree->SetPendingTransactionId(0);
}
#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
+1 -1
View File
@@ -470,7 +470,7 @@ protected:
*/
bool CanComposite();
void DidComposite();
void DidComposite(TimeStamp& aCompositeStart, TimeStamp& aCompositeEnd);
nsRefPtr<LayerManagerComposite> mLayerManager;
nsRefPtr<Compositor> mCompositor;
+2 -1
View File
@@ -45,7 +45,8 @@ child:
// the root layer tree).
// transactionId is the id of the transaction before this composite, or 0
// if there was no transaction since the last composite.
async DidComposite(uint64_t id, uint64_t transactionId);
async DidComposite(uint64_t id, uint64_t transactionId,
TimeStamp compositeStart, TimeStamp compositeEnd);
// The parent sends the child the requested fill ratio numbers.
async Overfill(uint32_t aOverfill);
-2
View File
@@ -11,8 +11,6 @@ namespace mozilla {
namespace layers {
TEST(TiledLayerBuffer, TileStart) {
gfxPlatform::GetPlatform()->ComputeTileSize();
ASSERT_EQ(RoundDownToTileEdge(10, 256), 0);
ASSERT_EQ(RoundDownToTileEdge(-10, 256), -256);
}
-15
View File
@@ -94,21 +94,6 @@ inline ExtendMode ToExtendMode(gfxPattern::GraphicsExtend aExtend)
}
}
inline gfxPattern::GraphicsPatternType
ThebesPatternType(PatternType aType)
{
switch (aType) {
case PatternType::SURFACE:
return gfxPattern::PATTERN_SURFACE;
case PatternType::LINEAR_GRADIENT:
return gfxPattern::PATTERN_LINEAR;
case PatternType::RADIAL_GRADIENT:
return gfxPattern::PATTERN_RADIAL;
default:
return gfxPattern::PATTERN_SOLID;
}
}
inline gfxPattern::GraphicsExtend ThebesExtend(ExtendMode aExtend)
{
switch (aExtend) {
+1 -13
View File
@@ -100,13 +100,7 @@ gfxAndroidPlatform::gfxAndroidPlatform()
RegisterStrongMemoryReporter(new FreetypeReporter());
nsCOMPtr<nsIScreenManager> screenMgr = do_GetService("@mozilla.org/gfx/screenmanager;1");
nsCOMPtr<nsIScreen> screen;
screenMgr->GetPrimaryScreen(getter_AddRefs(screen));
mScreenDepth = 24;
screen->GetColorDepth(&mScreenDepth);
mOffscreenFormat = mScreenDepth == 16
mOffscreenFormat = GetScreenDepth() == 16
? gfxImageFormat::RGB16_565
: gfxImageFormat::RGB24;
@@ -401,12 +395,6 @@ gfxAndroidPlatform::RequiresLinearZoom()
return gfxPlatform::RequiresLinearZoom();
}
int
gfxAndroidPlatform::GetScreenDepth() const
{
return mScreenDepth;
}
bool
gfxAndroidPlatform::UseAcceleratedSkiaCanvas()
{
-2
View File
@@ -80,8 +80,6 @@ public:
FT_Library GetFTLibrary();
virtual int GetScreenDepth() const;
virtual bool CanRenderContentToDataSurface() const override {
return true;
}
+8 -8
View File
@@ -268,7 +268,6 @@ gfxCoreTextShaper::SetGlyphsFromRun(gfxShapedText *aShapedText,
nullptr, nullptr, nullptr);
nsAutoTArray<gfxShapedText::DetailedGlyph,1> detailedGlyphs;
gfxShapedText::CompressedGlyph g;
gfxShapedText::CompressedGlyph *charGlyphs =
aShapedText->GetCharacterGlyphs() + aOffset;
@@ -490,19 +489,20 @@ gfxCoreTextShaper::SetGlyphsFromRun(gfxShapedText *aShapedText,
advance = int32_t(toNextGlyph * appUnitsPerDevUnit);
}
gfxTextRun::CompressedGlyph g;
g.SetComplex(charGlyphs[baseCharIndex].IsClusterStart(),
true, detailedGlyphs.Length());
aShapedText->SetGlyphs(aOffset + baseCharIndex, g, detailedGlyphs.Elements());
gfxTextRun::CompressedGlyph textRunGlyph;
textRunGlyph.SetComplex(charGlyphs[baseCharIndex].IsClusterStart(),
true, detailedGlyphs.Length());
aShapedText->SetGlyphs(aOffset + baseCharIndex, textRunGlyph,
detailedGlyphs.Elements());
detailedGlyphs.Clear();
}
// the rest of the chars in the group are ligature continuations, no associated glyphs
while (++baseCharIndex != endCharIndex && baseCharIndex < wordLength) {
gfxShapedText::CompressedGlyph &g = charGlyphs[baseCharIndex];
NS_ASSERTION(!g.IsSimpleGlyph(), "overwriting a simple glyph");
g.SetComplex(inOrder && g.IsClusterStart(), false, 0);
gfxShapedText::CompressedGlyph &shapedTextGlyph = charGlyphs[baseCharIndex];
NS_ASSERTION(!shapedTextGlyph.IsSimpleGlyph(), "overwriting a simple glyph");
shapedTextGlyph.SetComplex(inOrder && shapedTextGlyph.IsClusterStart(), false, 0);
}
glyphStart = glyphEnd;
+37 -114
View File
@@ -699,7 +699,7 @@ gfxDWriteFontEntry::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
// gfxDWriteFontList
gfxDWriteFontList::gfxDWriteFontList()
: mInitialized(false), mForceGDIClassicMaxFontSize(0.0)
: mForceGDIClassicMaxFontSize(0.0)
{
}
@@ -839,128 +839,64 @@ gfxDWriteFontList::MakePlatformFont(const nsAString& aFontName,
return entry;
}
#ifdef DEBUG_DWRITE_STARTUP
#define LOGREGISTRY(msg) LogRegistryEvent(msg)
// for use when monitoring process
static void LogRegistryEvent(const wchar_t *msg)
{
HKEY dummyKey;
HRESULT hr;
wchar_t buf[512];
wsprintfW(buf, L" log %s", msg);
hr = RegOpenKeyExW(HKEY_LOCAL_MACHINE, buf, 0, KEY_READ, &dummyKey);
if (SUCCEEDED(hr)) {
RegCloseKey(dummyKey);
}
}
#else
#define LOGREGISTRY(msg)
#endif
nsresult
gfxDWriteFontList::InitFontList()
{
LOGREGISTRY(L"InitFontList start");
mInitialized = false;
LARGE_INTEGER frequency; // ticks per second
LARGE_INTEGER t1, t2, t3; // ticks
LARGE_INTEGER frequency; // ticks per second
LARGE_INTEGER t1, t2, t3, t4, t5; // ticks
double elapsedTime, upTime;
char nowTime[256], nowDate[256];
if (LOG_FONTINIT_ENABLED()) {
GetTimeFormat(LOCALE_INVARIANT, TIME_FORCE24HOURFORMAT,
if (LOG_FONTINIT_ENABLED()) {
GetTimeFormat(LOCALE_INVARIANT, TIME_FORCE24HOURFORMAT,
nullptr, nullptr, nowTime, 256);
GetDateFormat(LOCALE_INVARIANT, 0, nullptr, nullptr, nowDate, 256);
upTime = (double) GetTickCount();
}
upTime = (double) GetTickCount();
QueryPerformanceFrequency(&frequency);
QueryPerformanceCounter(&t1);
QueryPerformanceCounter(&t1); // start
HRESULT hr;
mGDIFontTableAccess = Preferences::GetBool("gfx.font_rendering.directwrite.use_gdi_table_loading", false);
mGDIFontTableAccess =
Preferences::GetBool("gfx.font_rendering.directwrite.use_gdi_table_loading",
false);
gfxPlatformFontList::InitFontList();
mFontSubstitutes.Clear();
mNonExistingFonts.Clear();
QueryPerformanceCounter(&t2);
hr = gfxWindowsPlatform::GetPlatform()->GetDWriteFactory()->
GetGdiInterop(getter_AddRefs(mGDIInterop));
if (FAILED(hr)) {
return NS_ERROR_FAILURE;
}
LOGREGISTRY(L"InitFontList end");
QueryPerformanceCounter(&t2); // base-class/interop initialization
QueryPerformanceCounter(&t3);
if (LOG_FONTINIT_ENABLED()) {
// determine dwrite version
nsAutoString dwriteVers;
gfxWindowsPlatform::GetDLLVersion(L"dwrite.dll", dwriteVers);
LOG_FONTINIT(("InitFontList\n"));
LOG_FONTINIT(("Start: %s %s\n", nowDate, nowTime));
LOG_FONTINIT(("Uptime: %9.3f s\n", upTime/1000));
LOG_FONTINIT(("dwrite version: %s\n",
NS_ConvertUTF16toUTF8(dwriteVers).get()));
}
elapsedTime = (t3.QuadPart - t1.QuadPart) * 1000.0 / frequency.QuadPart;
LOG_FONTINIT(("Total time in InitFontList: %9.3f ms\n", elapsedTime));
elapsedTime = (t2.QuadPart - t1.QuadPart) * 1000.0 / frequency.QuadPart;
LOG_FONTINIT((" --- gfxPlatformFontList init: %9.3f ms\n", elapsedTime));
elapsedTime = (t3.QuadPart - t2.QuadPart) * 1000.0 / frequency.QuadPart;
LOG_FONTINIT((" --- GdiInterop object: %9.3f ms\n", elapsedTime));
return NS_OK;
}
nsresult
gfxDWriteFontList::DelayedInitFontList()
{
LOGREGISTRY(L"DelayedInitFontList start");
LARGE_INTEGER frequency; // ticks per second
LARGE_INTEGER t1, t2, t3; // ticks
double elapsedTime, upTime;
char nowTime[256], nowDate[256];
if (LOG_FONTINIT_ENABLED()) {
GetTimeFormat(LOCALE_INVARIANT, TIME_FORCE24HOURFORMAT,
nullptr, nullptr, nowTime, 256);
GetDateFormat(LOCALE_INVARIANT, 0, nullptr, nullptr, nowDate, 256);
}
upTime = (double) GetTickCount();
QueryPerformanceFrequency(&frequency);
QueryPerformanceCounter(&t1);
HRESULT hr;
nsRefPtr<IDWriteFactory> factory =
gfxWindowsPlatform::GetPlatform()->GetDWriteFactory();
LOGREGISTRY(L"calling GetSystemFontCollection");
hr = factory->GetSystemFontCollection(getter_AddRefs(mSystemFonts));
NS_ASSERTION(SUCCEEDED(hr), "GetSystemFontCollection failed!");
LOGREGISTRY(L"GetSystemFontCollection done");
if (FAILED(hr)) {
return NS_ERROR_FAILURE;
}
QueryPerformanceCounter(&t2);
QueryPerformanceCounter(&t3); // system font collection
GetFontsFromCollection(mSystemFonts);
// if no fonts found, something is out of whack, bail and use GDI backend
NS_ASSERTION(mFontFamilies.Count() != 0,
"no fonts found in the system fontlist -- holy crap batman!");
if (mFontFamilies.Count() == 0) {
return NS_ERROR_FAILURE;
}
QueryPerformanceCounter(&t4); // iterate over system fonts
#ifdef MOZ_BUNDLED_FONTS
mBundledFonts = CreateBundledFontsCollection(factory);
if (mBundledFonts) {
@@ -978,7 +914,7 @@ gfxDWriteFontList::DelayedInitFontList()
// with both pre-DW systems and with IE9, which appears to do the same.
GetDirectWriteSubstitutes();
// bug 551313 - DirectWrite creates a Gill Sans family out of
// bug 551313 - DirectWrite creates a Gill Sans family out of
// poorly named members of the Gill Sans MT family containing
// only Ultra Bold weights. This causes big problems for pages
// using Gill Sans which is usually only available on OSX
@@ -1050,36 +986,39 @@ gfxDWriteFontList::DelayedInitFontList()
GetPrefsAndStartLoader();
LOGREGISTRY(L"DelayedInitFontList end");
QueryPerformanceCounter(&t3);
QueryPerformanceCounter(&t5); // misc initialization
if (LOG_FONTINIT_ENABLED()) {
// determine dwrite version
nsAutoString dwriteVers;
gfxWindowsPlatform::GetDLLVersion(L"dwrite.dll", dwriteVers);
LOG_FONTINIT(("DelayedInitFontList\n"));
LOG_FONTINIT(("Start: %s %s\n", nowDate, nowTime));
LOG_FONTINIT(("Uptime: %9.3f s\n", upTime/1000));
LOG_FONTINIT(("dwrite version: %s\n",
LOG_FONTINIT(("(fontinit) Start: %s %s\n", nowDate, nowTime));
LOG_FONTINIT(("(fontinit) Uptime: %9.3f s\n", upTime/1000));
LOG_FONTINIT(("(fontinit) dwrite version: %s\n",
NS_ConvertUTF16toUTF8(dwriteVers).get()));
}
elapsedTime = (t3.QuadPart - t1.QuadPart) * 1000.0 / frequency.QuadPart;
elapsedTime = (t5.QuadPart - t1.QuadPart) * 1000.0 / frequency.QuadPart;
Telemetry::Accumulate(Telemetry::DWRITEFONT_DELAYEDINITFONTLIST_TOTAL, elapsedTime);
Telemetry::Accumulate(Telemetry::DWRITEFONT_DELAYEDINITFONTLIST_COUNT,
mSystemFonts->GetFontFamilyCount());
LOG_FONTINIT((
"Total time in DelayedInitFontList: %9.3f ms (families: %d, %s)\n",
"(fontinit) Total time in InitFontList: %9.3f ms (families: %d, %s)\n",
elapsedTime, mSystemFonts->GetFontFamilyCount(),
(mGDIFontTableAccess ? "gdi table access" : "dwrite table access")));
elapsedTime = (t2.QuadPart - t1.QuadPart) * 1000.0 / frequency.QuadPart;
Telemetry::Accumulate(Telemetry::DWRITEFONT_DELAYEDINITFONTLIST_COLLECT, elapsedTime);
LOG_FONTINIT((" --- GetSystemFontCollection: %9.3f ms\n", elapsedTime));
LOG_FONTINIT(("(fontinit) --- base/interop obj initialization init: %9.3f ms\n", elapsedTime));
elapsedTime = (t3.QuadPart - t2.QuadPart) * 1000.0 / frequency.QuadPart;
LOG_FONTINIT((" --- iterate over families: %9.3f ms\n", elapsedTime));
Telemetry::Accumulate(Telemetry::DWRITEFONT_DELAYEDINITFONTLIST_COLLECT, elapsedTime);
LOG_FONTINIT(("(fontinit) --- GetSystemFontCollection: %9.3f ms\n", elapsedTime));
elapsedTime = (t4.QuadPart - t3.QuadPart) * 1000.0 / frequency.QuadPart;
LOG_FONTINIT(("(fontinit) --- iterate over families: %9.3f ms\n", elapsedTime));
elapsedTime = (t5.QuadPart - t4.QuadPart) * 1000.0 / frequency.QuadPart;
LOG_FONTINIT(("(fontinit) --- misc initialization: %9.3f ms\n", elapsedTime));
return NS_OK;
}
@@ -1303,11 +1242,6 @@ gfxDWriteFontList::FindFamily(const nsAString& aFamily,
nsIAtom* aLanguage,
bool aUseSystemFonts)
{
if (!mInitialized) {
mInitialized = true;
DelayedInitFontList();
}
nsAutoString keyName(aFamily);
BuildKeyNameFromFontName(keyName);
@@ -1323,17 +1257,6 @@ gfxDWriteFontList::FindFamily(const nsAString& aFamily,
return gfxPlatformFontList::FindFamily(aFamily);
}
void
gfxDWriteFontList::GetFontFamilyList(nsTArray<nsRefPtr<gfxFontFamily> >& aFamilyArray)
{
if (!mInitialized) {
mInitialized = true;
DelayedInitFontList();
}
return gfxPlatformFontList::GetFontFamilyList(aFamilyArray);
}
void
gfxDWriteFontList::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf,
FontListSizes* aSizes) const
-5
View File
@@ -368,8 +368,6 @@ public:
nsIAtom* aLanguage = nullptr,
bool aUseSystemFonts = false);
virtual void GetFontFamilyList(nsTArray<nsRefPtr<gfxFontFamily> >& aFamilyArray);
gfxFloat GetForceGDIClassicMaxFontSize() { return mForceGDIClassicMaxFontSize; }
virtual void AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
@@ -412,9 +410,6 @@ private:
*/
FontFamilyTable mFontSubstitutes;
bool mInitialized;
virtual nsresult DelayedInitFontList();
virtual already_AddRefed<FontInfoData> CreateFontInfoData();
gfxFloat mForceGDIClassicMaxFontSize;
+96 -122
View File
@@ -919,19 +919,19 @@ gfxFT2FontList::AppendFacesFromFontFile(const nsCString& aFileName,
StandardFile aStdFile,
FT2FontFamily::Visibility aVisibility)
{
nsCString faceList;
nsCString cachedFaceList;
uint32_t filesize = 0, timestamp = 0;
if (aCache) {
aCache->GetInfoForFile(aFileName, faceList, &timestamp, &filesize);
aCache->GetInfoForFile(aFileName, cachedFaceList, &timestamp, &filesize);
}
struct stat s;
int statRetval = stat(aFileName.get(), &s);
if (!faceList.IsEmpty() && 0 == statRetval &&
if (!cachedFaceList.IsEmpty() && 0 == statRetval &&
s.st_mtime == timestamp && s.st_size == filesize)
{
LOG(("using cached font info for %s", aFileName.get()));
AppendFacesFromCachedFaceList(aFileName, faceList, aStdFile,
AppendFacesFromCachedFaceList(aFileName, cachedFaceList, aStdFile,
aVisibility);
return;
}
@@ -940,7 +940,7 @@ gfxFT2FontList::AppendFacesFromFontFile(const nsCString& aFileName,
FT_Face dummy;
if (FT_Err_Ok == FT_New_Face(ftLibrary, aFileName.get(), -1, &dummy)) {
LOG(("reading font info via FreeType for %s", aFileName.get()));
nsCString faceList;
nsCString newFaceList;
timestamp = s.st_mtime;
filesize = s.st_size;
for (FT_Long i = 0; i < dummy->num_faces; i++) {
@@ -948,12 +948,12 @@ gfxFT2FontList::AppendFacesFromFontFile(const nsCString& aFileName,
if (FT_Err_Ok != FT_New_Face(ftLibrary, aFileName.get(), i, &face)) {
continue;
}
AddFaceToList(aFileName, i, aStdFile, aVisibility, face, faceList);
AddFaceToList(aFileName, i, aStdFile, aVisibility, face, newFaceList);
FT_Done_Face(face);
}
FT_Done_Face(dummy);
if (aCache && 0 == statRetval && !faceList.IsEmpty()) {
aCache->CacheFileInfo(aFileName, faceList, timestamp, filesize);
if (aCache && 0 == statRetval && !newFaceList.IsEmpty()) {
aCache->CacheFileInfo(aFileName, newFaceList, timestamp, filesize);
}
}
}
@@ -1123,22 +1123,19 @@ gfxFT2FontList::AppendFacesFromOmnijarEntry(nsZipArchive* aArchive,
// Called on each family after all fonts are added to the list;
// this will sort faces to give priority to "standard" font files
// if aUserArg is non-null (i.e. we're using it as a boolean flag)
static PLDHashOperator
static void
FinalizeFamilyMemberList(nsStringHashKey::KeyType aKey,
nsRefPtr<gfxFontFamily>& aFamily,
void* aUserArg)
bool aSortFaces)
{
gfxFontFamily *family = aFamily.get();
bool sortFaces = (aUserArg != nullptr);
family->SetHasStyles(true);
if (sortFaces) {
if (aSortFaces) {
family->SortAvailableFonts();
}
family->CheckForSimpleFamily();
return PL_DHASH_NEXT;
}
void
@@ -1165,8 +1162,17 @@ gfxFT2FontList::FindFonts()
// Passing null for userdata tells Finalize that it does not need
// to sort faces (because they were already sorted by chrome,
// so we just maintain the existing order)
mFontFamilies.Enumerate(FinalizeFamilyMemberList, nullptr);
mHiddenFontFamilies.Enumerate(FinalizeFamilyMemberList, nullptr);
for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) {
nsStringHashKey::KeyType key = iter.Key();
nsRefPtr<gfxFontFamily>& family = iter.Data();
FinalizeFamilyMemberList(key, family, /* aSortFaces */ false);
}
for (auto iter = mHiddenFontFamilies.Iter(); !iter.Done(); iter.Next()) {
nsStringHashKey::KeyType key = iter.Key();
nsRefPtr<gfxFontFamily>& family = iter.Data();
FinalizeFamilyMemberList(key, family, /* aSortFaces */ false );
}
LOG(("got font list from chrome process: %d faces in %d families "
"and %d in hidden families",
fonts.Length(), mFontFamilies.Count(),
@@ -1229,8 +1235,16 @@ gfxFT2FontList::FindFonts()
// Finalize the families by sorting faces into standard order
// and marking "simple" families.
// Passing non-null userData here says that we want faces to be sorted.
mFontFamilies.Enumerate(FinalizeFamilyMemberList, this);
mHiddenFontFamilies.Enumerate(FinalizeFamilyMemberList, this);
for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) {
nsStringHashKey::KeyType key = iter.Key();
nsRefPtr<gfxFontFamily>& family = iter.Data();
FinalizeFamilyMemberList(key, family, /* aSortFaces */ true);
}
for (auto iter = mHiddenFontFamilies.Iter(); !iter.Done(); iter.Next()) {
nsStringHashKey::KeyType key = iter.Key();
nsRefPtr<gfxFontFamily>& family = iter.Data();
FinalizeFamilyMemberList(key, family, /* aSortFaces */ true);
}
}
void
@@ -1320,39 +1334,17 @@ gfxFT2FontList::AppendFaceFromFontListEntry(const FontListEntry& aFLE,
}
}
static PLDHashOperator
AddFamilyToFontList(nsStringHashKey::KeyType aKey,
nsRefPtr<gfxFontFamily>& aFamily,
void* aUserArg)
{
InfallibleTArray<FontListEntry>* fontlist =
reinterpret_cast<InfallibleTArray<FontListEntry>*>(aUserArg);
FT2FontFamily *family = static_cast<FT2FontFamily*>(aFamily.get());
family->AddFacesToFontList(fontlist, FT2FontFamily::kVisible);
return PL_DHASH_NEXT;
}
static PLDHashOperator
AddHiddenFamilyToFontList(nsStringHashKey::KeyType aKey,
nsRefPtr<gfxFontFamily>& aFamily,
void* aUserArg)
{
InfallibleTArray<FontListEntry>* fontlist =
reinterpret_cast<InfallibleTArray<FontListEntry>*>(aUserArg);
FT2FontFamily *family = static_cast<FT2FontFamily*>(aFamily.get());
family->AddFacesToFontList(fontlist, FT2FontFamily::kHidden);
return PL_DHASH_NEXT;
}
void
gfxFT2FontList::GetSystemFontList(InfallibleTArray<FontListEntry>* retValue)
{
mFontFamilies.Enumerate(AddFamilyToFontList, retValue);
mHiddenFontFamilies.Enumerate(AddHiddenFamilyToFontList, retValue);
for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) {
auto family = static_cast<FT2FontFamily*>(iter.Data().get());
family->AddFacesToFontList(retValue, FT2FontFamily::kVisible);
}
for (auto iter = mHiddenFontFamilies.Iter(); !iter.Done(); iter.Next()) {
auto family = static_cast<FT2FontFamily*>(iter.Data().get());
family->AddFacesToFontList(retValue, FT2FontFamily::kHidden);
}
}
static void
@@ -1369,10 +1361,9 @@ LoadSkipSpaceLookupCheck(nsTHashtable<nsStringHashKey>& aSkipSpaceLookupCheck)
}
}
static PLDHashOperator
void
PreloadAsUserFontFaces(nsStringHashKey::KeyType aKey,
nsRefPtr<gfxFontFamily>& aFamily,
void* aUserArg)
nsRefPtr<gfxFontFamily>& aFamily)
{
gfxFontFamily *family = aFamily.get();
@@ -1425,8 +1416,6 @@ PreloadAsUserFontFaces(nsStringHashKey::KeyType aKey,
gfxUserFontSet::UserFontCache::CacheFont(
fe, gfxUserFontSet::UserFontCache::kPersistent);
}
return PL_DHASH_NEXT;
}
nsresult
@@ -1435,74 +1424,65 @@ gfxFT2FontList::InitFontList()
// reset font lists
gfxPlatformFontList::InitFontList();
mHiddenFontFamilies.Clear();
LoadSkipSpaceLookupCheck(mSkipSpaceLookupCheckFamilies);
FindFonts();
mHiddenFontFamilies.Enumerate(PreloadAsUserFontFaces, this);
for (auto iter = mHiddenFontFamilies.Iter(); !iter.Done(); iter.Next()) {
nsStringHashKey::KeyType key = iter.Key();
nsRefPtr<gfxFontFamily>& family = iter.Data();
PreloadAsUserFontFaces(key, family);
}
return NS_OK;
}
struct FullFontNameSearch {
FullFontNameSearch(const nsAString& aFullName)
: mFullName(aFullName), mFontEntry(nullptr)
{ }
nsString mFullName;
FT2FontEntry *mFontEntry;
};
// callback called for each family name, based on the assumption that the
// called for each family name, based on the assumption that the
// first part of the full name is the family name
static PLDHashOperator
FindFullName(nsStringHashKey::KeyType aKey,
nsRefPtr<gfxFontFamily>& aFontFamily,
void* userArg)
{
FullFontNameSearch *data = reinterpret_cast<FullFontNameSearch*>(userArg);
// does the family name match up to the length of the family name?
const nsString& family = aFontFamily->Name();
nsString fullNameFamily;
data->mFullName.Left(fullNameFamily, family.Length());
// if so, iterate over faces in this family to see if there is a match
if (family.Equals(fullNameFamily, nsCaseInsensitiveStringComparator())) {
nsTArray<nsRefPtr<gfxFontEntry> >& fontList = aFontFamily->GetFontList();
int index, len = fontList.Length();
for (index = 0; index < len; index++) {
gfxFontEntry* fe = fontList[index];
if (!fe) {
continue;
}
if (fe->Name().Equals(data->mFullName,
nsCaseInsensitiveStringComparator())) {
data->mFontEntry = static_cast<FT2FontEntry*>(fe);
return PL_DHASH_STOP;
}
}
}
return PL_DHASH_NEXT;
}
gfxFontEntry*
gfxFontEntry*
gfxFT2FontList::LookupLocalFont(const nsAString& aFontName,
uint16_t aWeight,
int16_t aStretch,
bool aItalic)
{
// walk over list of names
FullFontNameSearch data(aFontName);
FT2FontEntry* fontEntry = nullptr;
nsString fullName(aFontName);
// Note that we only check mFontFamilies here, not mHiddenFontFamilies;
// hence @font-face { src:local(...) } will not find hidden fonts.
mFontFamilies.Enumerate(FindFullName, &data);
for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) {
// Check family name, based on the assumption that the
// first part of the full name is the family name
nsRefPtr<gfxFontFamily>& fontFamily = iter.Data();
if (!data.mFontEntry) {
// does the family name match up to the length of the family name?
const nsString& family = fontFamily->Name();
nsString fullNameFamily;
fullName.Left(fullNameFamily, family.Length());
// if so, iterate over faces in this family to see if there is a match
if (family.Equals(fullNameFamily, nsCaseInsensitiveStringComparator())) {
nsTArray<nsRefPtr<gfxFontEntry> >& fontList = fontFamily->GetFontList();
int index, len = fontList.Length();
for (index = 0; index < len; index++) {
gfxFontEntry* fe = fontList[index];
if (!fe) {
continue;
}
if (fe->Name().Equals(fullName,
nsCaseInsensitiveStringComparator())) {
fontEntry = static_cast<FT2FontEntry*>(fe);
goto searchDone;
}
}
}
}
searchDone:
if (!fontEntry) {
return nullptr;
}
@@ -1510,16 +1490,16 @@ gfxFT2FontList::LookupLocalFont(const nsAString& aFontName,
// from the userfont entry rather than the actual font.
// Ensure existence of mFTFace in the original entry
data.mFontEntry->CairoFontFace();
if (!data.mFontEntry->mFTFace) {
fontEntry->CairoFontFace();
if (!fontEntry->mFTFace) {
return nullptr;
}
FT2FontEntry* fe =
FT2FontEntry::CreateFontEntry(data.mFontEntry->mFTFace,
data.mFontEntry->mFilename.get(),
data.mFontEntry->mFTFontIndex,
data.mFontEntry->Name(), nullptr);
FT2FontEntry::CreateFontEntry(fontEntry->mFTFace,
fontEntry->mFilename.get(),
fontEntry->mFTFontIndex,
fontEntry->Name(), nullptr);
if (fe) {
fe->mItalic = aItalic;
fe->mWeight = aWeight;
@@ -1561,21 +1541,15 @@ gfxFT2FontList::MakePlatformFont(const nsAString& aFontName,
aItalic, aFontData, aLength);
}
static PLDHashOperator
AppendFamily(nsStringHashKey::KeyType aKey,
nsRefPtr<gfxFontFamily>& aFamily,
void* aUserArg)
{
nsTArray<nsRefPtr<gfxFontFamily> > * familyArray =
reinterpret_cast<nsTArray<nsRefPtr<gfxFontFamily>>*>(aUserArg);
familyArray->AppendElement(aFamily);
return PL_DHASH_NEXT;
}
void
gfxFT2FontList::GetFontFamilyList(nsTArray<nsRefPtr<gfxFontFamily> >& aFamilyArray)
{
mFontFamilies.Enumerate(AppendFamily, &aFamilyArray);
mHiddenFontFamilies.Enumerate(AppendFamily, &aFamilyArray);
for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) {
nsRefPtr<gfxFontFamily>& family = iter.Data();
aFamilyArray.AppendElement(family);
}
for (auto iter = mHiddenFontFamilies.Iter(); !iter.Done(); iter.Next()) {
nsRefPtr<gfxFontFamily>& family = iter.Data();
aFamilyArray.AppendElement(family);
}
}
+2 -4
View File
@@ -351,7 +351,7 @@ gfxFontconfigFontEntry::ReadCMAP(FontInfoData *aFontInfoData)
nsRefPtr<gfxCharacterMap> charmap;
nsresult rv;
bool symbolFont;
bool symbolFont = false; // currently ignored
if (aFontInfoData && (charmap = GetCMAPFromFontInfo(aFontInfoData,
mUVSOffset,
@@ -363,7 +363,7 @@ gfxFontconfigFontEntry::ReadCMAP(FontInfoData *aFontInfoData)
AutoTable cmapTable(this, kCMAP);
if (cmapTable) {
bool unicodeFont = false, symbolFont = false; // currently ignored
bool unicodeFont = false; // currently ignored
uint32_t cmapLen;
const uint8_t* cmapData =
reinterpret_cast<const uint8_t*>(hb_blob_get_data(cmapTable,
@@ -1487,5 +1487,3 @@ ApplyGdkScreenFontOptions(FcPattern *aPattern)
}
#endif // MOZ_WIDGET_GTK2
+5 -3
View File
@@ -428,7 +428,7 @@ gfxFontShaper::MergeFontFeatures(
bool aDisableLigatures,
const nsAString& aFamilyName,
bool aAddSmallCaps,
PLDHashOperator (*aHandleFeature)(const uint32_t&, uint32_t&, void*),
void (*aHandleFeature)(const uint32_t&, uint32_t&, void*),
void* aHandleFeatureData)
{
uint32_t numAlts = aStyle->alternateValues.Length();
@@ -530,7 +530,9 @@ gfxFontShaper::MergeFontFeatures(
}
if (mergedFeatures.Count() != 0) {
mergedFeatures.Enumerate(aHandleFeature, aHandleFeatureData);
for (auto iter = mergedFeatures.Iter(); !iter.Done(); iter.Next()) {
aHandleFeature(iter.Key(), iter.Data(), aHandleFeatureData);
}
}
}
@@ -2226,7 +2228,7 @@ gfxFont::Measure(gfxTextRun *aTextRun,
const gfxTextRun::DetailedGlyph *details =
aTextRun->GetDetailedGlyphs(i);
NS_ASSERTION(details != nullptr,
"detaiedGlyph record should not be missing!");
"detailedGlyph record should not be missing!");
uint32_t j;
for (j = 0; j < glyphCount; ++j, ++details) {
uint32_t glyphIndex = details->mGlyphID;
+2 -2
View File
@@ -637,8 +637,8 @@ public:
bool aDisableLigatures,
const nsAString& aFamilyName,
bool aAddSmallCaps,
PLDHashOperator (*aHandleFeature)(const uint32_t&,
uint32_t&, void*),
void (*aHandleFeature)(const uint32_t&,
uint32_t&, void*),
void* aHandleFeatureData);
protected:
+6 -9
View File
@@ -146,13 +146,6 @@ gfxFontEntry::gfxFontEntry(const nsAString& aName, bool aIsStandardFace) :
memset(&mNonDefaultSubSpaceFeatures, 0, sizeof(mNonDefaultSubSpaceFeatures));
}
static PLDHashOperator
DestroyHBSet(const uint32_t& aTag, hb_set_t*& aSet, void *aUserArg)
{
hb_set_destroy(aSet);
return PL_DHASH_NEXT;
}
gfxFontEntry::~gfxFontEntry()
{
if (mCOLR) {
@@ -170,7 +163,10 @@ gfxFontEntry::~gfxFontEntry()
}
if (mFeatureInputs) {
mFeatureInputs->Enumerate(DestroyHBSet, nullptr);
for (auto iter = mFeatureInputs->Iter(); !iter.Done(); iter.Next()) {
hb_set_t*& set = iter.Data();
hb_set_destroy(set);
}
}
// By the time the entry is destroyed, all font instances that were
@@ -905,7 +901,8 @@ gfxFontEntry::SupportsOpenTypeFeature(int32_t aScript, uint32_t aFeatureTag)
aFeatureTag == HB_TAG('p','c','a','p') ||
aFeatureTag == HB_TAG('c','2','p','c') ||
aFeatureTag == HB_TAG('s','u','p','s') ||
aFeatureTag == HB_TAG('s','u','b','s'),
aFeatureTag == HB_TAG('s','u','b','s') ||
aFeatureTag == HB_TAG('v','e','r','t'),
"use of unknown feature tag");
// note: graphite feature support uses the last script index
+32 -6
View File
@@ -12,6 +12,12 @@
using namespace mozilla;
using services::GetObserverService;
#define LOG_FONTINIT(args) MOZ_LOG(gfxPlatform::GetLog(eGfxLog_fontinit), \
LogLevel::Debug, args)
#define LOG_FONTINIT_ENABLED() MOZ_LOG_TEST( \
gfxPlatform::GetLog(eGfxLog_fontinit), \
LogLevel::Debug)
void
FontInfoData::Load()
{
@@ -57,6 +63,21 @@ class AsyncFontInfoLoader : public nsRunnable {
nsRefPtr<FontInfoLoadCompleteEvent> mCompleteEvent;
};
class ShutdownThreadEvent : public nsRunnable {
virtual ~ShutdownThreadEvent() {}
NS_DECL_ISUPPORTS_INHERITED
explicit ShutdownThreadEvent(nsIThread* aThread) : mThread(aThread) {}
NS_IMETHOD Run() override {
mThread->Shutdown();
return NS_OK;
}
nsCOMPtr<nsIThread> mThread;
};
NS_IMPL_ISUPPORTS_INHERITED0(ShutdownThreadEvent, nsRunnable);
// runs on main thread after async font info loading is done
nsresult
FontInfoLoadCompleteEvent::Run()
@@ -106,6 +127,9 @@ gfxFontInfoLoader::StartLoader(uint32_t aDelay, uint32_t aInterval)
{
mInterval = aInterval;
NS_ASSERTION(!mFontInfo,
"fontinfo should be null when starting font loader");
// sanity check
if (mState != stateInitial &&
mState != stateTimerOff &&
@@ -149,6 +173,11 @@ gfxFontInfoLoader::StartLoader(uint32_t aDelay, uint32_t aInterval)
nsCOMPtr<nsIRunnable> loadEvent = new AsyncFontInfoLoader(mFontInfo);
mFontLoaderThread->Dispatch(loadEvent.forget(), NS_DISPATCH_NORMAL);
if (LOG_FONTINIT_ENABLED()) {
LOG_FONTINIT(("(fontinit) fontloader started (fontinfo: %p)\n",
mFontInfo.get()));
}
}
void
@@ -159,7 +188,7 @@ gfxFontInfoLoader::FinalizeLoader(FontInfoData *aFontInfo)
// thread has already Shutdown(), and likely before processing
// the Shutdown event it handled the load event and sent back
// our Completion event, thus we end up here.
if (mState != stateAsyncLoad) {
if (mState != stateAsyncLoad || mFontInfo != aFontInfo) {
return;
}
@@ -189,11 +218,8 @@ gfxFontInfoLoader::CancelLoader()
mTimer = nullptr;
}
if (mFontLoaderThread) {
// NOTE: Shutdown() runs the event loop, and we can get timer events
// ensure that we can't try to do this twice!
nsCOMPtr<nsIThread> temp;
temp.swap(mFontLoaderThread);
temp->Shutdown();
NS_DispatchToMainThread(new ShutdownThreadEvent(mFontLoaderThread));
mFontLoaderThread = nullptr;
}
RemoveShutdownObserver();
CleanupLoader();
+35
View File
@@ -0,0 +1,35 @@
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// this needs to match the list of pref font.default.xx entries listed in all.js!
FONT_PREF_LANG(Western, "x-western", x_western),
FONT_PREF_LANG(Japanese, "ja", Japanese),
FONT_PREF_LANG(ChineseTW, "zh-TW", Taiwanese),
FONT_PREF_LANG(ChineseCN, "zh-CN", Chinese),
FONT_PREF_LANG(ChineseHK, "zh-HK", HongKongChinese),
FONT_PREF_LANG(Korean, "ko", ko),
FONT_PREF_LANG(Cyrillic, "x-cyrillic", x_cyrillic),
FONT_PREF_LANG(Greek, "el", el),
FONT_PREF_LANG(Thai, "th", th),
FONT_PREF_LANG(Hebrew, "he", he),
FONT_PREF_LANG(Arabic, "ar", ar),
FONT_PREF_LANG(Devanagari, "x-devanagari", x_devanagari),
FONT_PREF_LANG(Tamil, "x-tamil", x_tamil),
FONT_PREF_LANG(Armenian, "x-armn", x_armn),
FONT_PREF_LANG(Bengali, "x-beng", x_beng),
FONT_PREF_LANG(Canadian, "x-cans", x_cans),
FONT_PREF_LANG(Ethiopic, "x-ethi", x_ethi),
FONT_PREF_LANG(Georgian, "x-geor", x_geor),
FONT_PREF_LANG(Gujarati, "x-gujr", x_gujr),
FONT_PREF_LANG(Gurmukhi, "x-guru", x_guru),
FONT_PREF_LANG(Khmer, "x-khmr", x_khmr),
FONT_PREF_LANG(Malayalam, "x-mlym", x_mlym),
FONT_PREF_LANG(Oriya, "x-orya", x_orya),
FONT_PREF_LANG(Telugu, "x-telu", x_telu),
FONT_PREF_LANG(Kannada, "x-knda", x_knda),
FONT_PREF_LANG(Sinhala, "x-sinh", x_sinh),
FONT_PREF_LANG(Tibetan, "x-tibt", x_tibt),
FONT_PREF_LANG(Others, "x-unicode", Unicode)
+7 -8
View File
@@ -1005,13 +1005,13 @@ gfxFcFontSet::SortPreferredFonts(bool &aWaitForUserFont)
// Aliases seem to often end up occurring more than once, but
// duplicate families can't be removed from the sort pattern without
// knowing whether duplicates have the same binding.
gfxFontconfigUtils::DepFcStrEntry *entry =
gfxFontconfigUtils::DepFcStrEntry *familyEntry =
existingFamilies.PutEntry(family);
if (entry) {
if (entry->mKey) // old entry
if (familyEntry) {
if (familyEntry->mKey) // old entry
continue;
entry->mKey = family; // initialize new entry
familyEntry->mKey = family; // initialize new entry
}
for (uint32_t f = 0; f < familyFonts->Length(); ++f) {
@@ -1032,10 +1032,10 @@ gfxFcFontSet::SortPreferredFonts(bool &aWaitForUserFont)
continue;
for (uint32_t r = 0; r < requiredLangs.Length(); ++r) {
const LangSupportEntry& entry = requiredLangs[r];
const LangSupportEntry& langEntry = requiredLangs[r];
FcLangResult support =
gfxFontconfigUtils::GetLangSupport(font, entry.mLang);
if (support <= entry.mBestSupport) { // lower is better
gfxFontconfigUtils::GetLangSupport(font, langEntry.mLang);
if (support <= langEntry.mBestSupport) { // lower is better
requiredLangs.RemoveElementAt(r);
--r;
}
@@ -2158,4 +2158,3 @@ gfxFcFont::GetGlyphRenderingOptions(const TextRunDrawParams* aRunParams)
return mozilla::gfx::Factory::CreateCairoGlyphRenderingOptions(hinting, false, aaMode);
}
#endif
+1 -2
View File
@@ -72,7 +72,7 @@ struct GrFontFeatures {
gr_feature_val *mFeatures;
};
static PLDHashOperator
static void
AddFeature(const uint32_t& aTag, uint32_t& aValue, void *aUserArg)
{
GrFontFeatures *f = static_cast<GrFontFeatures*>(aUserArg);
@@ -81,7 +81,6 @@ AddFeature(const uint32_t& aTag, uint32_t& aValue, void *aUserArg)
if (fref) {
gr_fref_set_feature_value(fref, aValue, f->mFeatures);
}
return PL_DHASH_NEXT;
}
bool
+214 -40
View File
@@ -17,6 +17,16 @@
#include "harfbuzz/hb.h"
#include "harfbuzz/hb-ot.h"
#if ENABLE_INTL_API // ICU is available: we'll use it for Unicode composition
// and decomposition in preference to nsUnicodeNormalizer.
#include "unicode/unorm.h"
#include "unicode/utext.h"
#define MOZ_HB_SHAPER_USE_ICU_NORMALIZATION 1
static const UNormalizer2 * sNormalizer = nullptr;
#else
#undef MOZ_HB_SHAPER_USE_ICU_NORMALIZATION
#endif
#include <algorithm>
#define FloatToFixed(f) (65536 * (f))
@@ -175,6 +185,61 @@ gfxHarfBuzzShaper::GetGlyph(hb_codepoint_t unicode,
return gid;
}
static int
VertFormsGlyphCompare(const void* aKey, const void* aElem)
{
return int(*((hb_codepoint_t*)(aKey))) - int(*((uint16_t*)(aElem)));
}
// Return a vertical presentation-form codepoint corresponding to the
// given Unicode value, or 0 if no such form is available.
static hb_codepoint_t
GetVerticalPresentationForm(hb_codepoint_t unicode)
{
static const uint16_t sVerticalForms[][2] = {
{ 0x2013, 0xfe32 }, // EN DASH
{ 0x2014, 0xfe31 }, // EM DASH
{ 0x2025, 0xfe30 }, // TWO DOT LEADER
{ 0x2026, 0xfe19 }, // HORIZONTAL ELLIPSIS
{ 0x3001, 0xfe11 }, // IDEOGRAPHIC COMMA
{ 0x3002, 0xfe12 }, // IDEOGRAPHIC FULL STOP
{ 0x3008, 0xfe3f }, // LEFT ANGLE BRACKET
{ 0x3009, 0xfe40 }, // RIGHT ANGLE BRACKET
{ 0x300a, 0xfe3d }, // LEFT DOUBLE ANGLE BRACKET
{ 0x300b, 0xfe3e }, // RIGHT DOUBLE ANGLE BRACKET
{ 0x300c, 0xfe41 }, // LEFT CORNER BRACKET
{ 0x300d, 0xfe42 }, // RIGHT CORNER BRACKET
{ 0x300e, 0xfe43 }, // LEFT WHITE CORNER BRACKET
{ 0x300f, 0xfe44 }, // RIGHT WHITE CORNER BRACKET
{ 0x3010, 0xfe3b }, // LEFT BLACK LENTICULAR BRACKET
{ 0x3011, 0xfe3c }, // RIGHT BLACK LENTICULAR BRACKET
{ 0x3014, 0xfe39 }, // LEFT TORTOISE SHELL BRACKET
{ 0x3015, 0xfe3a }, // RIGHT TORTOISE SHELL BRACKET
{ 0x3016, 0xfe17 }, // LEFT WHITE LENTICULAR BRACKET
{ 0x3017, 0xfe18 }, // RIGHT WHITE LENTICULAR BRACKET
{ 0xfe4f, 0xfe34 }, // WAVY LOW LINE
{ 0xff01, 0xfe15 }, // FULLWIDTH EXCLAMATION MARK
{ 0xff08, 0xfe35 }, // FULLWIDTH LEFT PARENTHESIS
{ 0xff09, 0xfe36 }, // FULLWIDTH RIGHT PARENTHESIS
{ 0xff0c, 0xfe10 }, // FULLWIDTH COMMA
{ 0xff1a, 0xfe13 }, // FULLWIDTH COLON
{ 0xff1b, 0xfe14 }, // FULLWIDTH SEMICOLON
{ 0xff1f, 0xfe16 }, // FULLWIDTH QUESTION MARK
{ 0xff3b, 0xfe47 }, // FULLWIDTH LEFT SQUARE BRACKET
{ 0xff3d, 0xfe48 }, // FULLWIDTH RIGHT SQUARE BRACKET
{ 0xff3f, 0xfe33 }, // FULLWIDTH LOW LINE
{ 0xff5b, 0xfe37 }, // FULLWIDTH LEFT CURLY BRACKET
{ 0xff5d, 0xfe38 } // FULLWIDTH RIGHT CURLY BRACKET
};
const uint16_t* charPair =
static_cast<const uint16_t*>(bsearch(&unicode,
sVerticalForms,
ArrayLength(sVerticalForms),
sizeof(sVerticalForms[0]),
VertFormsGlyphCompare));
return charPair ? charPair[1] : 0;
}
static hb_bool_t
HBGetGlyph(hb_font_t *font, void *font_data,
hb_codepoint_t unicode, hb_codepoint_t variation_selector,
@@ -183,6 +248,18 @@ HBGetGlyph(hb_font_t *font, void *font_data,
{
const gfxHarfBuzzShaper::FontCallbackData *fcd =
static_cast<const gfxHarfBuzzShaper::FontCallbackData*>(font_data);
if (fcd->mShaper->UseVerticalPresentationForms()) {
hb_codepoint_t verticalForm = GetVerticalPresentationForm(unicode);
if (verticalForm) {
*glyph = fcd->mShaper->GetGlyph(verticalForm, variation_selector);
if (*glyph != 0) {
return true;
}
}
// fall back to the non-vertical form if we didn't find an alternate
}
*glyph = fcd->mShaper->GetGlyph(unicode, variation_selector);
return *glyph != 0;
}
@@ -356,15 +433,22 @@ gfxHarfBuzzShaper::GetGlyphVOrigin(hb_codepoint_t aGlyph,
return;
}
if (aGlyph >= uint32_t(mNumLongVMetrics)) {
aGlyph = mNumLongVMetrics - 1;
}
const GlyphMetrics* metrics =
reinterpret_cast<const GlyphMetrics*>
(hb_blob_get_data(mVmtxTable, nullptr));
int16_t lsb;
if (aGlyph < hb_codepoint_t(mNumLongVMetrics)) {
// Glyph is covered by the first (advance & sidebearing) array
lsb = int16_t(metrics->metrics[aGlyph].lsb);
} else {
// Glyph is covered by the second (sidebearing-only) array
const AutoSwap_PRInt16* sidebearings =
reinterpret_cast<const AutoSwap_PRInt16*>
(&metrics->metrics[mNumLongVMetrics]);
lsb = int16_t(sidebearings[aGlyph - mNumLongVMetrics]);
}
*aY = -FloatToFixed(mFont->FUnitsToDevUnitsFactor() *
(int16_t(metrics->metrics[aGlyph].lsb) +
int16_t(glyf->yMax)));
(lsb + int16_t(glyf->yMax)));
return;
} else {
// XXX TODO: not a truetype font; need to get glyph extents
@@ -383,8 +467,11 @@ gfxHarfBuzzShaper::GetGlyphVOrigin(hb_codepoint_t aGlyph,
reinterpret_cast<const MetricsHeader*>(hb_blob_get_data(hheaTable,
&len));
if (len >= sizeof(MetricsHeader)) {
*aY = -FloatToFixed(GetFont()->FUnitsToDevUnitsFactor() *
int16_t(hhea->ascender));
// divide up the default advance we're using (1em) in proportion
// to ascender:descender from the hhea table
int16_t a = int16_t(hhea->ascender);
int16_t d = int16_t(hhea->descender);
*aY = -FloatToFixed(GetFont()->GetAdjustedSize() * a / (a - d));
return;
}
}
@@ -976,89 +1063,107 @@ HBUnicodeCompose(hb_unicode_funcs_t *ufuncs,
hb_codepoint_t *ab,
void *user_data)
{
hb_bool_t found = nsUnicodeNormalizer::Compose(a, b, ab);
#if MOZ_HB_SHAPER_USE_ICU_NORMALIZATION
if (!found && (b & 0x1fff80) == 0x0580) {
if (sNormalizer) {
UChar32 ch = unorm2_composePair(sNormalizer, a, b);
if (ch >= 0) {
*ab = ch;
return true;
}
}
#else // no ICU available, use the old nsUnicodeNormalizer
if (nsUnicodeNormalizer::Compose(a, b, ab)) {
return true;
}
#endif
if ((b & 0x1fff80) == 0x0580) {
// special-case Hebrew presentation forms that are excluded from
// standard normalization, but wanted for old fonts
switch (b) {
case 0x05B4: // HIRIQ
if (a == 0x05D9) { // YOD
*ab = 0xFB1D;
found = true;
return true;
}
break;
case 0x05B7: // patah
if (a == 0x05F2) { // YIDDISH YOD YOD
*ab = 0xFB1F;
found = true;
} else if (a == 0x05D0) { // ALEF
return true;
}
if (a == 0x05D0) { // ALEF
*ab = 0xFB2E;
found = true;
return true;
}
break;
case 0x05B8: // QAMATS
if (a == 0x05D0) { // ALEF
*ab = 0xFB2F;
found = true;
return true;
}
break;
case 0x05B9: // HOLAM
if (a == 0x05D5) { // VAV
*ab = 0xFB4B;
found = true;
return true;
}
break;
case 0x05BC: // DAGESH
if (a >= 0x05D0 && a <= 0x05EA) {
*ab = sDageshForms[a - 0x05D0];
found = (*ab != 0);
} else if (a == 0xFB2A) { // SHIN WITH SHIN DOT
return (*ab != 0);
}
if (a == 0xFB2A) { // SHIN WITH SHIN DOT
*ab = 0xFB2C;
found = true;
} else if (a == 0xFB2B) { // SHIN WITH SIN DOT
return true;
}
if (a == 0xFB2B) { // SHIN WITH SIN DOT
*ab = 0xFB2D;
found = true;
return true;
}
break;
case 0x05BF: // RAFE
switch (a) {
case 0x05D1: // BET
*ab = 0xFB4C;
found = true;
break;
return true;
case 0x05DB: // KAF
*ab = 0xFB4D;
found = true;
break;
return true;
case 0x05E4: // PE
*ab = 0xFB4E;
found = true;
break;
return true;
}
break;
case 0x05C1: // SHIN DOT
if (a == 0x05E9) { // SHIN
*ab = 0xFB2A;
found = true;
} else if (a == 0xFB49) { // SHIN WITH DAGESH
return true;
}
if (a == 0xFB49) { // SHIN WITH DAGESH
*ab = 0xFB2C;
found = true;
return true;
}
break;
case 0x05C2: // SIN DOT
if (a == 0x05E9) { // SHIN
*ab = 0xFB2B;
found = true;
} else if (a == 0xFB49) { // SHIN WITH DAGESH
return true;
}
if (a == 0xFB49) { // SHIN WITH DAGESH
*ab = 0xFB2D;
found = true;
return true;
}
break;
}
}
return found;
return false;
}
static hb_bool_t
@@ -1077,10 +1182,49 @@ HBUnicodeDecompose(hb_unicode_funcs_t *ufuncs,
return true;
}
#endif
#if MOZ_HB_SHAPER_USE_ICU_NORMALIZATION
if (!sNormalizer) {
return false;
}
// Canonical decompositions are never more than two characters,
// or a maximum of 4 utf-16 code units.
const unsigned MAX_DECOMP_LENGTH = 4;
UErrorCode error = U_ZERO_ERROR;
UChar decomp[MAX_DECOMP_LENGTH];
int32_t len = unorm2_getRawDecomposition(sNormalizer, ab, decomp,
MAX_DECOMP_LENGTH, &error);
if (U_FAILURE(error) || len < 0) {
return false;
}
UText text = UTEXT_INITIALIZER;
utext_openUChars(&text, decomp, len, &error);
NS_ASSERTION(U_SUCCESS(error), "UText failure?");
UChar32 ch = UTEXT_NEXT32(&text);
if (ch != U_SENTINEL) {
*a = ch;
}
ch = UTEXT_NEXT32(&text);
if (ch != U_SENTINEL) {
*b = ch;
}
utext_close(&text);
return *b != 0 || *a != ab;
#else // no ICU available, use the old nsUnicodeNormalizer
return nsUnicodeNormalizer::DecomposeNonRecursively(ab, a, b);
#endif
}
static PLDHashOperator
static void
AddOpenTypeFeature(const uint32_t& aTag, uint32_t& aValue, void *aUserArg)
{
nsTArray<hb_feature_t>* features = static_cast<nsTArray<hb_feature_t>*> (aUserArg);
@@ -1089,7 +1233,6 @@ AddOpenTypeFeature(const uint32_t& aTag, uint32_t& aValue, void *aUserArg)
feat.tag = aTag;
feat.value = aValue;
features->AppendElement(feat);
return PL_DHASH_NEXT;
}
/*
@@ -1159,6 +1302,12 @@ gfxHarfBuzzShaper::Initialize()
hb_unicode_funcs_set_decompose_func(sHBUnicodeFuncs,
HBUnicodeDecompose,
nullptr, nullptr);
#if MOZ_HB_SHAPER_USE_ICU_NORMALIZATION
UErrorCode error = U_ZERO_ERROR;
sNormalizer = unorm2_getNFCInstance(&error);
NS_ASSERTION(U_SUCCESS(error), "failed to get ICU normalizer");
#endif
}
gfxFontEntry *entry = mFont->GetFontEntry();
@@ -1219,7 +1368,7 @@ gfxHarfBuzzShaper::LoadHmtxTable()
// (this method will return FALSE below if mHmtxTable
// is null)
mHmtxTable = entry->GetFontTable(TRUETYPE_TAG('h','m','t','x'));
if (hb_blob_get_length(mHmtxTable) <
if (mHmtxTable && hb_blob_get_length(mHmtxTable) <
mNumLongHMetrics * sizeof(LongMetric)) {
// metrics table is not large enough for the claimed
// number of entries: invalid, do not use.
@@ -1238,6 +1387,13 @@ gfxHarfBuzzShaper::LoadHmtxTable()
bool
gfxHarfBuzzShaper::InitializeVertical()
{
// We only try this once. If we don't have a mHmtxTable after that,
// this font can't handle vertical shaping, so return false.
if (mVerticalInitialized) {
return mHmtxTable != nullptr;
}
mVerticalInitialized = true;
if (!mHmtxTable) {
if (!LoadHmtxTable()) {
return false;
@@ -1255,11 +1411,22 @@ gfxHarfBuzzShaper::InitializeVertical()
(hb_blob_get_data(vheaTable, &len));
if (len >= sizeof(MetricsHeader)) {
mNumLongVMetrics = vhea->numOfLongMetrics;
if (mNumLongVMetrics > 0 &&
gfxFontEntry::AutoTable
maxpTable(entry, TRUETYPE_TAG('m','a','x','p'));
int numGlyphs = -1; // invalid if we fail to read 'maxp'
if (maxpTable &&
hb_blob_get_length(maxpTable) >= sizeof(MaxpTableHeader)) {
const MaxpTableHeader* maxp =
reinterpret_cast<const MaxpTableHeader*>
(hb_blob_get_data(maxpTable, nullptr));
numGlyphs = uint16_t(maxp->numGlyphs);
}
if (mNumLongVMetrics > 0 && mNumLongVMetrics <= numGlyphs &&
int16_t(vhea->metricDataFormat) == 0) {
mVmtxTable = entry->GetFontTable(TRUETYPE_TAG('v','m','t','x'));
if (hb_blob_get_length(mVmtxTable) <
mNumLongVMetrics * sizeof(LongMetric)) {
if (mVmtxTable && hb_blob_get_length(mVmtxTable) <
mNumLongVMetrics * sizeof(LongMetric) +
(numGlyphs - mNumLongVMetrics) * sizeof(int16_t)) {
// metrics table is not large enough for the claimed
// number of entries: invalid, do not use.
hb_blob_destroy(mVmtxTable);
@@ -1309,6 +1476,7 @@ gfxHarfBuzzShaper::ShapeText(gfxContext *aContext,
}
mCallbackData.mContext = aContext;
mUseVerticalPresentationForms = false;
if (!Initialize()) {
return false;
@@ -1318,6 +1486,10 @@ gfxHarfBuzzShaper::ShapeText(gfxContext *aContext,
if (!InitializeVertical()) {
return false;
}
if (!mFont->GetFontEntry()->
SupportsOpenTypeFeature(aScript, HB_TAG('v','e','r','t'))) {
mUseVerticalPresentationForms = true;
}
}
const gfxFontStyle *style = mFont->GetStyle();
@@ -1385,6 +1557,8 @@ gfxHarfBuzzShaper::ShapeText(gfxContext *aContext,
reinterpret_cast<const uint16_t*>(aText),
length, 0, length);
hb_buffer_set_cluster_level(buffer, HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS);
hb_shape(mHBFont, buffer, features.Elements(), features.Length());
if (isRightToLeft) {
@@ -1608,7 +1782,7 @@ gfxHarfBuzzShaper::SetGlyphsFromRun(gfxContext *aContext,
charGlyphs[baseCharIndex].SetSimpleGlyph(advance,
ginfo[glyphStart].codepoint);
} else {
// collect all glyphs in a list to be assigned to the first char;
// Collect all glyphs in a list to be assigned to the first char;
// there must be at least one in the clump, and we already measured
// its advance, hence the placement of the loop-exit test and the
// measurement of the next glyph.
+9
View File
@@ -76,6 +76,11 @@ public:
hb_bool_t GetGlyphExtents(hb_codepoint_t aGlyph,
hb_glyph_extents_t *aExtents) const;
bool UseVerticalPresentationForms() const
{
return mUseVerticalPresentationForms;
}
static hb_script_t
GetHBScriptUsedForShaping(int32_t aScript) {
// Decide what harfbuzz script code will be used for shaping
@@ -176,6 +181,10 @@ protected:
bool mInitialized;
bool mVerticalInitialized;
// Whether to use vertical presentation forms for CJK characters
// when available (only set if the 'vert' feature is not available).
bool mUseVerticalPresentationForms;
// these are set from the FindGlyf callback on first use of the glyf data
mutable bool mLoadedLocaGlyf;
mutable bool mLocaLongOffsets;
+18 -17
View File
@@ -160,7 +160,7 @@ MacOSFontEntry::ReadCMAP(FontInfoData *aFontInfoData)
nsRefPtr<gfxCharacterMap> charmap;
nsresult rv;
bool symbolFont;
bool symbolFont = false; // currently ignored
if (aFontInfoData && (charmap = GetCMAPFromFontInfo(aFontInfoData,
mUVSOffset,
@@ -172,7 +172,7 @@ MacOSFontEntry::ReadCMAP(FontInfoData *aFontInfoData)
AutoTable cmapTable(this, kCMAP);
if (cmapTable) {
bool unicodeFont = false, symbolFont = false; // currently ignored
bool unicodeFont = false; // currently ignored
uint32_t cmapLen;
const uint8_t* cmapData =
reinterpret_cast<const uint8_t*>(hb_blob_get_data(cmapTable,
@@ -812,7 +812,7 @@ gfxMacPlatformFontList::GlobalFontFallback(const uint32_t aCh,
CFStringRef str;
UniChar ch[2];
CFIndex len = 1;
CFIndex length = 1;
if (IS_IN_BMP(aCh)) {
ch[0] = aCh;
@@ -826,7 +826,7 @@ gfxMacPlatformFontList::GlobalFontFallback(const uint32_t aCh,
if (!str) {
return nullptr;
}
len = 2;
length = 2;
}
// use CoreText to find the fallback family
@@ -841,27 +841,27 @@ gfxMacPlatformFontList::GlobalFontFallback(const uint32_t aCh,
}
fallback = ::CTFontCreateForString(mDefaultFont, str,
::CFRangeMake(0, len));
::CFRangeMake(0, length));
if (fallback) {
CFStringRef familyName = ::CTFontCopyFamilyName(fallback);
CFStringRef familyNameRef = ::CTFontCopyFamilyName(fallback);
::CFRelease(fallback);
if (familyName &&
::CFStringCompare(familyName, CFSTR("LastResort"),
if (familyNameRef &&
::CFStringCompare(familyNameRef, CFSTR("LastResort"),
kCFCompareCaseInsensitive) != kCFCompareEqualTo)
{
nsAutoTArray<UniChar, 1024> buffer;
CFIndex len = ::CFStringGetLength(familyName);
buffer.SetLength(len+1);
::CFStringGetCharacters(familyName, ::CFRangeMake(0, len),
CFIndex familyNameLen = ::CFStringGetLength(familyNameRef);
buffer.SetLength(familyNameLen+1);
::CFStringGetCharacters(familyNameRef, ::CFRangeMake(0, familyNameLen),
buffer.Elements());
buffer[len] = 0;
nsDependentString familyName(reinterpret_cast<char16_t*>(buffer.Elements()), len);
buffer[familyNameLen] = 0;
nsDependentString familyNameString(reinterpret_cast<char16_t*>(buffer.Elements()), familyNameLen);
bool needsBold; // ignored in the system fallback case
gfxFontFamily *family = FindFamily(familyName);
gfxFontFamily *family = FindFamily(familyNameString);
if (family) {
fontEntry = family->FindFontForStyle(*aMatchStyle, needsBold);
if (fontEntry) {
@@ -875,8 +875,8 @@ gfxMacPlatformFontList::GlobalFontFallback(const uint32_t aCh,
}
}
if (familyName) {
::CFRelease(familyName);
if (familyNameRef) {
::CFRelease(familyNameRef);
}
}
@@ -1083,12 +1083,13 @@ MacFontInfo::LoadFontFamilyData(const nsAString& aFamilyName)
kCTFontTableOptionNoOptions);
if (cmapTable) {
bool unicodeFont = false, symbolFont = false; // ignored
const uint8_t *cmapData =
(const uint8_t*)CFDataGetBytePtr(cmapTable);
uint32_t cmapLen = CFDataGetLength(cmapTable);
nsRefPtr<gfxCharacterMap> charmap = new gfxCharacterMap();
uint32_t offset;
bool unicodeFont = false; // ignored
bool symbolFont = false;
nsresult rv;
rv = gfxFontUtils::ReadCMAP(cmapData, cmapLen, *charmap, offset,
-6
View File
@@ -219,12 +219,6 @@ gfxPattern::GetSolidColor(Color& aColorOut)
return false;
}
gfxPattern::GraphicsPatternType
gfxPattern::GetType() const
{
return ThebesPatternType(mGfxPattern.GetPattern()->GetType());
}
int
gfxPattern::CairoStatus()
{
-9
View File
@@ -74,15 +74,6 @@ public:
void SetExtend(GraphicsExtend extend);
GraphicsExtend Extend() const;
enum GraphicsPatternType {
PATTERN_SOLID,
PATTERN_SURFACE,
PATTERN_LINEAR,
PATTERN_RADIAL
};
GraphicsPatternType GetType() const;
int CairoStatus();
void SetFilter(GraphicsFilter filter);
+69 -89
View File
@@ -52,13 +52,18 @@
#include "gfxGraphiteShaper.h"
#include "gfx2DGlue.h"
#include "gfxGradientCache.h"
#include "gfxUtils.h" // for NextPowerOfTwo
#include "nsUnicodeRange.h"
#include "nsServiceManagerUtils.h"
#include "nsTArray.h"
#include "nsILocaleService.h"
#include "nsIObserverService.h"
#include "nsIScreenManager.h"
#include "MainThreadUtils.h"
#ifdef MOZ_CRASHREPORTER
#include "nsExceptionHandler.h"
#endif
#include "nsWeakReference.h"
@@ -86,13 +91,21 @@
#endif
#include "mozilla/Hal.h"
#ifdef USE_SKIA
#include "skia/include/core/SkGraphics.h"
# ifdef __GNUC__
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wshadow"
# endif
# include "skia/include/core/SkGraphics.h"
# ifdef USE_SKIA_GPU
# include "skia/include/gpu/GrContext.h"
# include "skia/include/gpu/gl/GrGLInterface.h"
# include "SkiaGLGlue.h"
# endif
# ifdef __GNUC__
# pragma GCC diagnostic pop // -Wshadow
# endif
#endif
#if !defined(USE_SKIA) || !defined(USE_SKIA_GPU)
@@ -351,71 +364,26 @@ MemoryPressureObserver::Observe(nsISupports *aSubject,
return NS_OK;
}
// this needs to match the list of pref font.default.xx entries listed in all.js!
// the order *must* match the order in eFontPrefLang
// xxx - this can probably be eliminated by reworking pref font handling code
static const char *gPrefLangNames[] = {
"x-western",
"ja",
"zh-TW",
"zh-CN",
"zh-HK",
"ko",
"x-cyrillic",
"el",
"th",
"he",
"ar",
"x-devanagari",
"x-tamil",
"x-armn",
"x-beng",
"x-cans",
"x-ethi",
"x-geor",
"x-gujr",
"x-guru",
"x-khmr",
"x-mlym",
"x-orya",
"x-telu",
"x-knda",
"x-sinh",
"x-tibt",
"x-unicode",
#define FONT_PREF_LANG(enum_id_, str_, atom_id_) str_
#include "gfxFontPrefLangList.h"
#undef FONT_PREF_LANG
};
// this needs to match the list of pref font.default.xx entries listed in all.js!
// the order *must* match the order in eFontPrefLang
static nsIAtom* gPrefLangToLangGroups[] = {
nsGkAtoms::x_western,
nsGkAtoms::Japanese,
nsGkAtoms::Taiwanese,
nsGkAtoms::Chinese,
nsGkAtoms::HongKongChinese,
nsGkAtoms::ko,
nsGkAtoms::x_cyrillic,
nsGkAtoms::el,
nsGkAtoms::th,
nsGkAtoms::he,
nsGkAtoms::ar,
nsGkAtoms::x_devanagari,
nsGkAtoms::x_tamil,
nsGkAtoms::x_armn,
nsGkAtoms::x_beng,
nsGkAtoms::x_cans,
nsGkAtoms::x_ethi,
nsGkAtoms::x_geor,
nsGkAtoms::x_gujr,
nsGkAtoms::x_guru,
nsGkAtoms::x_khmr,
nsGkAtoms::x_mlym,
nsGkAtoms::x_orya,
nsGkAtoms::x_telu,
nsGkAtoms::x_knda,
nsGkAtoms::x_sinh,
nsGkAtoms::x_tibt,
nsGkAtoms::Unicode
};
static nsIAtom* PrefLangToLangGroups(uint32_t aIndex)
{
// static array here avoids static constructor
static nsIAtom* gPrefLangToLangGroups[] = {
#define FONT_PREF_LANG(enum_id_, str_, atom_id_) nsGkAtoms::atom_id_
#include "gfxFontPrefLangList.h"
#undef FONT_PREF_LANG
};
return aIndex < ArrayLength(gPrefLangToLangGroups)
? gPrefLangToLangGroups[aIndex]
: nsGkAtoms::Unicode;
}
gfxPlatform::gfxPlatform()
: mTileWidth(-1)
@@ -423,6 +391,7 @@ gfxPlatform::gfxPlatform()
, mAzureCanvasBackendCollector(this, &gfxPlatform::GetAzureBackendInfo)
, mApzSupportCollector(this, &gfxPlatform::GetApzSupportInfo)
, mCompositorBackend(layers::LayersBackend::LAYERS_NONE)
, mScreenDepth(0)
{
mAllowDownloadableFonts = UNINITIALIZED_VALUE;
mFallbackUsesCmaps = UNINITIALIZED_VALUE;
@@ -547,6 +516,9 @@ gfxPlatform::Init()
InitLayersAccelerationPrefs();
InitLayersIPC();
gPlatform->PopulateScreenInfo();
gPlatform->ComputeTileSize();
nsresult rv;
bool usePlatformFontList = true;
@@ -719,14 +691,10 @@ gfxPlatform::InitLayersIPC()
if (XRE_IsParentProcess())
{
mozilla::layers::CompositorParent::StartUp();
#ifndef MOZ_WIDGET_GONK
if (gfxPrefs::AsyncVideoEnabled()) {
mozilla::layers::ImageBridgeChild::StartUp();
}
#else
mozilla::layers::ImageBridgeChild::StartUp();
#ifdef MOZ_WIDGET_GONK
SharedBufferManagerChild::StartUp();
#endif
mozilla::layers::ImageBridgeChild::StartUp();
}
}
@@ -1051,26 +1019,29 @@ gfxPlatform::ComputeTileSize()
// The tile size should be picked in the parent processes
// and sent to the child processes over IPDL GetTileSize.
if (!XRE_IsParentProcess()) {
NS_RUNTIMEABORT("wrong process.");
return;
}
int32_t w = gfxPrefs::LayersTileWidth();
int32_t h = gfxPrefs::LayersTileHeight();
// TODO We may want to take the screen size into consideration here.
if (gfxPrefs::LayersTilesAdjust()) {
gfx::IntSize screenSize = GetScreenSize();
if (screenSize.width > 0) {
// FIXME: we should probably make sure this is within the max texture size,
// but I think everything should at least support 1024
w = h = std::max(std::min(NextPowerOfTwo(screenSize.width) / 2, 1024), 256);
}
#ifdef MOZ_WIDGET_GONK
int32_t format = android::PIXEL_FORMAT_RGBA_8888;
android::sp<android::GraphicBuffer> alloc =
new android::GraphicBuffer(gfxPrefs::LayersTileWidth(), gfxPrefs::LayersTileHeight(),
format,
android::GraphicBuffer::USAGE_SW_READ_OFTEN |
android::GraphicBuffer::USAGE_SW_WRITE_OFTEN |
android::GraphicBuffer::USAGE_HW_TEXTURE);
new android::GraphicBuffer(w, h, android::PIXEL_FORMAT_RGBA_8888,
android::GraphicBuffer::USAGE_SW_READ_OFTEN |
android::GraphicBuffer::USAGE_SW_WRITE_OFTEN |
android::GraphicBuffer::USAGE_HW_TEXTURE);
if (alloc.get()) {
w = alloc->getStride(); // We want the tiles to be gralloc stride aligned.
// No need to adjust the height here.
}
#endif
}
@@ -1078,6 +1049,25 @@ gfxPlatform::ComputeTileSize()
SetTileSize(w, h);
}
void
gfxPlatform::PopulateScreenInfo()
{
nsCOMPtr<nsIScreenManager> manager = do_GetService("@mozilla.org/gfx/screenmanager;1");
MOZ_ASSERT(manager, "failed to get nsIScreenManager");
nsCOMPtr<nsIScreen> screen;
manager->GetPrimaryScreen(getter_AddRefs(screen));
if (!screen) {
// This can happen in xpcshell, for instance
return;
}
screen->GetColorDepth(&mScreenDepth);
int left, top;
screen->GetRect(&left, &top, &mScreenSize.width, &mScreenSize.height);
}
bool
gfxPlatform::SupportsAzureContentForDrawTarget(DrawTarget* aTarget)
{
@@ -1512,10 +1502,7 @@ gfxPlatform::GetLangGroupForPrefLang(eFontPrefLang aLang)
// calls to individual CJK pref langs before getting here
NS_ASSERTION(aLang != eFontPrefLang_CJKSet, "unresolved CJK set pref lang");
if (uint32_t(aLang) < ArrayLength(gPrefLangToLangGroups)) {
return gPrefLangToLangGroups[uint32_t(aLang)];
}
return nsGkAtoms::Unicode;
return PrefLangToLangGroups(uint32_t(aLang));
}
const char*
@@ -2173,13 +2160,6 @@ gfxPlatform::GetLog(eGfxLog aWhichLog)
return nullptr;
}
int
gfxPlatform::GetScreenDepth() const
{
NS_WARNING("GetScreenDepth not implemented on this platform -- returning 0!");
return 0;
}
mozilla::gfx::SurfaceFormat
gfxPlatform::Optimal2DFormatForContent(gfxContentType aContent)
{
+21 -40
View File
@@ -71,41 +71,12 @@ BackendTypeBit(BackendType b)
extern cairo_user_data_key_t kDrawTarget;
// pref lang id's for font prefs
// !!! needs to match the list of pref font.default.xx entries listed in all.js !!!
// !!! don't use as bit mask, this may grow larger !!!
enum eFontPrefLang {
eFontPrefLang_Western = 0,
eFontPrefLang_Japanese = 1,
eFontPrefLang_ChineseTW = 2,
eFontPrefLang_ChineseCN = 3,
eFontPrefLang_ChineseHK = 4,
eFontPrefLang_Korean = 5,
eFontPrefLang_Cyrillic = 6,
eFontPrefLang_Greek = 7,
eFontPrefLang_Thai = 8,
eFontPrefLang_Hebrew = 9,
eFontPrefLang_Arabic = 10,
eFontPrefLang_Devanagari = 11,
eFontPrefLang_Tamil = 12,
eFontPrefLang_Armenian = 13,
eFontPrefLang_Bengali = 14,
eFontPrefLang_Canadian = 15,
eFontPrefLang_Ethiopic = 16,
eFontPrefLang_Georgian = 17,
eFontPrefLang_Gujarati = 18,
eFontPrefLang_Gurmukhi = 19,
eFontPrefLang_Khmer = 20,
eFontPrefLang_Malayalam = 21,
eFontPrefLang_Oriya = 22,
eFontPrefLang_Telugu = 23,
eFontPrefLang_Kannada = 24,
eFontPrefLang_Sinhala = 25,
eFontPrefLang_Tibetan = 26,
#define FONT_PREF_LANG(enum_id_, str_, atom_id_) eFontPrefLang_ ## enum_id_
#include "gfxFontPrefLangList.h"
#undef FONT_PREF_LANG
eFontPrefLang_Others = 27, // x-unicode
eFontPrefLang_CJKSet = 28 // special code for CJK set
, eFontPrefLang_CJKSet // special code for CJK set
};
enum eCMSMode {
@@ -337,12 +308,6 @@ public:
int GetTileWidth();
int GetTileHeight();
void SetTileSize(int aWidth, int aHeight);
/**
* Calling this function will compute and set the ideal tile size for the
* platform. This should only be called in the parent process; child processes
* should be updated via SetTileSize to match the value computed in the parent.
*/
void ComputeTileSize();
/**
* Rebuilds the any cached system font lists
@@ -605,7 +570,8 @@ public:
*/
static PRLogModuleInfo* GetLog(eGfxLog aWhichLog);
virtual int GetScreenDepth() const;
int GetScreenDepth() const { return mScreenDepth; }
mozilla::gfx::IntSize GetScreenSize() const { return mScreenSize; }
/**
* Return the layer debugging options to use browser-wide.
@@ -792,6 +758,18 @@ private:
virtual void GetPlatformCMSOutputProfile(void *&mem, size_t &size);
/**
* Calling this function will compute and set the ideal tile size for the
* platform. This will only have an effect in the parent process; child processes
* should be updated via SetTileSize to match the value computed in the parent.
*/
void ComputeTileSize();
/**
* This uses nsIScreenManager to determine the screen size and color depth
*/
void PopulateScreenInfo();
nsRefPtr<gfxASurface> mScreenReferenceSurface;
nsTArray<uint32_t> mCJKPrefLangs;
nsCOMPtr<nsIObserver> mSRGBOverrideObserver;
@@ -819,6 +797,9 @@ private:
// Backend that we are compositing with. NONE, if no compositor has been
// created yet.
mozilla::layers::LayersBackend mCompositorBackend;
int32_t mScreenDepth;
mozilla::gfx::IntSize mScreenSize;
};
#endif /* GFX_PLATFORM_H */
+87 -171
View File
@@ -163,7 +163,7 @@ gfxPlatformFontList::MemoryReporter::CollectReports(
gfxPlatformFontList::gfxPlatformFontList(bool aNeedFullnamePostscriptNames)
: mFontFamilies(64), mOtherFamilyNames(16),
mPrefFonts(8), mBadUnderlineFamilyNames(8), mSharedCmaps(8),
mStartIndex(0), mIncrement(1), mNumFamilies(0)
mStartIndex(0), mIncrement(1), mNumFamilies(0), mFontlistInitCount(0)
{
mOtherFamilyNamesInitialized = false;
@@ -195,6 +195,12 @@ gfxPlatformFontList::~gfxPlatformFontList()
nsresult
gfxPlatformFontList::InitFontList()
{
mFontlistInitCount++;
if (LOG_FONTINIT_ENABLED()) {
LOG_FONTINIT(("(fontinit) system fontlist initialization\n"));
}
// rebuilding fontlist so clear out font/word caches
gfxFontCache *fontCache = gfxFontCache::GetCache();
if (fontCache) {
@@ -231,18 +237,9 @@ gfxPlatformFontList::GenerateFontListKey(const nsAString& aKeyName, nsAString& a
ToLowerCase(aResult);
}
struct InitOtherNamesData {
InitOtherNamesData(gfxPlatformFontList *aFontList,
TimeStamp aStartTime)
: mFontList(aFontList), mStartTime(aStartTime), mTimedOut(false)
{}
#define OTHERNAMES_TIMEOUT 200
gfxPlatformFontList *mFontList;
TimeStamp mStartTime;
bool mTimedOut;
};
void
void
gfxPlatformFontList::InitOtherFamilyNames()
{
if (mOtherFamilyNamesInitialized) {
@@ -250,14 +247,19 @@ gfxPlatformFontList::InitOtherFamilyNames()
}
TimeStamp start = TimeStamp::Now();
bool timedOut = false;
// iterate over all font families and read in other family names
InitOtherNamesData otherNamesData(this, start);
for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) {
nsRefPtr<gfxFontFamily>& family = iter.Data();
family->ReadOtherFamilyNames(this);
TimeDuration elapsed = TimeStamp::Now() - start;
if (elapsed.ToMilliseconds() > OTHERNAMES_TIMEOUT) {
timedOut = true;
break;
}
}
mFontFamilies.Enumerate(gfxPlatformFontList::InitOtherFamilyNamesProc,
&otherNamesData);
if (!otherNamesData.mTimedOut) {
if (!timedOut) {
mOtherFamilyNamesInitialized = true;
}
TimeStamp end = TimeStamp::Now();
@@ -268,55 +270,44 @@ gfxPlatformFontList::InitOtherFamilyNames()
TimeDuration elapsed = end - start;
LOG_FONTINIT(("(fontinit) InitOtherFamilyNames took %8.2f ms %s",
elapsed.ToMilliseconds(),
(otherNamesData.mTimedOut ? "timeout" : "")));
(timedOut ? "timeout" : "")));
}
}
#define OTHERNAMES_TIMEOUT 200
PLDHashOperator
gfxPlatformFontList::InitOtherFamilyNamesProc(nsStringHashKey::KeyType aKey,
nsRefPtr<gfxFontFamily>& aFamilyEntry,
void* userArg)
{
InitOtherNamesData *data = static_cast<InitOtherNamesData*>(userArg);
aFamilyEntry->ReadOtherFamilyNames(data->mFontList);
TimeDuration elapsed = TimeStamp::Now() - data->mStartTime;
if (elapsed.ToMilliseconds() > OTHERNAMES_TIMEOUT) {
data->mTimedOut = true;
return PL_DHASH_STOP;
}
return PL_DHASH_NEXT;
}
struct ReadFaceNamesData {
ReadFaceNamesData(gfxPlatformFontList *aFontList, TimeStamp aStartTime)
: mFontList(aFontList), mStartTime(aStartTime), mTimedOut(false),
mFirstChar(0)
{}
gfxPlatformFontList *mFontList;
TimeStamp mStartTime;
bool mTimedOut;
// if mFirstChar is not 0, only load facenames for families
// that start with this character
char16_t mFirstChar;
};
// time limit for loading facename lists (ms)
#define NAMELIST_TIMEOUT 200
gfxFontEntry*
gfxPlatformFontList::SearchFamiliesForFaceName(const nsAString& aFaceName)
{
TimeStamp start = TimeStamp::Now();
bool timedOut = false;
// if mFirstChar is not 0, only load facenames for families
// that start with this character
char16_t firstChar = 0;
gfxFontEntry *lookup = nullptr;
ReadFaceNamesData faceNameListsData(this, start);
// iterate over familes starting with the same letter
faceNameListsData.mFirstChar = ToLowerCase(aFaceName.CharAt(0));
mFontFamilies.Enumerate(gfxPlatformFontList::ReadFaceNamesProc,
&faceNameListsData);
firstChar = ToLowerCase(aFaceName.CharAt(0));
for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) {
nsStringHashKey::KeyType key = iter.Key();
nsRefPtr<gfxFontFamily>& family = iter.Data();
// when filtering, skip names that don't start with the filter character
if (firstChar && ToLowerCase(key.CharAt(0)) != firstChar) {
continue;
}
family->ReadFaceNames(this, NeedFullnamePostscriptNames());
TimeDuration elapsed = TimeStamp::Now() - start;
if (elapsed.ToMilliseconds() > NAMELIST_TIMEOUT) {
timedOut = true;
break;
}
}
lookup = FindFaceName(aFaceName);
TimeStamp end = TimeStamp::Now();
@@ -327,38 +318,12 @@ gfxPlatformFontList::SearchFamiliesForFaceName(const nsAString& aFaceName)
LOG_FONTINIT(("(fontinit) SearchFamiliesForFaceName took %8.2f ms %s %s",
elapsed.ToMilliseconds(),
(lookup ? "found name" : ""),
(faceNameListsData.mTimedOut ? "timeout" : "")));
(timedOut ? "timeout" : "")));
}
return lookup;
}
// time limit for loading facename lists (ms)
#define NAMELIST_TIMEOUT 200
PLDHashOperator
gfxPlatformFontList::ReadFaceNamesProc(nsStringHashKey::KeyType aKey,
nsRefPtr<gfxFontFamily>& aFamilyEntry,
void* userArg)
{
ReadFaceNamesData *data = static_cast<ReadFaceNamesData*>(userArg);
gfxPlatformFontList *fc = data->mFontList;
// when filtering, skip names that don't start with the filter character
if (data->mFirstChar && ToLowerCase(aKey.CharAt(0)) != data->mFirstChar) {
return PL_DHASH_NEXT;
}
aFamilyEntry->ReadFaceNames(fc, fc->NeedFullnamePostscriptNames());
TimeDuration elapsed = TimeStamp::Now() - data->mStartTime;
if (elapsed.ToMilliseconds() > NAMELIST_TIMEOUT) {
data->mTimedOut = true;
return PL_DHASH_STOP;
}
return PL_DHASH_NEXT;
}
gfxFontEntry*
gfxPlatformFontList::FindFaceName(const nsAString& aFaceName)
{
@@ -443,84 +408,49 @@ gfxPlatformFontList::UpdateFontList()
RebuildLocalFonts();
}
struct FontListData {
FontListData(nsIAtom *aLangGroup,
const nsACString& aGenericFamily,
nsTArray<nsString>& aListOfFonts) :
mLangGroup(aLangGroup), mGenericFamily(aGenericFamily),
mListOfFonts(aListOfFonts) {}
nsIAtom *mLangGroup;
const nsACString& mGenericFamily;
nsTArray<nsString>& mListOfFonts;
};
PLDHashOperator
gfxPlatformFontList::HashEnumFuncForFamilies(nsStringHashKey::KeyType aKey,
nsRefPtr<gfxFontFamily>& aFamilyEntry,
void *aUserArg)
{
FontListData *data = static_cast<FontListData*>(aUserArg);
// use the first variation for now. This data should be the same
// for all the variations and should probably be moved up to
// the Family
gfxFontStyle style;
style.language = data->mLangGroup;
bool needsBold;
nsRefPtr<gfxFontEntry> aFontEntry = aFamilyEntry->FindFontForStyle(style, needsBold);
NS_ASSERTION(aFontEntry, "couldn't find any font entry in family");
if (!aFontEntry)
return PL_DHASH_NEXT;
/* skip symbol fonts */
if (aFontEntry->IsSymbolFont())
return PL_DHASH_NEXT;
if (aFontEntry->SupportsLangGroup(data->mLangGroup) &&
aFontEntry->MatchesGenericFamily(data->mGenericFamily)) {
nsAutoString localizedFamilyName;
aFamilyEntry->LocalizedName(localizedFamilyName);
data->mListOfFonts.AppendElement(localizedFamilyName);
}
return PL_DHASH_NEXT;
}
void
gfxPlatformFontList::GetFontList(nsIAtom *aLangGroup,
const nsACString& aGenericFamily,
nsTArray<nsString>& aListOfFonts)
{
FontListData data(aLangGroup, aGenericFamily, aListOfFonts);
for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) {
nsRefPtr<gfxFontFamily>& family = iter.Data();
// use the first variation for now. This data should be the same
// for all the variations and should probably be moved up to
// the Family
gfxFontStyle style;
style.language = aLangGroup;
bool needsBold;
nsRefPtr<gfxFontEntry> fontEntry = family->FindFontForStyle(style, needsBold);
NS_ASSERTION(fontEntry, "couldn't find any font entry in family");
if (!fontEntry) {
continue;
}
mFontFamilies.Enumerate(gfxPlatformFontList::HashEnumFuncForFamilies, &data);
/* skip symbol fonts */
if (fontEntry->IsSymbolFont()) {
continue;
}
if (fontEntry->SupportsLangGroup(aLangGroup) &&
fontEntry->MatchesGenericFamily(aGenericFamily)) {
nsAutoString localizedFamilyName;
family->LocalizedName(localizedFamilyName);
aListOfFonts.AppendElement(localizedFamilyName);
}
}
aListOfFonts.Sort();
aListOfFonts.Compact();
}
struct FontFamilyListData {
explicit FontFamilyListData(nsTArray<nsRefPtr<gfxFontFamily> >& aFamilyArray)
: mFamilyArray(aFamilyArray)
{}
static PLDHashOperator AppendFamily(nsStringHashKey::KeyType aKey,
nsRefPtr<gfxFontFamily>& aFamilyEntry,
void *aUserArg)
{
FontFamilyListData *data = static_cast<FontFamilyListData*>(aUserArg);
data->mFamilyArray.AppendElement(aFamilyEntry);
return PL_DHASH_NEXT;
}
nsTArray<nsRefPtr<gfxFontFamily> >& mFamilyArray;
};
void
gfxPlatformFontList::GetFontFamilyList(nsTArray<nsRefPtr<gfxFontFamily> >& aFamilyArray)
{
FontFamilyListData data(aFamilyArray);
mFontFamilies.Enumerate(FontFamilyListData::AppendFamily, &data);
for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) {
nsRefPtr<gfxFontFamily>& family = iter.Data();
aFamilyArray.AppendElement(family);
}
}
gfxFontEntry*
@@ -610,18 +540,6 @@ gfxPlatformFontList::SystemFindFontForChar(uint32_t aCh, uint32_t aNextCh,
return fontEntry;
}
PLDHashOperator
gfxPlatformFontList::FindFontForCharProc(nsStringHashKey::KeyType aKey, nsRefPtr<gfxFontFamily>& aFamilyEntry,
void *userArg)
{
GlobalFontMatch *data = static_cast<GlobalFontMatch*>(userArg);
// evaluate all fonts in this family for a match
aFamilyEntry->FindFontForChar(data);
return PL_DHASH_NEXT;
}
#define NUM_FALLBACK_FONTS 8
gfxFontEntry*
@@ -671,7 +589,11 @@ gfxPlatformFontList::GlobalFontFallback(const uint32_t aCh,
GlobalFontMatch data(aCh, aRunScript, aMatchStyle);
// iterate over all font families to find a font that support the character
mFontFamilies.Enumerate(gfxPlatformFontList::FindFontForCharProc, &data);
for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) {
nsRefPtr<gfxFontFamily>& family = iter.Data();
// evaluate all fonts in this family for a match
family->FindFontForChar(&data);
}
aCmapCount = data.mCmapsTested;
*aMatchedFamily = data.mMatchedFamily;
@@ -879,22 +801,16 @@ gfxPlatformFontList::RemoveCmap(const gfxCharacterMap* aCharMap)
}
}
static PLDHashOperator AppendFamilyToList(nsStringHashKey::KeyType aKey,
nsRefPtr<gfxFontFamily>& aFamilyEntry,
void *aUserArg)
{
nsTArray<nsString> *familyNames = static_cast<nsTArray<nsString> *>(aUserArg);
familyNames->AppendElement(aFamilyEntry->Name());
return PL_DHASH_NEXT;
}
void
gfxPlatformFontList::GetFontFamilyNames(nsTArray<nsString>& aFontFamilyNames)
{
mFontFamilies.Enumerate(AppendFamilyToList, &aFontFamilyNames);
for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) {
nsRefPtr<gfxFontFamily>& family = iter.Data();
aFontFamilyNames.AppendElement(family->Name());
}
}
void
void
gfxPlatformFontList::InitLoader()
{
GetFontFamilyNames(mFontInfo->mFontFamiliesToLoad);
+9 -14
View File
@@ -194,6 +194,11 @@ public:
static const gfxFontEntry::ScriptRange sComplexScriptRanges[];
void GetFontlistInitInfo(uint32_t& aNumInits, uint32_t& aLoaderState) {
aNumInits = mFontlistInitCount;
aLoaderState = (uint32_t) mState;
}
protected:
class MemoryReporter final : public nsIMemoryReporter
{
@@ -207,10 +212,6 @@ protected:
static gfxPlatformFontList *sPlatformFontList;
static PLDHashOperator FindFontForCharProc(nsStringHashKey::KeyType aKey,
nsRefPtr<gfxFontFamily>& aFamilyEntry,
void* userArg);
// Lookup family name in global family list without substitutions or
// localized family name lookup. Used for common font fallback families.
gfxFontFamily* FindFamilyByCanonicalName(const nsAString& aFamily) {
@@ -246,21 +247,11 @@ protected:
// initialize localized family names
void InitOtherFamilyNames();
static PLDHashOperator
InitOtherFamilyNamesProc(nsStringHashKey::KeyType aKey,
nsRefPtr<gfxFontFamily>& aFamilyEntry,
void* userArg);
// search through font families, looking for a given name, initializing
// facename lists along the way. first checks all families with names
// close to face name, then searchs all families if not found.
gfxFontEntry* SearchFamiliesForFaceName(const nsAString& aFaceName);
static PLDHashOperator
ReadFaceNamesProc(nsStringHashKey::KeyType aKey,
nsRefPtr<gfxFontFamily>& aFamilyEntry,
void* userArg);
// helper method for finding fullname/postscript names in facename lists
gfxFontEntry* FindFaceName(const nsAString& aFaceName);
@@ -364,6 +355,10 @@ protected:
uint32_t mIncrement;
uint32_t mNumFamilies;
// xxx - info for diagnosing no default font aborts
// see bugs 636957, 1070983, 1189129
uint32_t mFontlistInitCount; // num times InitFontList called
nsTHashtable<nsPtrHashKey<gfxUserFontSet> > mUserFontSetList;
};
-18
View File
@@ -350,24 +350,6 @@ gfxPlatformGtk::GetOffscreenFormat()
return gfxImageFormat::RGB24;
}
static int sDepth = 0;
int
gfxPlatformGtk::GetScreenDepth() const
{
if (!sDepth) {
GdkScreen *screen = gdk_screen_get_default();
if (screen) {
sDepth = gdk_visual_get_depth(gdk_visual_get_system());
} else {
sDepth = 24;
}
}
return sDepth;
}
void
gfxPlatformGtk::GetPlatformCMSOutputProfile(void *&mem, size_t &size)
{
-2
View File
@@ -124,8 +124,6 @@ public:
virtual gfxImageFormat GetOffscreenFormat() override;
virtual int GetScreenDepth() const override;
bool SupportsApzWheelInput() const override {
return true;
}
-2
View File
@@ -296,8 +296,6 @@ private:
DECL_GFX_PREF(Once, "layers.acceleration.force-enabled", LayersAccelerationForceEnabled, bool, false);
DECL_GFX_PREF(Once, "layers.async-pan-zoom.enabled", AsyncPanZoomEnabledDoNotUseDirectly, bool, true);
DECL_GFX_PREF(Once, "layers.async-pan-zoom.separate-event-thread", AsyncPanZoomSeparateEventThread, bool, false);
DECL_GFX_PREF(Once, "layers.async-video.enabled", AsyncVideoEnabled, bool, true);
DECL_GFX_PREF(Once, "layers.async-video-oop.enabled", AsyncVideoOOPEnabled, bool, true);
DECL_GFX_PREF(Live, "layers.bench.enabled", LayersBenchEnabled, bool, false);
DECL_GFX_PREF(Once, "layers.bufferrotation.enabled", BufferRotationEnabled, bool, true);
#ifdef MOZ_GFX_OPTIMIZE_MOBILE
+2 -8
View File
@@ -53,8 +53,8 @@ gfxQtPlatform::gfxQtPlatform()
if (!sFontconfigUtils)
sFontconfigUtils = gfxFontconfigUtils::GetFontconfigUtils();
mScreenDepth = qApp->primaryScreen()->depth();
if (mScreenDepth == 16) {
int32_t depth = GetScreenDepth();
if (depth == 16) {
sOffscreenFormat = gfxImageFormat::RGB16_565;
}
uint32_t canvasMask = BackendTypeBit(BackendType::CAIRO) | BackendTypeBit(BackendType::SKIA);
@@ -195,12 +195,6 @@ gfxQtPlatform::GetOffscreenFormat()
return sOffscreenFormat;
}
int
gfxQtPlatform::GetScreenDepth() const
{
return mScreenDepth;
}
already_AddRefed<ScaledFont>
gfxQtPlatform::GetScaledFontForFont(DrawTarget* aTarget, gfxFont* aFont)
{
-2
View File
@@ -82,8 +82,6 @@ public:
static Screen* GetXScreen(QWindow* aWindow = 0);
#endif
virtual int GetScreenDepth() const override;
bool AccelerateLayersByDefault() override {
return true;
}

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