mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 05:37:11 +00:00
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:
+10
-169
@@ -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(<);
|
||||
// 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++;
|
||||
|
||||
@@ -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_
|
||||
@@ -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
|
||||
|
||||
@@ -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_
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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_
|
||||
@@ -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 += [
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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();
|
||||
|
||||
@@ -2678,7 +2678,6 @@ _getvalueforurl(NPP instance, NPNURLVariable variable, const char *url,
|
||||
return NPERR_NO_ERROR;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
// Fall through and return an error...
|
||||
;
|
||||
|
||||
@@ -3471,7 +3471,6 @@ nsPluginHost::AddHeadersToChannel(const char *aHeadersData,
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
@@ -5,3 +5,4 @@ skip-if = buildapp == 'b2g'
|
||||
[test_bug338427.html]
|
||||
[test_bug434998.xul]
|
||||
[test_bug678842.html]
|
||||
[test_bug717433.html]
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
# Affix file for British English dictionary
|
||||
# Fake file, nothing here.
|
||||
@@ -0,0 +1,4 @@
|
||||
3
|
||||
Mary
|
||||
Paul
|
||||
Peter
|
||||
@@ -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]
|
||||
|
||||
@@ -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>
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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>
|
||||
@@ -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.
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -470,7 +470,7 @@ protected:
|
||||
*/
|
||||
bool CanComposite();
|
||||
|
||||
void DidComposite();
|
||||
void DidComposite(TimeStamp& aCompositeStart, TimeStamp& aCompositeEnd);
|
||||
|
||||
nsRefPtr<LayerManagerComposite> mLayerManager;
|
||||
nsRefPtr<Compositor> mCompositor;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -80,8 +80,6 @@ public:
|
||||
|
||||
FT_Library GetFTLibrary();
|
||||
|
||||
virtual int GetScreenDepth() const;
|
||||
|
||||
virtual bool CanRenderContentToDataSurface() const override {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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, ×tamp, &filesize);
|
||||
aCache->GetInfoForFile(aFileName, cachedFaceList, ×tamp, &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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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)
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -219,12 +219,6 @@ gfxPattern::GetSolidColor(Color& aColorOut)
|
||||
return false;
|
||||
}
|
||||
|
||||
gfxPattern::GraphicsPatternType
|
||||
gfxPattern::GetType() const
|
||||
{
|
||||
return ThebesPatternType(mGfxPattern.GetPattern()->GetType());
|
||||
}
|
||||
|
||||
int
|
||||
gfxPattern::CairoStatus()
|
||||
{
|
||||
|
||||
@@ -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
@@ -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
@@ -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 */
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -124,8 +124,6 @@ public:
|
||||
|
||||
virtual gfxImageFormat GetOffscreenFormat() override;
|
||||
|
||||
virtual int GetScreenDepth() const override;
|
||||
|
||||
bool SupportsApzWheelInput() const override {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user