Merge m-c to fx-team

This commit is contained in:
Carsten "Tomcat" Book 2013-11-25 15:41:33 +01:00
commit 26f0e95568
47 changed files with 998 additions and 190 deletions

View File

@ -256,14 +256,13 @@ pref("ui.dragThresholdY", 25);
// Layers Acceleration. We can only have nice things on gonk, because
// they're not maintained anywhere else.
pref("layers.offmainthreadcomposition.enabled", true);
#ifndef MOZ_WIDGET_GONK
pref("dom.ipc.tabs.disabled", true);
pref("layers.offmainthreadcomposition.enabled", false);
pref("layers.offmainthreadcomposition.async-animations", false);
pref("layers.async-video.enabled", false);
#else
pref("dom.ipc.tabs.disabled", false);
pref("layers.offmainthreadcomposition.enabled", true);
pref("layers.acceleration.disabled", false);
pref("layers.offmainthreadcomposition.async-animations", true);
pref("layers.async-video.enabled", true);

View File

@ -1,4 +1,4 @@
{
"revision": "5cc15d1e291050f4e46c91b87a1af1353d1c5e46",
"revision": "2a055e0d4214f04646c15c09a6a03bf96f347689",
"repo_path": "/integration/gaia-central"
}

View File

@ -186,6 +186,7 @@
if (!this._statusPanel) {
this._statusPanel = document.createElementNS(this.namespaceURI, "statuspanel");
this._statusPanel.setAttribute("inactive", "true");
this._statusPanel.setAttribute("layer", "true");
this._appendStatusPanel();
}
return this._statusPanel;

View File

@ -2208,11 +2208,13 @@ CanvasRenderingContext2D::SetFont(const nsAString& font,
fontStyle->mFont.AddFontFeaturesToStyle(&style);
nsPresContext *c = presShell->GetPresContext();
CurrentState().fontGroup =
gfxPlatform::GetPlatform()->CreateFontGroup(fontStyle->mFont.name,
&style,
presShell->GetPresContext()->GetUserFontSet());
c->GetUserFontSet());
NS_ASSERTION(CurrentState().fontGroup, "Could not get font group");
CurrentState().fontGroup->SetTextPerfMetrics(c->GetTextPerfMetrics());
// The font getter is required to be reserialized based on what we
// parsed (including having line-height removed). (Older drafts of
@ -2806,6 +2808,12 @@ gfxFontGroup *CanvasRenderingContext2D::GetCurrentFontStyle()
nullptr);
if (CurrentState().fontGroup) {
CurrentState().font = kDefaultFontStyle;
nsIPresShell* presShell = GetPresShell();
if (presShell) {
CurrentState().fontGroup->SetTextPerfMetrics(
presShell->GetPresContext()->GetTextPerfMetrics());
}
} else {
NS_ERROR("Default canvas font is invalid");
}

View File

@ -10,6 +10,7 @@
#include <hardware/bluetooth.h>
#include <hardware/bt_av.h>
#include <hardware/bt_rc.h>
#include "BluetoothCommon.h"
#include "BluetoothService.h"
@ -31,9 +32,9 @@ namespace {
StaticRefPtr<BluetoothA2dpManager> sBluetoothA2dpManager;
bool sInShutdown = false;
static const btav_interface_t* sBtA2dpInterface;
static const btrc_interface_t* sBtAvrcpInterface;
} // anonymous namespace
class SinkPropertyChangedHandler : public nsRunnable
{
public:
@ -50,6 +51,7 @@ public:
BluetoothA2dpManager* a2dp = BluetoothA2dpManager::Get();
NS_ENSURE_TRUE(a2dp, NS_ERROR_FAILURE);
a2dp->HandleSinkPropertyChanged(mSignal);
return NS_OK;
}
@ -57,6 +59,122 @@ private:
BluetoothSignal mSignal;
};
class RequestPlayStatusTask : public nsRunnable
{
public:
RequestPlayStatusTask()
{
MOZ_ASSERT(!NS_IsMainThread());
}
nsresult Run()
{
MOZ_ASSERT(NS_IsMainThread());
BluetoothSignal signal(NS_LITERAL_STRING(REQUEST_MEDIA_PLAYSTATUS_ID),
NS_LITERAL_STRING(KEY_ADAPTER),
InfallibleTArray<BluetoothNamedValue>());
BluetoothService* bs = BluetoothService::Get();
NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE);
bs->DistributeSignal(signal);
return NS_OK;
}
};
class UpdateRegisterNotificationTask : public nsRunnable
{
public:
UpdateRegisterNotificationTask(btrc_event_id_t aEventId, uint32_t aParam)
: mEventId(aEventId)
, mParam(aParam)
{
MOZ_ASSERT(!NS_IsMainThread());
}
nsresult Run()
{
MOZ_ASSERT(NS_IsMainThread());
BluetoothA2dpManager* a2dp = BluetoothA2dpManager::Get();
NS_ENSURE_TRUE(a2dp, NS_OK);
a2dp->UpdateRegisterNotification(mEventId, mParam);
return NS_OK;
}
private:
btrc_event_id_t mEventId;
uint32_t mParam;
};
/*
* This function maps attribute id and returns corresponding values
* Attribute id refers to btrc_media_attr_t in bt_rc.h
*/
static void
ConvertAttributeString(int aAttrId, nsAString& aAttrStr)
{
BluetoothA2dpManager* a2dp = BluetoothA2dpManager::Get();
NS_ENSURE_TRUE_VOID(a2dp);
switch (aAttrId) {
case BTRC_MEDIA_ATTR_TITLE:
a2dp->GetTitle(aAttrStr);
break;
case BTRC_MEDIA_ATTR_ARTIST:
a2dp->GetArtist(aAttrStr);
break;
case BTRC_MEDIA_ATTR_ALBUM:
a2dp->GetAlbum(aAttrStr);
break;
case BTRC_MEDIA_ATTR_TRACK_NUM:
aAttrStr.AppendInt(a2dp->GetMediaNumber());
break;
case BTRC_MEDIA_ATTR_NUM_TRACKS:
aAttrStr.AppendInt(a2dp->GetTotalMediaNumber());
break;
case BTRC_MEDIA_ATTR_GENRE:
// TODO: we currently don't support genre from music player
aAttrStr.Truncate();
break;
case BTRC_MEDIA_ATTR_PLAYING_TIME:
aAttrStr.AppendInt(a2dp->GetDuration());
break;
}
}
class UpdateElementAttrsTask : public nsRunnable
{
public:
UpdateElementAttrsTask(uint8_t aNumAttr, btrc_media_attr_t* aPlayerAttrs)
: mNumAttr(aNumAttr)
, mPlayerAttrs(aPlayerAttrs)
{
MOZ_ASSERT(!NS_IsMainThread());
}
nsresult Run()
{
MOZ_ASSERT(NS_IsMainThread());
btrc_element_attr_val_t* attrs = new btrc_element_attr_val_t[mNumAttr];
for (int i = 0; i < mNumAttr; i++) {
nsAutoString attrText;
attrs[i].attr_id = mPlayerAttrs[i];
ConvertAttributeString(mPlayerAttrs[i], attrText);
strcpy((char *)attrs[i].text, NS_ConvertUTF16toUTF8(attrText).get());
}
NS_ENSURE_TRUE(sBtAvrcpInterface, NS_OK);
sBtAvrcpInterface->get_element_attr_rsp(mNumAttr, attrs);
return NS_OK;
}
private:
uint8_t mNumAttr;
btrc_media_attr_t* mPlayerAttrs;
};
NS_IMETHODIMP
BluetoothA2dpManager::Observe(nsISupports* aSubject,
const char* aTopic,
@ -147,12 +265,131 @@ A2dpAudioStateCallback(btav_audio_state_t aState,
NS_DispatchToMainThread(new SinkPropertyChangedHandler(signal));
}
/*
* Avrcp 1.3 callbacks
*/
/*
* This function is to request Gaia player application to update
* current play status.
* Callback for play status request
*/
static void
AvrcpGetPlayStatusCallback()
{
MOZ_ASSERT(!NS_IsMainThread());
NS_DispatchToMainThread(new RequestPlayStatusTask());
}
/*
* This function is trying to get element attributes, which request from CT
* Unlike BlueZ only calls UpdateMetaData, bluedroid does not cache meta data
* information, but instead uses callback AvrcpGetElementAttrCallback and
* call get_element_attr_rsp() to reply request.
*
* Callback to fetch the get element attributes of the current song
* aNumAttr: It represents the number of attributes requested in aPlayerAttrs
* aPlayerAttrs: It represents Attribute Ids
*/
static void
AvrcpGetElementAttrCallback(uint8_t aNumAttr, btrc_media_attr_t* aPlayerAttrs)
{
MOZ_ASSERT(!NS_IsMainThread());
NS_DispatchToMainThread(new UpdateElementAttrsTask(aNumAttr, aPlayerAttrs));
}
/*
* Callback for register notification (Play state change/track change/...)
* To reply RegisterNotification INTERIM response
* See AVRCP 1.3 Spec 25.2
* aParam: It only valids if event_id is BTRC_EVT_PLAY_POS_CHANGED,
* which is playback interval time
*/
static void
AvrcpRegisterNotificationCallback(btrc_event_id_t aEventId, uint32_t aParam)
{
MOZ_ASSERT(!NS_IsMainThread());
NS_DispatchToMainThread(new UpdateRegisterNotificationTask(aEventId, aParam));
}
/*
* Player application settings is optional for Avrcp 1.3
* B2G 1.3 currently does not support Player application setting
* related functions. Support Player Setting in the future version
*/
static void
AvrcpListPlayerAppAttributeCallback()
{
MOZ_ASSERT(!NS_IsMainThread());
// TODO: Support avrcp application setting related functions
}
static void
AvrcpListPlayerAppValuesCallback(btrc_player_attr_t aAttrId)
{
MOZ_ASSERT(!NS_IsMainThread());
// TODO: Support avrcp application setting related functions
}
static void
AvrcpGetPlayerAppValueCallback(uint8_t aNumAttr,
btrc_player_attr_t* aPlayerAttrs)
{
MOZ_ASSERT(!NS_IsMainThread());
// TODO: Support avrcp application setting related functions
}
static void
AvrcpGetPlayerAppAttrsTextCallback(uint8_t aNumAttr,
btrc_player_attr_t* PlayerAttrs)
{
MOZ_ASSERT(!NS_IsMainThread());
// TODO: Support avrcp application setting related functions
}
static void
AvrcpGetPlayerAppValuesTextCallback(uint8_t aAttrId, uint8_t aNumVal,
uint8_t* PlayerVals)
{
MOZ_ASSERT(!NS_IsMainThread());
// TODO: Support avrcp application setting related functions
}
static void
AvrcpSetPlayerAppValueCallback(btrc_player_settings_t* aPlayerVals)
{
MOZ_ASSERT(!NS_IsMainThread());
// TODO: Support avrcp application setting related functions
}
static btav_callbacks_t sBtA2dpCallbacks = {
sizeof(sBtA2dpCallbacks),
A2dpConnectionStateCallback,
A2dpAudioStateCallback
};
static btrc_callbacks_t sBtAvrcpCallbacks = {
sizeof(sBtAvrcpCallbacks),
AvrcpGetPlayStatusCallback,
AvrcpListPlayerAppAttributeCallback,
AvrcpListPlayerAppValuesCallback,
AvrcpGetPlayerAppValueCallback,
AvrcpGetPlayerAppAttrsTextCallback,
AvrcpGetPlayerAppValuesTextCallback,
AvrcpSetPlayerAppValueCallback,
AvrcpGetElementAttrCallback,
AvrcpRegisterNotificationCallback
};
/*
* This function will be only called when Bluetooth is turning on.
* It is important to register a2dp callbacks before enable() gets called.
@ -164,15 +401,27 @@ BluetoothA2dpManager::Init()
{
const bt_interface_t* btInf = GetBluetoothInterface();
NS_ENSURE_TRUE(btInf, false);
sBtA2dpInterface = (btav_interface_t *)btInf->
get_profile_interface(BT_PROFILE_ADVANCED_AUDIO_ID);
NS_ENSURE_TRUE(sBtA2dpInterface, false);
int ret = sBtA2dpInterface->init(&sBtA2dpCallbacks);
if (ret != BT_STATUS_SUCCESS) {
BT_LOGR("failed to init a2dp module");
BT_LOGR("Warning: failed to init a2dp module");
return false;
}
sBtAvrcpInterface = (btrc_interface_t *)btInf->
get_profile_interface(BT_PROFILE_AV_RC_ID);
NS_ENSURE_TRUE(sBtAvrcpInterface, false);
ret = sBtAvrcpInterface->init(&sBtAvrcpCallbacks);
if (ret != BT_STATUS_SUCCESS) {
BT_LOGR("Warning: failed to init avrcp module");
return false;
}
return true;
}
@ -487,6 +736,10 @@ BluetoothA2dpManager::IsConnected()
return mA2dpConnected;
}
/*
* In bluedroid stack case, there is no interface to know exactly
* avrcp connection status. All connection are managed by bluedroid stack.
*/
void
BluetoothA2dpManager::SetAvrcpConnected(bool aConnected)
{
@ -502,6 +755,10 @@ BluetoothA2dpManager::IsAvrcpConnected()
return mAvrcpConnected;
}
/*
* This function only updates meta data in BluetoothA2dpManager
* Send "Get Element Attributes response" in AvrcpGetElementAttrCallback
*/
void
BluetoothA2dpManager::UpdateMetaData(const nsAString& aTitle,
const nsAString& aArtist,
@ -510,6 +767,36 @@ BluetoothA2dpManager::UpdateMetaData(const nsAString& aTitle,
uint32_t aTotalMediaCount,
uint32_t aDuration)
{
MOZ_ASSERT(NS_IsMainThread());
NS_ENSURE_TRUE_VOID(sBtAvrcpInterface);
// Send track changed and position changed if track num is not the same.
// See also AVRCP 1.3 Spec 5.4.2
if (mMediaNumber != aMediaNumber &&
mTrackChangedNotifyType == BTRC_NOTIFICATION_TYPE_INTERIM) {
btrc_register_notification_t param;
// convert to network big endian format
// since track stores as uint8[8]
// 56 = 8 * (BTRC_UID_SIZE -1)
for (int i = 0; i < BTRC_UID_SIZE; ++i) {
param.track[i] = (aMediaNumber >> (56 - 8 * i));
}
mTrackChangedNotifyType = BTRC_NOTIFICATION_TYPE_CHANGED;
sBtAvrcpInterface->register_notification_rsp(BTRC_EVT_TRACK_CHANGE,
BTRC_NOTIFICATION_TYPE_CHANGED,
&param);
if (mPlayPosChangedNotifyType == BTRC_NOTIFICATION_TYPE_INTERIM) {
param.song_pos = mPosition;
// EVENT_PLAYBACK_POS_CHANGED shall be notified if changed current track
mPlayPosChangedNotifyType = BTRC_NOTIFICATION_TYPE_CHANGED;
sBtAvrcpInterface->register_notification_rsp(
BTRC_EVT_PLAY_POS_CHANGED,
BTRC_NOTIFICATION_TYPE_CHANGED,
&param);
}
}
mTitle.Assign(aTitle);
mArtist.Assign(aArtist);
mAlbum.Assign(aAlbum);
@ -518,20 +805,93 @@ BluetoothA2dpManager::UpdateMetaData(const nsAString& aTitle,
mDuration = aDuration;
}
/*
* This function is to reply AvrcpGetPlayStatusCallback (play-status-request)
* from media player application (Gaia side)
*/
void
BluetoothA2dpManager::UpdatePlayStatus(uint32_t aDuration,
uint32_t aPosition,
ControlPlayStatus aPlayStatus)
{
MOZ_ASSERT(NS_IsMainThread());
NS_ENSURE_TRUE_VOID(sBtAvrcpInterface);
// when play status changed, send both play status and position
if (mPlayStatus != aPlayStatus &&
mPlayStatusChangedNotifyType == BTRC_NOTIFICATION_TYPE_INTERIM) {
btrc_register_notification_t param;
param.play_status = (btrc_play_status_t)aPlayStatus;
mPlayStatusChangedNotifyType = BTRC_NOTIFICATION_TYPE_CHANGED;
sBtAvrcpInterface->register_notification_rsp(BTRC_EVT_PLAY_STATUS_CHANGED,
BTRC_NOTIFICATION_TYPE_CHANGED,
&param);
}
if (mPosition != aPosition &&
mPlayPosChangedNotifyType == BTRC_NOTIFICATION_TYPE_INTERIM) {
btrc_register_notification_t param;
param.song_pos = aPosition;
mPlayPosChangedNotifyType = BTRC_NOTIFICATION_TYPE_CHANGED;
sBtAvrcpInterface->register_notification_rsp(BTRC_EVT_PLAY_POS_CHANGED,
BTRC_NOTIFICATION_TYPE_CHANGED,
&param);
}
sBtAvrcpInterface->get_play_status_rsp((btrc_play_status_t)aPlayStatus,
aDuration, aPosition);
mDuration = aDuration;
mPosition = aPosition;
mPlayStatus = aPlayStatus;
}
/*
* This function handles RegisterNotification request from
* AvrcpRegisterNotificationCallback, which updates current
* track/status/position status.
*
* aParam is only valid when position changed
*/
void
BluetoothA2dpManager::UpdateRegisterNotification(int aEventId, int aParam)
{
MOZ_ASSERT(NS_IsMainThread());
NS_ENSURE_TRUE_VOID(sBtAvrcpInterface);
btrc_register_notification_t param;
switch (aEventId) {
case BTRC_EVT_PLAY_STATUS_CHANGED:
mPlayPosChangedNotifyType = BTRC_NOTIFICATION_TYPE_INTERIM;
param.play_status = (btrc_play_status_t)mPlayStatus;
break;
case BTRC_EVT_TRACK_CHANGE:
mTrackChangedNotifyType = BTRC_NOTIFICATION_TYPE_INTERIM;
// needs to convert to network big endian format since track stores
// as uint8[8]. 56 = 8 * (BTRC_UID_SIZE -1)
for (int i = 0; i < BTRC_UID_SIZE; ++i) {
param.track[i] = (mMediaNumber >> (56 - 8 * i));
}
break;
case BTRC_EVT_PLAY_POS_CHANGED:
mPlayPosChangedNotifyType = BTRC_NOTIFICATION_TYPE_INTERIM;
param.song_pos = mPosition;
mPlaybackInterval = aParam;
break;
default:
break;
}
sBtAvrcpInterface->register_notification_rsp((btrc_event_id_t)aEventId,
BTRC_NOTIFICATION_TYPE_INTERIM,
&param);
}
void
BluetoothA2dpManager::GetAlbum(nsAString& aAlbum)
{
aAlbum.Assign(mAlbum);
aAlbum.Assign(mAlbum);
}
uint32_t
@ -558,11 +918,23 @@ BluetoothA2dpManager::GetMediaNumber()
return mMediaNumber;
}
uint32_t
BluetoothA2dpManager::GetTotalMediaNumber()
{
return mTotalMediaCount;
}
void
BluetoothA2dpManager::GetTitle(nsAString& aTitle)
{
aTitle.Assign(mTitle);
}
void
BluetoothA2dpManager::GetArtist(nsAString& aArtist)
{
aArtist.Assign(mArtist);
}
NS_IMPL_ISUPPORTS1(BluetoothA2dpManager, nsIObserver)

View File

@ -12,7 +12,6 @@
#include "BluetoothProfileManagerBase.h"
BEGIN_BLUETOOTH_NAMESPACE
class BluetoothA2dpManager : public BluetoothProfileManagerBase
{
public:
@ -52,13 +51,15 @@ public:
void UpdatePlayStatus(uint32_t aDuration,
uint32_t aPosition,
ControlPlayStatus aPlayStatus);
void UpdateRegisterNotification(int aEventId, int aParam);
void GetAlbum(nsAString& aAlbum);
uint32_t GetDuration();
ControlPlayStatus GetPlayStatus();
uint32_t GetPosition();
uint32_t GetMediaNumber();
uint32_t GetTotalMediaNumber();
void GetTitle(nsAString& aTitle);
void GetArtist(nsAString& aArtist);
private:
class SinkPropertyChangedHandler;
BluetoothA2dpManager();
@ -82,7 +83,27 @@ private:
uint32_t mMediaNumber;
uint32_t mTotalMediaCount;
uint32_t mPosition;
/*
* mPlaybackInterval specifies the time interval (in seconds) at which
* the change in playback position will be notified. If the song is being
* forwarded / rewound, a notification will be received whenever the playback
* position will change by this value.
*/
uint32_t mPlaybackInterval;
ControlPlayStatus mPlayStatus;
/*
* Notification types: 1. INTERIM 2. CHANGED
* 1. The initial response to this Notify command shall be an INTERIM
* response with current status.
* 2. The following response shall be a CHANGED response with the updated
* status.
* mPlayStatusChangedNotifType, mTrackChangedNotifType,
* mPlayPosChangedNotifType represents current RegisterNotification
* notification type.
*/
int mPlayStatusChangedNotifyType;
int mTrackChangedNotifyType;
int mPlayPosChangedNotifyType;
};
END_BLUETOOTH_NAMESPACE

View File

@ -160,6 +160,26 @@ ClassToIcon(uint32_t aClass, nsAString& aRetIcon)
break;
}
}
static ControlPlayStatus
PlayStatusStringToControlPlayStatus(const nsAString& aPlayStatus)
{
ControlPlayStatus playStatus = ControlPlayStatus::PLAYSTATUS_UNKNOWN;
if (aPlayStatus.EqualsLiteral("STOPPED")) {
playStatus = ControlPlayStatus::PLAYSTATUS_STOPPED;
} else if (aPlayStatus.EqualsLiteral("PLAYING")) {
playStatus = ControlPlayStatus::PLAYSTATUS_PLAYING;
} else if (aPlayStatus.EqualsLiteral("PAUSED")) {
playStatus = ControlPlayStatus::PLAYSTATUS_PAUSED;
} else if (aPlayStatus.EqualsLiteral("FWD_SEEK")) {
playStatus = ControlPlayStatus::PLAYSTATUS_FWD_SEEK;
} else if (aPlayStatus.EqualsLiteral("REV_SEEK")) {
playStatus = ControlPlayStatus::PLAYSTATUS_REV_SEEK;
} else if (aPlayStatus.EqualsLiteral("ERROR")) {
playStatus = ControlPlayStatus::PLAYSTATUS_ERROR;
}
return playStatus;
}
static bool
IsReady()
@ -1300,7 +1320,12 @@ BluetoothServiceBluedroid::SendMetaData(const nsAString& aTitle,
int64_t aDuration,
BluetoothReplyRunnable* aRunnable)
{
BluetoothA2dpManager* a2dp = BluetoothA2dpManager::Get();
if (a2dp) {
a2dp->UpdateMetaData(aTitle, aArtist, aAlbum, aMediaNumber,
aTotalMediaCount, aDuration);
}
DispatchBluetoothReply(aRunnable, BluetoothValue(true), EmptyString());
}
void
@ -1309,14 +1334,23 @@ BluetoothServiceBluedroid::SendPlayStatus(
const nsAString& aPlayStatus,
BluetoothReplyRunnable* aRunnable)
{
BluetoothA2dpManager* a2dp = BluetoothA2dpManager::Get();
if (a2dp) {
ControlPlayStatus playStatus =
PlayStatusStringToControlPlayStatus(aPlayStatus);
a2dp->UpdatePlayStatus(aDuration, aPosition, playStatus);
}
DispatchBluetoothReply(aRunnable, BluetoothValue(true), EmptyString());
}
void
BluetoothServiceBluedroid::UpdatePlayStatus(
uint32_t aDuration, uint32_t aPosition, ControlPlayStatus aPlayStatus)
{
// We don't need this function for bluedroid.
// In bluez, it only calls dbus api
// But it does not update BluetoothA2dpManager member fields
MOZ_ASSERT(false);
}
nsresult

View File

@ -410,6 +410,7 @@ const ContentPanning = {
function scroll(delta) {
current = root;
firstScroll = true;
while (current) {
if (doScroll(current, delta)) {
firstScroll = false;

View File

@ -1,7 +1,7 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
MARIONETTE_TIMEOUT = 60000;
MARIONETTE_TIMEOUT = 120000;
MARIONETTE_HEAD_JS = 'head.js';
const PDU_SMSC_NONE = "00"; // no SMSC Address

View File

@ -1139,7 +1139,7 @@ void WriteSnapshotLinkToDumpFile(T* aObj, FILE* aFile)
nsCString string(aObj->Name());
string.Append("-");
string.AppendInt((uint64_t)aObj);
fprintf(aFile, "href=\"javascript:ViewImage('%s')\"", string.BeginReading());
fprintf_stderr(aFile, "href=\"javascript:ViewImage('%s')\"", string.BeginReading());
}
template <typename T>
@ -1148,11 +1148,13 @@ void WriteSnapshotToDumpFile_internal(T* aObj, gfxASurface* aSurf)
nsCString string(aObj->Name());
string.Append("-");
string.AppendInt((uint64_t)aObj);
if (gfxUtils::sDumpPaintFile)
fprintf(gfxUtils::sDumpPaintFile, "array[\"%s\"]=\"", string.BeginReading());
if (gfxUtils::sDumpPaintFile) {
fprintf_stderr(gfxUtils::sDumpPaintFile, "array[\"%s\"]=\"", string.BeginReading());
}
aSurf->DumpAsDataURL(gfxUtils::sDumpPaintFile);
if (gfxUtils::sDumpPaintFile)
fprintf(gfxUtils::sDumpPaintFile, "\";");
if (gfxUtils::sDumpPaintFile) {
fprintf_stderr(gfxUtils::sDumpPaintFile, "\";");
}
}
void WriteSnapshotToDumpFile(Layer* aLayer, gfxASurface* aSurf)
@ -1176,13 +1178,13 @@ void
Layer::Dump(FILE* aFile, const char* aPrefix, bool aDumpHtml)
{
if (aDumpHtml) {
fprintf(aFile, "<li><a id=\"%p\" ", this);
fprintf_stderr(aFile, "<li><a id=\"%p\" ", this);
#ifdef MOZ_DUMP_PAINTING
if (GetType() == TYPE_CONTAINER || GetType() == TYPE_THEBES) {
WriteSnapshotLinkToDumpFile(this, aFile);
}
#endif
fprintf(aFile, ">");
fprintf_stderr(aFile, ">");
}
DumpSelf(aFile, aPrefix);
@ -1193,7 +1195,7 @@ Layer::Dump(FILE* aFile, const char* aPrefix, bool aDumpHtml)
#endif
if (aDumpHtml) {
fprintf(aFile, "</a>");
fprintf_stderr(aFile, "</a>");
}
if (Layer* mask = GetMaskLayer()) {
@ -1206,16 +1208,16 @@ Layer::Dump(FILE* aFile, const char* aPrefix, bool aDumpHtml)
nsAutoCString pfx(aPrefix);
pfx += " ";
if (aDumpHtml) {
fprintf(aFile, "<ul>");
fprintf_stderr(aFile, "<ul>");
}
kid->Dump(aFile, pfx.get(), aDumpHtml);
if (aDumpHtml) {
fprintf(aFile, "</ul>");
fprintf_stderr(aFile, "</ul>");
}
}
if (aDumpHtml) {
fprintf(aFile, "</li>");
fprintf_stderr(aFile, "</li>");
}
if (Layer* next = GetNextSibling())
next->Dump(aFile, aPrefix, aDumpHtml);
@ -1226,11 +1228,7 @@ Layer::DumpSelf(FILE* aFile, const char* aPrefix)
{
nsAutoCString str;
PrintInfo(str, aPrefix);
if (!aFile || aFile == stderr) {
printf_stderr("%s\n", str.get());
} else {
fprintf(aFile, "%s\n", str.get());
}
fprintf_stderr(aFile, "%s\n", str.get());
}
void
@ -1407,34 +1405,34 @@ LayerManager::Dump(FILE* aFile, const char* aPrefix, bool aDumpHtml)
#ifdef MOZ_DUMP_PAINTING
if (aDumpHtml) {
fprintf(file, "<ul><li><a ");
fprintf_stderr(file, "<ul><li><a ");
WriteSnapshotLinkToDumpFile(this, file);
fprintf(file, ">");
fprintf_stderr(file, ">");
}
#endif
DumpSelf(file, aPrefix);
#ifdef MOZ_DUMP_PAINTING
if (aDumpHtml) {
fprintf(file, "</a>");
fprintf_stderr(file, "</a>");
}
#endif
nsAutoCString pfx(aPrefix);
pfx += " ";
if (!GetRoot()) {
fprintf(file, "%s(null)", pfx.get());
fprintf_stderr(file, "%s(null)", pfx.get());
if (aDumpHtml) {
fprintf(file, "</li></ul>");
fprintf_stderr(file, "</li></ul>");
}
return;
}
if (aDumpHtml) {
fprintf(file, "<ul>");
fprintf_stderr(file, "<ul>");
}
GetRoot()->Dump(file, pfx.get(), aDumpHtml);
if (aDumpHtml) {
fprintf(file, "</ul></li></ul>");
fprintf_stderr(file, "</ul></li></ul>");
}
fputc('\n', file);
}
@ -1444,7 +1442,7 @@ LayerManager::DumpSelf(FILE* aFile, const char* aPrefix)
{
nsAutoCString str;
PrintInfo(str, aPrefix);
fprintf(FILEOrDefault(aFile), "%s\n", str.get());
fprintf_stderr(FILEOrDefault(aFile), "%s\n", str.get());
}
void

View File

@ -260,20 +260,20 @@ ContentHostBase::Dump(FILE* aFile,
if (!aFile) {
aFile = stderr;
}
fprintf(aFile, "<ul>");
fprintf_stderr(aFile, "<ul>");
if (mDeprecatedTextureHost) {
fprintf(aFile, "%s", aPrefix);
fprintf(aFile, "<li> <a href=");
fprintf_stderr(aFile, "%s", aPrefix);
fprintf_stderr(aFile, "<li> <a href=");
DumpDeprecatedTextureHost(aFile, mDeprecatedTextureHost);
fprintf(aFile, "> Front buffer </a></li> ");
fprintf_stderr(aFile, "> Front buffer </a></li> ");
}
if (mDeprecatedTextureHostOnWhite) {
fprintf(aFile, "%s", aPrefix);
fprintf(aFile, "<li> <a href=");
fprintf_stderr(aFile, "%s", aPrefix);
fprintf_stderr(aFile, "<li> <a href=");
DumpDeprecatedTextureHost(aFile, mDeprecatedTextureHostOnWhite);
fprintf(aFile, "> Front buffer on white </a> </li> ");
fprintf_stderr(aFile, "> Front buffer on white </a> </li> ");
}
fprintf(aFile, "</ul>");
fprintf_stderr(aFile, "</ul>");
}
#endif
@ -816,20 +816,20 @@ ContentHostDoubleBuffered::Dump(FILE* aFile,
if (!aFile) {
aFile = stderr;
}
fprintf(aFile, "<ul>");
fprintf_stderr(aFile, "<ul>");
if (mBackHost) {
fprintf(aFile, "%s", aPrefix);
fprintf(aFile, "<li> <a href=");
fprintf_stderr(aFile, "%s", aPrefix);
fprintf_stderr(aFile, "<li> <a href=");
DumpDeprecatedTextureHost(aFile, mBackHost);
fprintf(aFile, " >Back buffer</a></li>");
fprintf_stderr(aFile, " >Back buffer</a></li>");
}
if (mBackHostOnWhite) {
fprintf(aFile, "%s", aPrefix);
fprintf(aFile, "<li> <a href=");
fprintf_stderr(aFile, "%s", aPrefix);
fprintf_stderr(aFile, "<li> <a href=");
DumpDeprecatedTextureHost(aFile, mBackHostOnWhite);
fprintf(aFile, " >Back buffer on white</a> </li>");
fprintf_stderr(aFile, " >Back buffer on white</a> </li>");
}
fprintf(aFile, "</ul>");
fprintf_stderr(aFile, "</ul>");
}
#endif

View File

@ -181,11 +181,11 @@ ImageHost::Dump(FILE* aFile,
aFile = stderr;
}
if (mFrontBuffer) {
fprintf(aFile, "%s", aPrefix);
fprintf(aFile, aDumpHtml ? "<ul><li>TextureHost: "
fprintf_stderr(aFile, "%s", aPrefix);
fprintf_stderr(aFile, aDumpHtml ? "<ul><li>TextureHost: "
: "TextureHost: ");
DumpTextureHost(aFile, mFrontBuffer);
fprintf(aFile, aDumpHtml ? " </li></ul> " : " ");
fprintf_stderr(aFile, aDumpHtml ? " </li></ul> " : " ");
}
}
#endif
@ -391,11 +391,11 @@ DeprecatedImageHostSingle::Dump(FILE* aFile,
aFile = stderr;
}
if (mDeprecatedTextureHost) {
fprintf(aFile, "%s", aPrefix);
fprintf(aFile, aDumpHtml ? "<ul><li>DeprecatedTextureHost: "
fprintf_stderr(aFile, "%s", aPrefix);
fprintf_stderr(aFile, aDumpHtml ? "<ul><li>DeprecatedTextureHost: "
: "DeprecatedTextureHost: ");
DumpDeprecatedTextureHost(aFile, mDeprecatedTextureHost);
fprintf(aFile, aDumpHtml ? " </li></ul> " : " ");
fprintf_stderr(aFile, aDumpHtml ? " </li></ul> " : " ");
}
}

View File

@ -331,16 +331,16 @@ TiledContentHost::Dump(FILE* aFile,
TiledLayerBufferComposite::Iterator it = mVideoMemoryTiledBuffer.TilesBegin();
TiledLayerBufferComposite::Iterator stop = mVideoMemoryTiledBuffer.TilesEnd();
if (aDumpHtml) {
fprintf(aFile, "<ul>");
fprintf_stderr(aFile, "<ul>");
}
for (;it != stop; ++it) {
fprintf(aFile, "%s", aPrefix);
fprintf(aFile, aDumpHtml ? "<li> <a href=" : "Tile ");
fprintf_stderr(aFile, "%s", aPrefix);
fprintf_stderr(aFile, aDumpHtml ? "<li> <a href=" : "Tile ");
DumpDeprecatedTextureHost(aFile, it->mDeprecatedTextureHost);
fprintf(aFile, aDumpHtml ? " >Tile</a></li>" : " ");
fprintf_stderr(aFile, aDumpHtml ? " >Tile</a></li>" : " ");
}
if (aDumpHtml) {
fprintf(aFile, "</ul>");
fprintf_stderr(aFile, "</ul>");
}
}
#endif

View File

@ -554,8 +554,8 @@ CompositorParent::CompositeInTransaction()
#ifdef MOZ_DUMP_PAINTING
static bool gDumpCompositorTree = false;
if (gDumpCompositorTree) {
fprintf(stdout, "Painting --- compositing layer tree:\n");
mLayerManager->Dump(stdout, "", false);
printf_stderr("Painting --- compositing layer tree:\n");
mLayerManager->Dump();
}
#endif
mLayerManager->EndEmptyTransaction();

View File

@ -66,6 +66,7 @@ public:
nsresult GetMetricsFor(const nsFont& aFont, nsIAtom* aLanguage,
gfxUserFontSet* aUserFontSet,
gfxTextPerfMetrics* aTextPerf,
nsFontMetrics*& aMetrics);
void FontMetricsDeleted(const nsFontMetrics* aFontMetrics);
@ -123,6 +124,7 @@ nsFontCache::Observe(nsISupports*, const char* aTopic, const PRUnichar*)
nsresult
nsFontCache::GetMetricsFor(const nsFont& aFont, nsIAtom* aLanguage,
gfxUserFontSet* aUserFontSet,
gfxTextPerfMetrics* aTextPerf,
nsFontMetrics*& aMetrics)
{
if (!aLanguage)
@ -152,7 +154,7 @@ nsFontCache::GetMetricsFor(const nsFont& aFont, nsIAtom* aLanguage,
fm = new nsFontMetrics();
NS_ADDREF(fm);
nsresult rv = fm->Init(aFont, aLanguage, mContext, aUserFontSet);
nsresult rv = fm->Init(aFont, aLanguage, mContext, aUserFontSet, aTextPerf);
if (NS_SUCCEEDED(rv)) {
// the mFontMetrics list has the "head" at the end, because append
// is cheaper than insert
@ -171,7 +173,7 @@ nsFontCache::GetMetricsFor(const nsFont& aFont, nsIAtom* aLanguage,
Compact();
fm = new nsFontMetrics();
NS_ADDREF(fm);
rv = fm->Init(aFont, aLanguage, mContext, aUserFontSet);
rv = fm->Init(aFont, aLanguage, mContext, aUserFontSet, aTextPerf);
if (NS_SUCCEEDED(rv)) {
mFontMetrics.AppendElement(fm);
aMetrics = fm;
@ -260,6 +262,7 @@ nsresult
nsDeviceContext::GetMetricsFor(const nsFont& aFont,
nsIAtom* aLanguage,
gfxUserFontSet* aUserFontSet,
gfxTextPerfMetrics* aTextPerf,
nsFontMetrics*& aMetrics)
{
if (!mFontCache) {
@ -268,7 +271,8 @@ nsDeviceContext::GetMetricsFor(const nsFont& aFont,
mFontCache->Init(this);
}
return mFontCache->GetMetricsFor(aFont, aLanguage, aUserFontSet, aMetrics);
return mFontCache->GetMetricsFor(aFont, aLanguage, aUserFontSet,
aTextPerf, aMetrics);
}
nsresult

View File

@ -20,6 +20,7 @@
#include "mozilla/AppUnits.h" // for AppUnits
class gfxASurface;
class gfxTextPerfMetrics;
class gfxUserFontSet;
class nsFont;
class nsFontCache;
@ -119,6 +120,7 @@ public:
*/
nsresult GetMetricsFor(const nsFont& aFont, nsIAtom* aLanguage,
gfxUserFontSet* aUserFontSet,
gfxTextPerfMetrics* aTextPerf,
nsFontMetrics*& aMetrics);
/**

View File

@ -96,7 +96,8 @@ nsFontMetrics::~nsFontMetrics()
nsresult
nsFontMetrics::Init(const nsFont& aFont, nsIAtom* aLanguage,
nsDeviceContext *aContext,
gfxUserFontSet *aUserFontSet)
gfxUserFontSet *aUserFontSet,
gfxTextPerfMetrics *aTextPerf)
{
NS_ABORT_IF_FALSE(mP2A == 0, "already initialized");
@ -119,6 +120,7 @@ nsFontMetrics::Init(const nsFont& aFont, nsIAtom* aLanguage,
mFontGroup = gfxPlatform::GetPlatform()->
CreateFontGroup(aFont.name, &style, aUserFontSet);
mFontGroup->SetTextPerfMetrics(aTextPerf);
if (mFontGroup->FontListLength() < 1)
return NS_ERROR_UNEXPECTED;

View File

@ -19,6 +19,7 @@
#include "nscore.h" // for PRUnichar
class gfxUserFontSet;
class gfxTextPerfMetrics;
class nsDeviceContext;
class nsIAtom;
class nsRenderingContext;
@ -58,7 +59,8 @@ public:
*/
nsresult Init(const nsFont& aFont, nsIAtom* aLanguage,
nsDeviceContext *aContext,
gfxUserFontSet *aUserFontSet = nullptr);
gfxUserFontSet *aUserFontSet,
gfxTextPerfMetrics *aTextPerf);
/**
* Destroy this font metrics. This breaks the association between

View File

@ -6,10 +6,6 @@
#ifndef GFX_ASURFACE_H
#define GFX_ASURFACE_H
#ifdef MOZ_DUMP_PAINTING
#define MOZ_DUMP_IMAGES
#endif
#include "mozilla/MemoryReporting.h"
#include "gfxTypes.h"
#include "mozilla/Scoped.h"

View File

@ -3083,6 +3083,12 @@ HashMix(uint32_t aHash, PRUnichar aCh)
return (aHash >> 28) ^ (aHash << 4) ^ aCh;
}
#ifdef __GNUC__
#define GFX_MAYBE_UNUSED __attribute__((unused))
#else
#define GFX_MAYBE_UNUSED
#endif
template<typename T>
gfxShapedWord*
gfxFont::GetShapedWord(gfxContext *aContext,
@ -3091,7 +3097,8 @@ gfxFont::GetShapedWord(gfxContext *aContext,
uint32_t aHash,
int32_t aRunScript,
int32_t aAppUnitsPerDevUnit,
uint32_t aFlags)
uint32_t aFlags,
gfxTextPerfMetrics *aTextPerf GFX_MAYBE_UNUSED)
{
// if the cache is getting too big, flush it and start over
uint32_t wordCacheMaxEntries =
@ -3121,12 +3128,23 @@ gfxFont::GetShapedWord(gfxContext *aContext,
Telemetry::Accumulate((isContent ? Telemetry::WORD_CACHE_HITS_CONTENT :
Telemetry::WORD_CACHE_HITS_CHROME),
aLength);
#ifndef RELEASE_BUILD
if (aTextPerf) {
aTextPerf->current.wordCacheHit++;
}
#endif
return sw;
}
Telemetry::Accumulate((isContent ? Telemetry::WORD_CACHE_MISSES_CONTENT :
Telemetry::WORD_CACHE_MISSES_CHROME),
aLength);
#ifndef RELEASE_BUILD
if (aTextPerf) {
aTextPerf->current.wordCacheMiss++;
}
#endif
sw = entry->mShapedWord = gfxShapedWord::Create(aText, aLength,
aRunScript,
aAppUnitsPerDevUnit,
@ -3371,6 +3389,12 @@ gfxFont::ShapeTextWithoutWordCache(gfxContext *aContext,
return ok;
}
#ifndef RELEASE_BUILD
#define TEXT_PERF_INCR(tp, m) (tp ? (tp)->current.m++ : 0)
#else
#define TEXT_PERF_INCR(tp, m)
#endif
inline static bool IsChar8Bit(uint8_t /*aCh*/) { return true; }
inline static bool IsChar8Bit(PRUnichar aCh) { return aCh < 0x100; }
@ -3387,7 +3411,25 @@ gfxFont::SplitAndInitTextRun(gfxContext *aContext,
return true;
}
gfxTextPerfMetrics *tp = nullptr;
#ifndef RELEASE_BUILD
tp = aTextRun->GetFontGroup()->GetTextPerfMetrics();
if (tp) {
if (mStyle.systemFont) {
tp->current.numChromeTextRuns++;
} else {
tp->current.numContentTextRuns++;
}
tp->current.numChars += aRunLength;
if (aRunLength > tp->current.maxTextRunLen) {
tp->current.maxTextRunLen = aRunLength;
}
}
#endif
if (BypassShapedWordCache(aRunScript)) {
TEXT_PERF_INCR(tp, wordCacheSpaceRules);
return ShapeTextWithoutWordCache(aContext, aString + aRunStart,
aRunStart, aRunLength, aRunScript,
aTextRun);
@ -3436,6 +3478,7 @@ gfxFont::SplitAndInitTextRun(gfxContext *aContext,
// For words longer than the limit, we don't use the
// font's word cache but just shape directly into the textrun.
if (length > wordCacheCharLimit) {
TEXT_PERF_INCR(tp, wordCacheLong);
bool ok = ShapeFragmentWithoutWordCache(aContext,
text + wordStart,
aRunStart + wordStart,
@ -3459,7 +3502,7 @@ gfxFont::SplitAndInitTextRun(gfxContext *aContext,
text + wordStart, length,
hash, aRunScript,
appUnitsPerDevUnit,
wordFlags);
wordFlags, tp);
if (sw) {
aTextRun->CopyGlyphDataFrom(sw, aRunStart + wordStart);
} else {
@ -3478,7 +3521,7 @@ gfxFont::SplitAndInitTextRun(gfxContext *aContext,
&space, 1,
HashMix(0, ' '), aRunScript,
appUnitsPerDevUnit,
flags | gfxTextRunFactory::TEXT_IS_8BIT);
flags | gfxTextRunFactory::TEXT_IS_8BIT, tp);
if (sw) {
aTextRun->CopyGlyphDataFrom(sw, aRunStart + i);
} else {
@ -4017,6 +4060,7 @@ gfxFontGroup::gfxFontGroup(const nsAString& aFamilies,
, mStyle(*aStyle)
, mUnderlineOffset(UNDERLINE_OFFSET_NOT_SET)
, mHyphenWidth(-1)
, mTextPerf(nullptr)
{
mUserFontSet = nullptr;
SetUserFontSet(aUserFontSet);
@ -4177,7 +4221,9 @@ gfxFontGroup::~gfxFontGroup()
gfxFontGroup *
gfxFontGroup::Copy(const gfxFontStyle *aStyle)
{
return new gfxFontGroup(mFamilies, aStyle, mUserFontSet);
gfxFontGroup *fg = new gfxFontGroup(mFamilies, aStyle, mUserFontSet);
fg->SetTextPerfMetrics(mTextPerf);
return fg;
}
bool
@ -5013,6 +5059,16 @@ void gfxFontGroup::ComputeRanges(nsTArray<gfxTextRange>& aRanges,
nsRefPtr<gfxFont> font =
FindFontForChar(ch, prevCh, aRunScript, prevFont, &matchType);
#ifndef RELEASE_BUILD
if (MOZ_UNLIKELY(mTextPerf)) {
if (matchType == gfxTextRange::kPrefsFallback) {
mTextPerf->current.fallbackPrefs++;
} else if (matchType == gfxTextRange::kSystemFallback) {
mTextPerf->current.fallbackSystem++;
}
}
#endif
prevCh = ch;
if (lastRangeIndex == -1) {
@ -5569,6 +5625,13 @@ gfxTextRun::gfxTextRun(const gfxTextRunFactory::Parameters *aParams,
MOZ_COUNT_CTOR(gfxTextRun);
NS_ADDREF(mFontGroup);
#ifndef RELEASE_BUILD
gfxTextPerfMetrics *tp = aFontGroup->GetTextPerfMetrics();
if (tp) {
tp->current.textrunConst++;
}
#endif
mCharacterGlyphs = reinterpret_cast<CompressedGlyph*>(this + 1);
if (aParams->mSkipChars) {
@ -5596,6 +5659,12 @@ gfxTextRun::~gfxTextRun()
// been told to release its reference to the group, so we mustn't do that
// again here.
if (!mReleasedFontGroup) {
#ifndef RELEASE_BUILD
gfxTextPerfMetrics *tp = mFontGroup->GetTextPerfMetrics();
if (tp) {
tp->current.textrunDestr++;
}
#endif
NS_RELEASE(mFontGroup);
}
@ -6648,7 +6717,8 @@ gfxTextRun::SetSpaceGlyph(gfxFont *aFont, gfxContext *aContext,
mAppUnitsPerDevUnit,
gfxTextRunFactory::TEXT_IS_8BIT |
gfxTextRunFactory::TEXT_IS_ASCII |
gfxTextRunFactory::TEXT_IS_PERSISTENT);
gfxTextRunFactory::TEXT_IS_PERSISTENT,
nullptr);
if (sw) {
AddGlyphRun(aFont, gfxTextRange::kFontGroup, aCharIndex, false);
CopyGlyphDataFrom(sw, aCharIndex);

View File

@ -1014,6 +1014,59 @@ protected:
nsCOMPtr<nsITimer> mWordCacheExpirationTimer;
};
class gfxTextPerfMetrics {
public:
struct TextCounts {
uint32_t numContentTextRuns;
uint32_t numChromeTextRuns;
uint32_t numChars;
uint32_t maxTextRunLen;
uint32_t wordCacheSpaceRules;
uint32_t wordCacheLong;
uint32_t wordCacheHit;
uint32_t wordCacheMiss;
uint32_t fallbackPrefs;
uint32_t fallbackSystem;
uint32_t textrunConst;
uint32_t textrunDestr;
};
uint32_t reflowCount;
// counts per reflow operation
TextCounts current;
// totals for the lifetime of a document
TextCounts cumulative;
gfxTextPerfMetrics() {
memset(this, 0, sizeof(gfxTextPerfMetrics));
}
// add current totals to cumulative ones
void Accumulate() {
if (current.numChars == 0) {
return;
}
cumulative.numContentTextRuns += current.numContentTextRuns;
cumulative.numChromeTextRuns += current.numChromeTextRuns;
cumulative.numChars += current.numChars;
if (current.maxTextRunLen > cumulative.maxTextRunLen) {
cumulative.maxTextRunLen = current.maxTextRunLen;
}
cumulative.wordCacheSpaceRules += current.wordCacheSpaceRules;
cumulative.wordCacheLong += current.wordCacheLong;
cumulative.wordCacheHit += current.wordCacheHit;
cumulative.wordCacheMiss += current.wordCacheMiss;
cumulative.fallbackPrefs += current.fallbackPrefs;
cumulative.fallbackSystem += current.fallbackSystem;
cumulative.textrunConst += current.textrunConst;
cumulative.textrunDestr += current.textrunDestr;
memset(&current, 0, sizeof(current));
}
};
class gfxTextRunFactory {
NS_INLINE_DECL_REFCOUNTING(gfxTextRunFactory)
@ -1645,7 +1698,8 @@ public:
uint32_t aHash,
int32_t aRunScript,
int32_t aAppUnitsPerDevUnit,
uint32_t aFlags);
uint32_t aFlags,
gfxTextPerfMetrics *aTextPerf);
// Ensure the ShapedWord cache is initialized. This MUST be called before
// any attempt to use GetShapedWord().
@ -3456,6 +3510,10 @@ public:
// with no @font-face rule, this always returns 0.
uint64_t GetGeneration();
// used when logging text performance
gfxTextPerfMetrics *GetTextPerfMetrics() { return mTextPerf; }
void SetTextPerfMetrics(gfxTextPerfMetrics *aTextPerf) { mTextPerf = aTextPerf; }
// If there is a user font set, check to see whether the font list or any
// caches need updating.
virtual void UpdateFontList();
@ -3486,6 +3544,8 @@ protected:
gfxUserFontSet* mUserFontSet;
uint64_t mCurrGeneration; // track the current user font set generation, rebuild font list if needed
gfxTextPerfMetrics *mTextPerf;
// Cache a textrun representing an ellipsis (useful for CSS text-overflow)
// at a specific appUnitsPerDevPixel size
nsAutoPtr<gfxTextRun> mCachedEllipsisTextRun;

View File

@ -120,6 +120,7 @@ static PRLogModuleInfo *sFontInitLog = nullptr;
static PRLogModuleInfo *sTextrunLog = nullptr;
static PRLogModuleInfo *sTextrunuiLog = nullptr;
static PRLogModuleInfo *sCmapDataLog = nullptr;
static PRLogModuleInfo *sTextPerfLog = nullptr;
#endif
/* Class to listen for pref changes so that chrome code can dynamically
@ -364,11 +365,12 @@ gfxPlatform::Init()
gEverInitialized = true;
#ifdef PR_LOGGING
sFontlistLog = PR_NewLogModule("fontlist");;
sFontInitLog = PR_NewLogModule("fontinit");;
sTextrunLog = PR_NewLogModule("textrun");;
sTextrunuiLog = PR_NewLogModule("textrunui");;
sCmapDataLog = PR_NewLogModule("cmapdata");;
sFontlistLog = PR_NewLogModule("fontlist");
sFontInitLog = PR_NewLogModule("fontinit");
sTextrunLog = PR_NewLogModule("textrun");
sTextrunuiLog = PR_NewLogModule("textrunui");
sCmapDataLog = PR_NewLogModule("cmapdata");
sTextPerfLog = PR_NewLogModule("textperf");
#endif
gGfxPlatformPrefsLock = new Mutex("gfxPlatform::gGfxPlatformPrefsLock");
@ -1945,6 +1947,9 @@ gfxPlatform::GetLog(eGfxLog aWhichLog)
case eGfxLog_cmapdata:
return sCmapDataLog;
break;
case eGfxLog_textperf:
return sTextPerfLog;
break;
default:
break;
}

View File

@ -117,7 +117,9 @@ enum eGfxLog {
// dump text runs, font matching, system fallback for chrome
eGfxLog_textrunui = 3,
// dump cmap coverage data as they are loaded
eGfxLog_cmapdata = 4
eGfxLog_cmapdata = 4,
// text perf data
eGfxLog_textperf = 5
};
// when searching through pref langs, max number of pref langs

View File

@ -180,7 +180,7 @@ public:
#ifdef DEBUG_DISPLAY_ITEM_DATA
void Dump(const char *aPrefix = "") {
printf("%sLayerManagerData %p\n", aPrefix, this);
printf_stderr("%sLayerManagerData %p\n", aPrefix, this);
nsAutoCString prefix;
prefix += aPrefix;
prefix += " ";
@ -899,7 +899,7 @@ InvalidatePostTransformRegion(ThebesLayer* aLayer, const nsIntRegion& aRegion,
if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
nsAutoCString str;
AppendToString(str, rgn);
printf("Invalidating layer %p: %s\n", aLayer, str.get());
printf_stderr("Invalidating layer %p: %s\n", aLayer, str.get());
}
#endif
}
@ -967,7 +967,7 @@ FrameLayerBuilder::RemoveFrameFromLayerManager(nsIFrame* aFrame,
while (rootData->mParent) {
rootData = rootData->mParent;
}
printf("Removing frame %p - dumping display data\n", aFrame);
printf_stderr("Removing frame %p - dumping display data\n", aFrame);
rootData->Dump();
}
#endif
@ -1057,7 +1057,7 @@ FrameLayerBuilder::ProcessRemovedDisplayItems(nsRefPtrHashKey<DisplayItemData>*
if (t) {
#ifdef MOZ_DUMP_PAINTING
if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
printf("Invalidating unused display item (%i) belonging to frame %p from layer %p\n", data->mDisplayItemKey, data->mFrameList[0], t);
printf_stderr("Invalidating unused display item (%i) belonging to frame %p from layer %p\n", data->mDisplayItemKey, data->mFrameList[0], t);
}
#endif
InvalidatePostTransformRegion(t,
@ -1116,11 +1116,11 @@ FrameLayerBuilder::DumpDisplayItemDataForFrame(nsRefPtrHashKey<DisplayItemData>*
}
str += "\n";
printf("%s", str.get());
printf_stderr("%s", str.get());
if (data->mInactiveManager) {
prefix += " ";
printf("%sDumping inactive layer info:\n", prefix.get());
printf_stderr("%sDumping inactive layer info:\n", prefix.get());
LayerManagerData* lmd = static_cast<LayerManagerData*>
(data->mInactiveManager->GetUserData(&gLayerManagerUserData));
lmd->Dump(prefix.get());
@ -1352,7 +1352,7 @@ InvalidateEntireThebesLayer(ThebesLayer* aLayer, const nsIFrame* aAnimatedGeomet
{
#ifdef MOZ_DUMP_PAINTING
if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
printf("Invalidating entire layer %p\n", aLayer);
printf_stderr("Invalidating entire layer %p\n", aLayer);
}
#endif
nsIntRect invalidate = aLayer->GetValidRegion().GetBounds();
@ -1402,7 +1402,7 @@ ContainerState::CreateOrRecycleThebesLayer(const nsIFrame* aAnimatedGeometryRoot
if (!data->mRegionToInvalidate.IsEmpty()) {
#ifdef MOZ_DUMP_PAINTING
if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
printf("Invalidating deleted frame content from layer %p\n", layer.get());
printf_stderr("Invalidating deleted frame content from layer %p\n", layer.get());
}
#endif
layer->InvalidateRegion(data->mRegionToInvalidate);
@ -1410,7 +1410,7 @@ ContainerState::CreateOrRecycleThebesLayer(const nsIFrame* aAnimatedGeometryRoot
if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
nsAutoCString str;
AppendToString(str, data->mRegionToInvalidate);
printf("Invalidating layer %p: %s\n", layer.get(), str.get());
printf_stderr("Invalidating layer %p: %s\n", layer.get(), str.get());
}
#endif
data->mRegionToInvalidate.SetEmpty();
@ -2053,9 +2053,9 @@ DumpPaintedImage(nsDisplayItem* aItem, gfxASurface* aSurf)
nsCString string(aItem->Name());
string.Append("-");
string.AppendInt((uint64_t)aItem);
fprintf(gfxUtils::sDumpPaintFile, "array[\"%s\"]=\"", string.BeginReading());
fprintf_stderr(gfxUtils::sDumpPaintFile, "array[\"%s\"]=\"", string.BeginReading());
aSurf->DumpAsDataURL(gfxUtils::sDumpPaintFile);
fprintf(gfxUtils::sDumpPaintFile, "\";");
fprintf_stderr(gfxUtils::sDumpPaintFile, "\";");
}
#endif
@ -2396,7 +2396,7 @@ ContainerState::InvalidateForLayerChange(nsDisplayItem* aItem,
// or a new scale here
#ifdef MOZ_DUMP_PAINTING
if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
printf("Display item type %s(%p) changed layers %p to %p!\n", aItem->Name(), aItem->Frame(), t, aNewLayer);
printf_stderr("Display item type %s(%p) changed layers %p to %p!\n", aItem->Name(), aItem->Frame(), t, aNewLayer);
}
#endif
InvalidatePostTransformRegion(t,
@ -2439,7 +2439,7 @@ ContainerState::InvalidateForLayerChange(nsDisplayItem* aItem,
combined = aClip.ApplyNonRoundedIntersection(aGeometry->ComputeInvalidationRegion());
#ifdef MOZ_DUMP_PAINTING
if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
printf("Display item type %s(%p) added to layer %p!\n", aItem->Name(), aItem->Frame(), aNewLayer);
printf_stderr("Display item type %s(%p) added to layer %p!\n", aItem->Name(), aItem->Frame(), aNewLayer);
}
#endif
} else if (isInvalid || (aItem->IsInvalid(invalid) && invalid.IsEmpty())) {
@ -2449,7 +2449,7 @@ ContainerState::InvalidateForLayerChange(nsDisplayItem* aItem,
combined.Or(combined, aClip.ApplyNonRoundedIntersection(aGeometry->ComputeInvalidationRegion()));
#ifdef MOZ_DUMP_PAINTING
if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
printf("Display item type %s(%p) (in layer %p) belongs to an invalidated frame!\n", aItem->Name(), aItem->Frame(), aNewLayer);
printf_stderr("Display item type %s(%p) (in layer %p) belongs to an invalidated frame!\n", aItem->Name(), aItem->Frame(), aNewLayer);
}
#endif
} else {
@ -2476,7 +2476,7 @@ ContainerState::InvalidateForLayerChange(nsDisplayItem* aItem,
#ifdef MOZ_DUMP_PAINTING
if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
if (!combined.IsEmpty()) {
printf("Display item type %s(%p) (in layer %p) changed geometry!\n", aItem->Name(), aItem->Frame(), aNewLayer);
printf_stderr("Display item type %s(%p) (in layer %p) changed geometry!\n", aItem->Name(), aItem->Frame(), aNewLayer);
}
}
#endif
@ -2583,7 +2583,7 @@ FrameLayerBuilder::AddThebesDisplayItem(ThebesLayer* aLayer,
if (!invalid.IsEmpty()) {
#ifdef MOZ_DUMP_PAINTING
if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
printf("Inactive LayerManager(%p) for display item %s(%p) has an invalid region - invalidating layer %p\n", tempManager.get(), aItem->Name(), aItem->Frame(), aLayer);
printf_stderr("Inactive LayerManager(%p) for display item %s(%p) has an invalid region - invalidating layer %p\n", tempManager.get(), aItem->Name(), aItem->Frame(), aLayer);
}
#endif
if (hasClip) {

View File

@ -2234,7 +2234,7 @@ nsDisplayThemedBackground::~nsDisplayThemedBackground()
void
nsDisplayThemedBackground::WriteDebugInfo(FILE *aOutput)
{
fprintf(aOutput, "(themed, appearance:%d) ", mAppearance);
fprintf_stderr(aOutput, "(themed, appearance:%d) ", mAppearance);
}
#endif
@ -4713,32 +4713,32 @@ nsDisplaySVGEffects::PrintEffects(FILE* aOutput)
bool isOK = true;
nsSVGClipPathFrame *clipPathFrame = effectProperties.GetClipPathFrame(&isOK);
bool first = true;
fprintf(aOutput, " effects=(");
fprintf_stderr(aOutput, " effects=(");
if (mFrame->StyleDisplay()->mOpacity != 1.0f) {
first = false;
fprintf(aOutput, "opacity(%f)", mFrame->StyleDisplay()->mOpacity);
fprintf_stderr(aOutput, "opacity(%f)", mFrame->StyleDisplay()->mOpacity);
}
if (clipPathFrame) {
if (!first) {
fprintf(aOutput, ", ");
fprintf_stderr(aOutput, ", ");
}
fprintf(aOutput, "clip(%s)", clipPathFrame->IsTrivial() ? "trivial" : "non-trivial");
fprintf_stderr(aOutput, "clip(%s)", clipPathFrame->IsTrivial() ? "trivial" : "non-trivial");
first = false;
}
if (effectProperties.GetFilterFrame(&isOK)) {
if (!first) {
fprintf(aOutput, ", ");
fprintf_stderr(aOutput, ", ");
}
fprintf(aOutput, "filter");
fprintf_stderr(aOutput, "filter");
first = false;
}
if (effectProperties.GetMaskFrame(&isOK)) {
if (!first) {
fprintf(aOutput, ", ");
fprintf_stderr(aOutput, ", ");
}
fprintf(aOutput, "mask");
fprintf_stderr(aOutput, "mask");
}
fprintf(aOutput, ")");
fprintf_stderr(aOutput, ")");
}
#endif

View File

@ -1934,17 +1934,32 @@ public:
virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE
{
return new nsDisplayItemBoundsGeometry(this, aBuilder);
return new nsDisplaySolidColorGeometry(this, aBuilder, mColor);
}
virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
const nsDisplayItemGeometry* aGeometry,
nsRegion* aInvalidRegion) MOZ_OVERRIDE
{
const nsDisplayItemBoundsGeometry* geometry = static_cast<const nsDisplayItemBoundsGeometry*>(aGeometry);
const nsDisplaySolidColorGeometry* geometry =
static_cast<const nsDisplaySolidColorGeometry*>(aGeometry);
if (mColor != geometry->mColor) {
bool dummy;
aInvalidRegion->Or(geometry->mBounds, GetBounds(aBuilder, &dummy));
return;
}
ComputeInvalidationRegionDifference(aBuilder, geometry, aInvalidRegion);
}
#ifdef MOZ_DUMP_PAINTING
virtual void WriteDebugInfo(FILE *aOutput) MOZ_OVERRIDE
{
fprintf(aOutput, "(rgba %d,%d,%d,%d)",
NS_GET_R(mColor), NS_GET_G(mColor),
NS_GET_B(mColor), NS_GET_A(mColor));
}
#endif
NS_DISPLAY_DECL_NAME("SolidColor", TYPE_SOLID_COLOR)
private:
@ -2155,7 +2170,7 @@ public:
NS_DISPLAY_DECL_NAME("BackgroundColor", TYPE_BACKGROUND_COLOR)
#ifdef MOZ_DUMP_PAINTING
virtual void WriteDebugInfo(FILE *aOutput) MOZ_OVERRIDE {
fprintf(aOutput, "(rgba %d,%d,%d,%d)",
fprintf_stderr(aOutput, "(rgba %d,%d,%d,%d)",
NS_GET_R(mColor), NS_GET_G(mColor),
NS_GET_B(mColor), NS_GET_A(mColor));
@ -2489,7 +2504,7 @@ public:
NS_DISPLAY_DECL_NAME("Opacity", TYPE_OPACITY)
#ifdef MOZ_DUMP_PAINTING
virtual void WriteDebugInfo(FILE *aOutput) MOZ_OVERRIDE {
fprintf(aOutput, "(opacity %f)", mFrame->StyleDisplay()->mOpacity);
fprintf_stderr(aOutput, "(opacity %f)", mFrame->StyleDisplay()->mOpacity);
}
#endif

View File

@ -116,4 +116,17 @@ public:
nsRect mPaddingRect;
};
class nsDisplaySolidColorGeometry : public nsDisplayItemBoundsGeometry
{
public:
nsDisplaySolidColorGeometry(nsDisplayItem* aItem,
nsDisplayListBuilder* aBuilder,
nscolor aColor)
: nsDisplayItemBoundsGeometry(aItem, aBuilder)
, mColor(aColor)
{ }
nscolor mColor;
};
#endif /*NSDISPLAYLISTINVALIDATION_H_*/

View File

@ -1025,6 +1025,7 @@ nsDocumentViewer::LoadComplete(nsresult aStatus)
// mPresShell could have been removed now, see bug 378682/421432
if (mPresShell) {
mPresShell->ScrollToAnchor();
mPresShell->LoadComplete();
}
}

View File

@ -417,6 +417,11 @@ public:
*/
virtual bool IsLayoutFlushObserver() = 0;
/**
* Called when document load completes.
*/
virtual NS_HIDDEN_(void) LoadComplete() = 0;
/**
* This calls through to the frame manager to get the root frame.
*/

View File

@ -127,16 +127,16 @@ PrintDisplayListTo(nsDisplayListBuilder* aBuilder, const nsDisplayList& aList,
FILE* aOutput, bool aDumpHtml)
{
if (aDumpHtml) {
fprintf(aOutput, "<ul>");
fprintf_stderr(aOutput, "<ul>");
}
for (nsDisplayItem* i = aList.GetBottom(); i != nullptr; i = i->GetAbove()) {
if (aDumpHtml) {
fprintf(aOutput, "<li>");
fprintf_stderr(aOutput, "<li>");
} else {
sPrintDisplayListIndent ++;
for (int indent = 0; indent < sPrintDisplayListIndent; indent++) {
fprintf(aOutput, " ");
fprintf_stderr(aOutput, " ");
}
}
nsIFrame* f = i->Frame();
@ -161,9 +161,9 @@ PrintDisplayListTo(nsDisplayListBuilder* aBuilder, const nsDisplayList& aList,
nsCString string(i->Name());
string.Append("-");
string.AppendInt((uint64_t)i);
fprintf(aOutput, "<a href=\"javascript:ViewImage('%s')\">", string.BeginReading());
fprintf_stderr(aOutput, "<a href=\"javascript:ViewImage('%s')\">", string.BeginReading());
}
fprintf(aOutput, "%s %p(%s) bounds(%d,%d,%d,%d) visible(%d,%d,%d,%d) componentAlpha(%d,%d,%d,%d) clip(%s) %s",
fprintf_stderr(aOutput, "%s %p(%s) bounds(%d,%d,%d,%d) visible(%d,%d,%d,%d) componentAlpha(%d,%d,%d,%d) clip(%s) %s",
i->Name(), (void*)f, NS_ConvertUTF16toUTF8(fName).get(),
rect.x, rect.y, rect.width, rect.height,
vis.x, vis.y, vis.width, vis.height,
@ -172,19 +172,19 @@ PrintDisplayListTo(nsDisplayListBuilder* aBuilder, const nsDisplayList& aList,
i->IsUniform(aBuilder, &color) ? " uniform" : "");
nsRegionRectIterator iter(opaque);
for (const nsRect* r = iter.Next(); r; r = iter.Next()) {
fprintf(aOutput, " (opaque %d,%d,%d,%d)", r->x, r->y, r->width, r->height);
fprintf_stderr(aOutput, " (opaque %d,%d,%d,%d)", r->x, r->y, r->width, r->height);
}
i->WriteDebugInfo(aOutput);
if (aDumpHtml && i->Painted()) {
fprintf(aOutput, "</a>");
fprintf_stderr(aOutput, "</a>");
}
uint32_t key = i->GetPerFrameKey();
Layer* layer = mozilla::FrameLayerBuilder::GetDebugOldLayerFor(f, key);
if (layer) {
if (aDumpHtml) {
fprintf(aOutput, " <a href=\"#%p\">layer=%p</a>", layer, layer);
fprintf_stderr(aOutput, " <a href=\"#%p\">layer=%p</a>", layer, layer);
} else {
fprintf(aOutput, " layer=%p", layer);
fprintf_stderr(aOutput, " layer=%p", layer);
}
}
if (i->GetType() == nsDisplayItem::TYPE_SVG_EFFECTS) {
@ -195,14 +195,14 @@ PrintDisplayListTo(nsDisplayListBuilder* aBuilder, const nsDisplayList& aList,
PrintDisplayListTo(aBuilder, *list, aOutput, aDumpHtml);
}
if (aDumpHtml) {
fprintf(aOutput, "</li>");
fprintf_stderr(aOutput, "</li>");
} else {
sPrintDisplayListIndent --;
}
}
if (aDumpHtml) {
fprintf(aOutput, "</ul>");
fprintf_stderr(aOutput, "</ul>");
}
}

View File

@ -2086,7 +2086,7 @@ nsLayoutUtils::GetFramesForArea(nsIFrame* aFrame, const nsRect& aRect,
#ifdef MOZ_DUMP_PAINTING
if (gDumpEventList) {
fprintf(stdout, "Event handling --- (%d,%d):\n", aRect.x, aRect.y);
fprintf_stderr(stderr, "Event handling --- (%d,%d):\n", aRect.x, aRect.y);
nsFrame::PrintDisplayList(&builder, list);
}
#endif
@ -2277,16 +2277,16 @@ nsLayoutUtils::PaintFrame(nsRenderingContext* aRenderingContext, nsIFrame* aFram
string.Append(".html");
gfxUtils::sDumpPaintFile = fopen(string.BeginReading(), "w");
} else {
gfxUtils::sDumpPaintFile = stdout;
gfxUtils::sDumpPaintFile = stderr;
}
if (gfxUtils::sDumpPaintingToFile) {
fprintf(gfxUtils::sDumpPaintFile, "<html><head><script>var array = {}; function ViewImage(index) { window.location = array[index]; }</script></head><body>");
fprintf_stderr(gfxUtils::sDumpPaintFile, "<html><head><script>var array = {}; function ViewImage(index) { window.location = array[index]; }</script></head><body>");
}
fprintf(gfxUtils::sDumpPaintFile, "Painting --- before optimization (dirty %d,%d,%d,%d):\n",
fprintf_stderr(gfxUtils::sDumpPaintFile, "Painting --- before optimization (dirty %d,%d,%d,%d):\n",
dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height);
nsFrame::PrintDisplayList(&builder, list, gfxUtils::sDumpPaintFile, gfxUtils::sDumpPaintingToFile);
if (gfxUtils::sDumpPaintingToFile) {
fprintf(gfxUtils::sDumpPaintFile, "<script>");
fprintf_stderr(gfxUtils::sDumpPaintFile, "<script>");
}
}
#endif
@ -2327,12 +2327,12 @@ nsLayoutUtils::PaintFrame(nsRenderingContext* aRenderingContext, nsIFrame* aFram
#ifdef MOZ_DUMP_PAINTING
if (gfxUtils::sDumpPaintList || gfxUtils::sDumpPainting) {
if (gfxUtils::sDumpPaintingToFile) {
fprintf(gfxUtils::sDumpPaintFile, "</script>");
fprintf_stderr(gfxUtils::sDumpPaintFile, "</script>");
}
fprintf(gfxUtils::sDumpPaintFile, "Painting --- after optimization:\n");
fprintf_stderr(gfxUtils::sDumpPaintFile, "Painting --- after optimization:\n");
nsFrame::PrintDisplayList(&builder, list, gfxUtils::sDumpPaintFile, gfxUtils::sDumpPaintingToFile);
fprintf(gfxUtils::sDumpPaintFile, "Painting --- retained layer tree:\n");
fprintf_stderr(gfxUtils::sDumpPaintFile, "Painting --- retained layer tree:\n");
nsIWidget* widget = aFrame->GetNearestWidget();
if (widget) {
nsRefPtr<LayerManager> layerManager = widget->GetLayerManager();
@ -2599,7 +2599,9 @@ nsLayoutUtils::GetFontMetricsForStyleContext(nsStyleContext* aStyleContext,
float aInflation)
{
// pass the user font set object into the device context to pass along to CreateFontGroup
gfxUserFontSet* fs = aStyleContext->PresContext()->GetUserFontSet();
nsPresContext* pc = aStyleContext->PresContext();
gfxUserFontSet* fs = pc->GetUserFontSet();
gfxTextPerfMetrics* tp = pc->GetTextPerfMetrics();
nsFont font = aStyleContext->StyleFont()->mFont;
// We need to not run font.size through floats when it's large since
@ -2608,9 +2610,9 @@ nsLayoutUtils::GetFontMetricsForStyleContext(nsStyleContext* aStyleContext,
if (aInflation != 1.0f) {
font.size = NSToCoordRound(font.size * aInflation);
}
return aStyleContext->PresContext()->DeviceContext()->GetMetricsFor(
return pc->DeviceContext()->GetMetricsFor(
font, aStyleContext->StyleFont()->mLanguage,
fs, *aFontMetrics);
fs, tp, *aFontMetrics);
}
nsIFrame*
@ -2947,9 +2949,9 @@ nsLayoutUtils::IntrinsicForContainer(nsRenderingContext *aRenderingContext,
NS_PRECONDITION(aType == MIN_WIDTH || aType == PREF_WIDTH, "bad type");
#ifdef DEBUG_INTRINSIC_WIDTH
nsFrame::IndentBy(stdout, gNoiseIndent);
static_cast<nsFrame*>(aFrame)->ListTag(stdout);
printf(" %s intrinsic width for container:\n",
nsFrame::IndentBy(stderr, gNoiseIndent);
static_cast<nsFrame*>(aFrame)->ListTag(stderr);
printf_stderr(" %s intrinsic width for container:\n",
aType == MIN_WIDTH ? "min" : "pref");
#endif
@ -3007,9 +3009,9 @@ nsLayoutUtils::IntrinsicForContainer(nsRenderingContext *aRenderingContext,
result = aFrame->GetPrefWidth(aRenderingContext);
#ifdef DEBUG_INTRINSIC_WIDTH
--gNoiseIndent;
nsFrame::IndentBy(stdout, gNoiseIndent);
static_cast<nsFrame*>(aFrame)->ListTag(stdout);
printf(" %s intrinsic width from frame is %d.\n",
nsFrame::IndentBy(stderr, gNoiseIndent);
static_cast<nsFrame*>(aFrame)->ListTag(stderr);
printf_stderr(" %s intrinsic width from frame is %d.\n",
aType == MIN_WIDTH ? "min" : "pref", result);
#endif
@ -3196,9 +3198,9 @@ nsLayoutUtils::IntrinsicForContainer(nsRenderingContext *aRenderingContext,
}
#ifdef DEBUG_INTRINSIC_WIDTH
nsFrame::IndentBy(stdout, gNoiseIndent);
static_cast<nsFrame*>(aFrame)->ListTag(stdout);
printf(" %s intrinsic width for container is %d twips.\n",
nsFrame::IndentBy(stderr, gNoiseIndent);
static_cast<nsFrame*>(aFrame)->ListTag(stderr);
printf_stderr(" %s intrinsic width for container is %d twips.\n",
aType == MIN_WIDTH ? "min" : "pref", result);
#endif

View File

@ -235,6 +235,12 @@ nsPresContext::nsPresContext(nsIDocument* aDocument, nsPresContextType aType)
mUserFontSet = nullptr;
mUserFontSetDirty = true;
// if text perf logging enabled, init stats struct
PRLogModuleInfo *log = gfxPlatform::GetLog(eGfxLog_textperf);
if (log && PR_LOG_TEST(log, PR_LOG_WARNING)) {
mTextPerf = new gfxTextPerfMetrics();
}
PR_INIT_CLIST(&mDOMMediaQueryLists);
}

View File

@ -56,6 +56,7 @@ struct nsStyleBackground;
struct nsStyleBorder;
class nsIRunnable;
class gfxUserFontSet;
class gfxTextPerfMetrics;
class nsUserFontSet;
struct nsFontFaceRuleContainer;
class nsObjectFrame;
@ -788,6 +789,8 @@ public:
*/
const nscoord* GetBorderWidthTable() { return mBorderWidthTable; }
gfxTextPerfMetrics *GetTextPerfMetrics() { return mTextPerf; }
bool IsDynamic() { return (mType == eContext_PageLayout || mType == eContext_Galley); }
bool IsScreen() { return (mMedium == nsGkAtoms::screen ||
mType == eContext_PageLayout ||
@ -1194,6 +1197,9 @@ protected:
// container for per-context fonts (downloadable, SVG, etc.)
nsUserFontSet* mUserFontSet;
// text performance metrics
nsAutoPtr<gfxTextPerfMetrics> mTextPerf;
nsRect mVisibleArea;
nsSize mPageSize;
float mPageScale;

View File

@ -878,12 +878,106 @@ PresShell::Init(nsIDocument* aDocument,
SetupFontInflation();
}
#ifdef PR_LOGGING
enum TextPerfLogType {
eLog_reflow,
eLog_loaddone,
eLog_totals
};
static void
LogTextPerfStats(gfxTextPerfMetrics* aTextPerf,
PresShell* aPresShell,
const gfxTextPerfMetrics::TextCounts& aCounts,
float aTime, TextPerfLogType aLogType, const char* aURL)
{
char prefix[256];
switch (aLogType) {
case eLog_reflow:
sprintf(prefix, "(textperf-reflow) %p time-ms: %7.0f", aPresShell, aTime);
break;
case eLog_loaddone:
sprintf(prefix, "(textperf-loaddone) %p time-ms: %7.0f", aPresShell, aTime);
break;
default:
MOZ_ASSERT(aLogType == eLog_totals, "unknown textperf log type");
sprintf(prefix, "(textperf-totals) %p", aPresShell);
}
PRLogModuleInfo* tpLog = gfxPlatform::GetLog(eGfxLog_textperf);
// ignore XUL contexts unless at debug level
PRLogModuleLevel logLevel = PR_LOG_WARNING;
if (aCounts.numContentTextRuns == 0) {
logLevel = PR_LOG_DEBUG;
}
double hitRatio = 0.0;
uint32_t lookups = aCounts.wordCacheHit + aCounts.wordCacheMiss;
if (lookups) {
hitRatio = double(aCounts.wordCacheHit) / double(lookups);
}
if (aLogType == eLog_loaddone) {
PR_LOG(tpLog, logLevel,
("%s reflow: %d chars: %d "
"[%s] "
"content-textruns: %d chrome-textruns: %d "
"max-textrun-len: %d "
"word-cache-lookups: %d word-cache-hit-ratio: %4.3f "
"word-cache-space: %d word-cache-long: %d "
"pref-fallbacks: %d system-fallbacks: %d "
"textruns-const: %d textruns-destr: %d "
"cumulative-textruns-destr: %d\n",
prefix, aTextPerf->reflowCount, aCounts.numChars,
(aURL ? aURL : ""),
aCounts.numContentTextRuns, aCounts.numChromeTextRuns,
aCounts.maxTextRunLen,
lookups, hitRatio,
aCounts.wordCacheSpaceRules, aCounts.wordCacheLong,
aCounts.fallbackPrefs, aCounts.fallbackSystem,
aCounts.textrunConst, aCounts.textrunDestr,
aTextPerf->cumulative.textrunDestr));
} else {
PR_LOG(tpLog, logLevel,
("%s reflow: %d chars: %d "
"content-textruns: %d chrome-textruns: %d "
"max-textrun-len: %d "
"word-cache-lookups: %d word-cache-hit-ratio: %4.3f "
"word-cache-space: %d word-cache-long: %d "
"pref-fallbacks: %d system-fallbacks: %d "
"textruns-const: %d textruns-destr: %d "
"cumulative-textruns-destr: %d\n",
prefix, aTextPerf->reflowCount, aCounts.numChars,
aCounts.numContentTextRuns, aCounts.numChromeTextRuns,
aCounts.maxTextRunLen,
lookups, hitRatio,
aCounts.wordCacheSpaceRules, aCounts.wordCacheLong,
aCounts.fallbackPrefs, aCounts.fallbackSystem,
aCounts.textrunConst, aCounts.textrunDestr,
aTextPerf->cumulative.textrunDestr));
}
}
#endif
void
PresShell::Destroy()
{
NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
"destroy called on presshell while scripts not blocked");
// dump out cumulative text perf metrics
#ifdef PR_LOGGING
gfxTextPerfMetrics* tp;
if (mPresContext && (tp = mPresContext->GetTextPerfMetrics())) {
tp->Accumulate();
if (tp->cumulative.numChars > 0) {
LogTextPerfStats(tp, this, tp->cumulative, 0.0, eLog_totals, nullptr);
}
}
#endif
#ifdef MOZ_REFLOW_PERF
DumpReflows();
if (mReflowCountMgr) {
@ -2399,15 +2493,24 @@ PresShell::BeginLoad(nsIDocument *aDocument)
mDocumentLoading = true;
#ifdef PR_LOGGING
if (gLog && PR_LOG_TEST(gLog, PR_LOG_DEBUG)) {
gfxTextPerfMetrics *tp = nullptr;
if (mPresContext) {
tp = mPresContext->GetTextPerfMetrics();
}
bool shouldLog = gLog && PR_LOG_TEST(gLog, PR_LOG_DEBUG);
if (shouldLog || tp) {
mLoadBegin = TimeStamp::Now();
}
if (shouldLog) {
nsIURI* uri = mDocument->GetDocumentURI();
nsAutoCString spec;
if (uri) {
uri->GetSpec(spec);
}
PR_LOG(gLog, PR_LOG_DEBUG,
("(presshell) %p begin load [%s]\n",
("(presshell) %p load begin [%s]\n",
this, spec.get()));
}
#endif
@ -2421,19 +2524,38 @@ PresShell::EndLoad(nsIDocument *aDocument)
RestoreRootScrollPosition();
mDocumentLoading = false;
}
void
PresShell::LoadComplete()
{
#ifdef PR_LOGGING
gfxTextPerfMetrics *tp = nullptr;
if (mPresContext) {
tp = mPresContext->GetTextPerfMetrics();
}
// log load
if (gLog && PR_LOG_TEST(gLog, PR_LOG_DEBUG)) {
bool shouldLog = gLog && PR_LOG_TEST(gLog, PR_LOG_DEBUG);
if (shouldLog || tp) {
TimeDuration loadTime = TimeStamp::Now() - mLoadBegin;
nsIURI* uri = mDocument->GetDocumentURI();
nsAutoCString spec;
if (uri) {
uri->GetSpec(spec);
}
PR_LOG(gLog, PR_LOG_DEBUG,
("(presshell) %p end load time-ms: %9.2f [%s]\n",
this, loadTime.ToMilliseconds(), spec.get()));
if (shouldLog) {
PR_LOG(gLog, PR_LOG_DEBUG,
("(presshell) %p load done time-ms: %9.2f [%s]\n",
this, loadTime.ToMilliseconds(), spec.get()));
}
if (tp) {
tp->Accumulate();
if (tp->cumulative.numChars > 0) {
LogTextPerfStats(tp, this, tp->cumulative, loadTime.ToMilliseconds(),
eLog_loaddone, spec.get());
}
}
}
#endif
}
@ -7877,6 +7999,14 @@ PresShell::DoReflow(nsIFrame* target, bool aInterruptible)
return true;
}
gfxTextPerfMetrics* tp = mPresContext->GetTextPerfMetrics();
TimeStamp timeStart;
if (tp) {
tp->Accumulate();
tp->reflowCount++;
timeStart = TimeStamp::Now();
}
target->SchedulePaint();
nsIFrame *parent = nsLayoutUtils::GetCrossDocParentFrame(target);
while (parent) {
@ -8032,6 +8162,18 @@ PresShell::DoReflow(nsIFrame* target, bool aInterruptible)
MaybeScheduleReflow();
}
#ifdef PR_LOGGING
// dump text perf metrics for reflows with significant text processing
if (tp) {
if (tp->current.numChars > 100) {
TimeDuration reflowTime = TimeStamp::Now() - timeStart;
LogTextPerfStats(tp, this, tp->current,
reflowTime.ToMilliseconds(), eLog_reflow, nullptr);
}
tp->Accumulate();
}
#endif
return !interrupted;
}
@ -9141,7 +9283,9 @@ void ReflowCountMgr::PaintCount(const char* aName,
// We have one frame, therefore we must have a root...
aPresContext->GetPresShell()->GetRootFrame()->
StyleFont()->mLanguage,
aPresContext->GetUserFontSet(), *getter_AddRefs(fm));
aPresContext->GetUserFontSet(),
aPresContext->GetTextPerfMetrics(),
*getter_AddRefs(fm));
aRenderingContext->SetFont(fm);
char buf[16];

View File

@ -318,6 +318,8 @@ public:
IsLayoutFlushObserver(this);
}
virtual void LoadComplete() MOZ_OVERRIDE;
void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
nsArenaMemoryStats *aArenaObjectsSize,
size_t *aPresShellSize,

View File

@ -1199,7 +1199,7 @@ nsRefreshDriver::Tick(int64_t aNowEpoch, TimeStamp aNowTime)
if (mViewManagerFlushIsPending) {
#ifdef MOZ_DUMP_PAINTING
if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
printf("Starting ProcessPendingUpdates\n");
printf_stderr("Starting ProcessPendingUpdates\n");
}
#endif
#ifndef MOZ_WIDGET_GONK
@ -1215,7 +1215,7 @@ nsRefreshDriver::Tick(int64_t aNowEpoch, TimeStamp aNowTime)
vm->ProcessPendingUpdates();
#ifdef MOZ_DUMP_PAINTING
if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
printf("Ending ProcessPendingUpdates\n");
printf_stderr("Ending ProcessPendingUpdates\n");
}
#endif
}

View File

@ -2017,6 +2017,8 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
new (aBuilder) nsDisplayBlendContainer(aBuilder, this, &resultList));
}
CreateOwnLayerIfNeeded(aBuilder, &resultList);
aList->AppendToTop(&resultList);
}
@ -8054,7 +8056,9 @@ void
nsIFrame::CreateOwnLayerIfNeeded(nsDisplayListBuilder* aBuilder,
nsDisplayList* aList)
{
if (GetContent()->HasAttr(kNameSpaceID_None, nsGkAtoms::layer)) {
if (GetContent() &&
GetContent()->IsXUL() &&
GetContent()->HasAttr(kNameSpaceID_None, nsGkAtoms::layer)) {
aList->AppendNewToTop(new (aBuilder)
nsDisplayOwnLayer(aBuilder, this, aList));
}

View File

@ -575,6 +575,7 @@ nsPageFrame::PaintHeaderFooter(nsRenderingContext& aRenderingContext,
nsRefPtr<nsFontMetrics> fontMet;
pc->DeviceContext()->GetMetricsFor(mPD->mHeadFootFont, nullptr,
pc->GetUserFontSet(),
pc->GetTextPerfMetrics(),
*getter_AddRefs(fontMet));
aRenderingContext.SetFont(fontMet);

View File

@ -924,6 +924,7 @@ SetFontFamily(nsStyleContext* aStyleContext,
aRenderingContext.DeviceContext()->GetMetricsFor(font,
aStyleContext->StyleFont()->mLanguage,
aStyleContext->PresContext()->GetUserFontSet(),
aStyleContext->PresContext()->GetTextPerfMetrics(),
*getter_AddRefs(fm));
// Set the font if it is an unicode table
// or if the same family name has been found
@ -1312,7 +1313,8 @@ nsMathMLChar::StretchInternal(nsPresContext* aPresContext,
nsRefPtr<nsFontMetrics> fm;
aRenderingContext.DeviceContext()->GetMetricsFor(font,
mStyleContext->StyleFont()->mLanguage,
aPresContext->GetUserFontSet(), *getter_AddRefs(fm));
aPresContext->GetUserFontSet(),
aPresContext->GetTextPerfMetrics(), *getter_AddRefs(fm));
aRenderingContext.SetFont(fm);
aDesiredStretchSize =
aRenderingContext.GetBoundingMetrics(mData.get(), uint32_t(mData.Length()));
@ -1868,7 +1870,7 @@ nsMathMLChar::PaintForeground(nsPresContext* aPresContext,
nsRefPtr<nsFontMetrics> fm;
aRenderingContext.DeviceContext()->GetMetricsFor(theFont,
styleContext->StyleFont()->mLanguage,
aPresContext->GetUserFontSet(),
aPresContext->GetUserFontSet(), aPresContext->GetTextPerfMetrics(),
*getter_AddRefs(fm));
aRenderingContext.SetFont(fm);

View File

@ -221,10 +221,11 @@ GetMetricsFor(nsPresContext* aPresContext,
if (aUseUserFontSet) {
fs = aPresContext->GetUserFontSet();
}
gfxTextPerfMetrics *tp = aPresContext->GetTextPerfMetrics();
nsRefPtr<nsFontMetrics> fm;
aPresContext->DeviceContext()->GetMetricsFor(font,
aStyleFont->mLanguage,
fs, *getter_AddRefs(fm));
fs, tp, *getter_AddRefs(fm));
return fm.forget();
}

View File

@ -481,6 +481,9 @@ function BrowserTabActor(aConnection, aBrowser, aTabBrowser)
this._extraActors = {};
this._onWindowCreated = this.onWindowCreated.bind(this);
// Number of event loops nested.
this._nestedEventLoopDepth = 0;
}
// XXX (bug 710213): BrowserTabActor attach/detach/exit/disconnect is a
@ -634,6 +637,9 @@ BrowserTabActor.prototype = {
type: "tabDetached" });
}
// Pop all nested event loops if we haven't already.
while (this._nestedEventLoopDepth > 0)
this.postNest();
this._browser = null;
this._tabbrowser = null;
},
@ -782,6 +788,7 @@ BrowserTabActor.prototype = {
.getInterface(Ci.nsIDOMWindowUtils);
windowUtils.suppressEventHandling(true);
windowUtils.suspendTimeouts();
this._nestedEventLoopDepth++;
},
/**
@ -790,6 +797,8 @@ BrowserTabActor.prototype = {
postNest: function BTA_postNest(aNestData) {
if (!this.window) {
// The tab is already closed.
dbg_assert(this._nestedEventLoopDepth === 0,
"window shouldn't be closed before all nested event loops have been popped");
return;
}
let windowUtils = this.window
@ -801,6 +810,7 @@ BrowserTabActor.prototype = {
this._pendingNavigation.resume();
this._pendingNavigation = null;
}
this._nestedEventLoopDepth--;
},
/**

View File

@ -309,7 +309,7 @@ void nsViewManager::Refresh(nsView *aView, const nsIntRegion& aRegion)
#ifdef DEBUG_roc
nsRect viewRect = aView->GetDimensions();
nsRect damageRect = damageRegion.GetBounds();
printf("XXX Damage rectangle (%d,%d,%d,%d) does not intersect the widget's view (%d,%d,%d,%d)!\n",
printf_stderr("XXX Damage rectangle (%d,%d,%d,%d) does not intersect the widget's view (%d,%d,%d,%d)!\n",
damageRect.x, damageRect.y, damageRect.width, damageRect.height,
viewRect.x, viewRect.y, viewRect.width, viewRect.height);
#endif
@ -337,7 +337,7 @@ void nsViewManager::Refresh(nsView *aView, const nsIntRegion& aRegion)
if (mPresShell) {
#ifdef MOZ_DUMP_PAINTING
if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
printf("--COMPOSITE-- %p\n", mPresShell);
printf_stderr("--COMPOSITE-- %p\n", mPresShell);
}
#endif
uint32_t paintFlags = nsIPresShell::PAINT_COMPOSITE;
@ -350,7 +350,7 @@ void nsViewManager::Refresh(nsView *aView, const nsIntRegion& aRegion)
}
#ifdef MOZ_DUMP_PAINTING
if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
printf("--ENDCOMPOSITE--\n");
printf_stderr("--ENDCOMPOSITE--\n");
}
#endif
mozilla::StartupTimeline::RecordOnce(mozilla::StartupTimeline::FIRST_PAINT);
@ -411,7 +411,7 @@ void nsViewManager::ProcessPendingUpdatesForView(nsView* aView,
#ifdef MOZ_DUMP_PAINTING
if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
printf("---- PAINT START ----PresShell(%p), nsView(%p), nsIWidget(%p)\n", mPresShell, aView, widget);
printf_stderr("---- PAINT START ----PresShell(%p), nsView(%p), nsIWidget(%p)\n", mPresShell, aView, widget);
}
#endif
nsAutoScriptBlocker scriptBlocker;
@ -421,7 +421,7 @@ void nsViewManager::ProcessPendingUpdatesForView(nsView* aView,
nsIPresShell::PAINT_LAYERS);
#ifdef MOZ_DUMP_PAINTING
if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
printf("---- PAINT END ----\n");
printf_stderr("---- PAINT END ----\n");
}
#endif

View File

@ -3337,16 +3337,7 @@ nsWindow::GetLayerManager(PLayerTransactionChild* aShadowManager,
// Fall back to software if we couldn't use any hardware backends.
if (!mLayerManager) {
// Try to use an async compositor first, if possible
if (ShouldUseOffMainThreadCompositing()) {
// e10s uses the parameter to pass in the shadow manager from the TabChild
// so we don't expect to see it there since this doesn't support e10s.
NS_ASSERTION(aShadowManager == nullptr, "Async Compositor not supported with e10s");
CreateCompositor();
}
if (!mLayerManager)
mLayerManager = CreateBasicLayerManager();
mLayerManager = CreateBasicLayerManager();
}
}

View File

@ -268,16 +268,19 @@ void NS_MakeRandomString(char *aBuf, int32_t aBufLen)
#endif
#if defined(XP_WIN)
#define va_copy(dest, src) (dest = src)
void
printf_stderr(const char *fmt, ...)
vprintf_stderr(const char *fmt, va_list args)
{
if (IsDebuggerPresent()) {
char buf[2048];
va_list args;
va_start(args, fmt);
vsnprintf(buf, sizeof(buf), fmt, args);
va_list argsCpy;
va_copy(argsCpy, args);
vsnprintf(buf, sizeof(buf), fmt, argsCpy);
buf[sizeof(buf) - 1] = '\0';
va_end(args);
va_end(argsCpy);
OutputDebugStringA(buf);
}
@ -285,29 +288,47 @@ printf_stderr(const char *fmt, ...)
if (!fp)
return;
va_list args;
va_start(args, fmt);
vfprintf(fp, fmt, args);
va_end(args);
fclose(fp);
}
#undef va_copy
#elif defined(ANDROID)
void
printf_stderr(const char *fmt, ...)
vprintf_stderr(const char *fmt, va_list args)
{
va_list args;
va_start(args, fmt);
__android_log_vprint(ANDROID_LOG_INFO, "Gecko", fmt, args);
va_end(args);
}
#else
void
vprintf_stderr(const char *fmt, va_list args)
{
vfprintf(stderr, fmt, args);
}
#endif
void
printf_stderr(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vfprintf(stderr, fmt, args);
vprintf_stderr(fmt, args);
va_end(args);
}
#endif
void
fprintf_stderr(FILE* aFile, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
if (aFile == stderr) {
vprintf_stderr(fmt, args);
} else {
vfprintf(aFile, fmt, args);
}
va_end(args);
}

View File

@ -398,6 +398,13 @@ extern "C" {
NS_COM_GLUE void
printf_stderr(const char *fmt, ...);
NS_COM_GLUE void
vprintf_stderr(const char *fmt, va_list args);
// fprintf with special handling for stderr to print to the console
NS_COM_GLUE void
fprintf_stderr(FILE* aFile, const char *fmt, ...);
#ifdef __cplusplus
}
#endif