Merge last PGO-green changeset of mozilla-inbound to mozilla-central

This commit is contained in:
Ed Morley 2012-01-31 10:52:29 +00:00
commit 08314b3ec8
117 changed files with 2970 additions and 993 deletions

View File

@ -593,30 +593,13 @@ nsAccessible::VisibilityState()
{
PRUint64 vstates = states::INVISIBLE | states::OFFSCREEN;
// We need to check the parent chain for visibility.
nsAccessible* accessible = this;
do {
// We don't want background tab page content to be aggressively invisible.
// Otherwise this foils screen reader virtual buffer caches.
roles::Role role = accessible->Role();
if (role == roles::PROPERTYPAGE || role == roles::PANE)
break;
nsIFrame* frame = accessible->GetFrame();
if (!frame)
return vstates;
const nsIView* view = frame->GetView();
if (view && view->GetVisibility() == nsViewVisibility_kHide)
return vstates;
} while (accessible = accessible->Parent());
nsIFrame* frame = GetFrame();
if (!frame)
return vstates;
const nsCOMPtr<nsIPresShell> shell(GetPresShell());
if (!shell)
return vstates;
// We need to know if at least a kMinPixels around the object is visible,
// otherwise it will be marked states::OFFSCREEN.
@ -644,6 +627,10 @@ nsAccessible::VisibilityState()
}
// XXX Do we really need to cross from content to chrome ancestor?
if (!frame->IsVisibleConsideringAncestors(nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY))
return vstates;
// Assume we are visible enough.
return vstates &= ~states::INVISIBLE;
}

View File

@ -47,6 +47,7 @@ MOZ_OFFICIAL_BRANDING_DIRECTORY=b2g/branding/official
MOZ_SAFE_BROWSING=
MOZ_SERVICES_SYNC=
MOZ_WEBSMS_BACKEND=1
MOZ_DISABLE_DOMCRYPTO=1
MOZ_APP_STATIC_INI=1

View File

@ -60,6 +60,12 @@ public interface Actions {
* @param geckoEvent The geckoEvent JSONObject's type
*/
EventExpecter expectGeckoEvent(String geckoEvent);
/**
* Listens for a paint event.
*/
EventExpecter expectPaint();
// Send the string kewsToSend to the application
void sendKeys(String keysToSend);
//Send any of the above keys to the element

View File

@ -52,4 +52,7 @@ public interface Assert {
void todo_is(Object a, Object b, String name);
void todo_isnot(Object a, Object b, String name);
void info(String name, String message);
// robocop-specific asserts
void ispixel(int actual, int r, int g, int b, String name);
}

View File

@ -68,4 +68,11 @@ public interface Driver {
void startFrameRecording();
int stopFrameRecording();
/**
* Get a copy of the painted content region.
* @return A 2-D array of pixels (indexed by y, then x). The pixels
* are in ARGB-8888 format.
*/
int[][] getPaintedSurface();
}

View File

@ -73,20 +73,24 @@ public class FennecNativeActions implements Actions {
// Map of IDs to element names.
private Solo solo;
private Instrumentation instr;
private Activity geckoApp;
// Objects for reflexive access of fennec classes.
private ClassLoader classLoader;
private Class gel;
private Class ge;
private Class gas;
private Class drawListener;
private Method registerGEL;
private Method unregisterGEL;
private Method sendGE;
private Method getLayerClient;
private Method setDrawListener;
public FennecNativeActions(Activity activity, Solo robocop, Instrumentation instrumentation){
this.solo = robocop;
this.instr = instrumentation;
this.geckoApp = activity;
// Set up reflexive access of java classes and methods.
try {
classLoader = activity.getClassLoader();
@ -101,6 +105,11 @@ public class FennecNativeActions implements Actions {
parameters = new Class[1];
parameters[0] = ge;
sendGE = gas.getMethod("sendEventToGecko", parameters);
getLayerClient = activity.getClass().getMethod("getSoftwareLayerClient");
Class gslc = classLoader.loadClass("org.mozilla.gecko.gfx.GeckoSoftwareLayerClient");
drawListener = classLoader.loadClass("org.mozilla.gecko.gfx.GeckoSoftwareLayerClient$DrawListener");
setDrawListener = gslc.getDeclaredMethod("setDrawListener", drawListener);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SecurityException e) {
@ -205,6 +214,75 @@ public class FennecNativeActions implements Actions {
return null;
}
class DrawListenerProxy implements InvocationHandler {
private final PaintExpecter mPaintExpecter;
DrawListenerProxy(PaintExpecter paintExpecter) {
mPaintExpecter = paintExpecter;
}
public Object invoke(Object proxy, Method method, Object[] args) {
String methodName = method.getName();
if ("drawFinished".equals(methodName)) {
Log.i("Robocop", "Received drawFinished notification");
mPaintExpecter.notifyOfEvent();
} else if ("toString".equals(methodName)) {
return "DrawListenerProxy";
} else if ("equals".equals(methodName)) {
return false;
} else if ("hashCode".equals(methodName)) {
return 0;
}
return null;
}
}
class PaintExpecter implements EventExpecter {
private Object mLayerClient;
private boolean mPaintDone;
PaintExpecter() throws IllegalAccessException, InvocationTargetException {
mLayerClient = getLayerClient.invoke(geckoApp);
setDrawListener.invoke(mLayerClient, Proxy.newProxyInstance(classLoader, new Class[] { drawListener }, new DrawListenerProxy(this)));
}
void notifyOfEvent() {
try {
setDrawListener.invoke(mLayerClient, (Object)null);
} catch (Exception e) {
e.printStackTrace();
}
synchronized (this) {
mPaintDone = true;
this.notifyAll();
}
}
public synchronized void blockForEvent() {
while (! mPaintDone) {
try {
this.wait();
} catch (InterruptedException ie) {
ie.printStackTrace();
break;
}
}
}
public synchronized boolean eventReceived() {
return mPaintDone;
}
}
public EventExpecter expectPaint() {
try {
return new PaintExpecter();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public void sendSpecialKey(SpecialKey button) {
switch( button) {
case DOWN:

View File

@ -243,6 +243,23 @@ public class FennecNativeAssert implements Assert {
ok(pass, name, diag);
}
public void ispixel(int actual, int r, int g, int b, String name) {
// When we read GL pixels the GPU has already processed them and they
// are usually off by a little bit. For example a CSS-color pixel of color #64FFF5
// was turned into #63FFF7 when it came out of glReadPixels. So in order to compare
// against the expected value, we use a little fuzz factor. For the alpha we just
// make sure it is always 0xFF.
int aAlpha = ((actual >> 24) & 0xFF);
int aR = ((actual >> 16) & 0xFF);
int aG = ((actual >> 8) & 0xFF);
int aB = (actual & 0xFF);
boolean pass = (aAlpha == 0xFF) /* alpha */
&& (Math.abs(aR - r) < 8) /* red */
&& (Math.abs(aG - g) < 8) /* green */
&& (Math.abs(aB - b) < 8); /* blue */
ok(pass, name, "Color rgba(" + aR + "," + aG + "," + aB + "," + aAlpha + ")" + (pass ? " " : " not") + " close enough to expected rgb(" + r + "," + g + "," + b + ")");
}
public void todo(boolean condition, String name, String diag) {
testInfo test = new testInfo(condition, name, diag, true);
_logMochitestResult(test, "TEST-UNEXPECTED-PASS", "TEST-KNOWN-FAIL");

View File

@ -45,6 +45,7 @@ import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.HashMap;
@ -58,6 +59,7 @@ import java.lang.reflect.InvocationHandler;
import java.lang.Long;
import android.app.Activity;
import android.opengl.GLSurfaceView;
import android.util.Log;
import android.view.View;
@ -81,6 +83,7 @@ public class FennecNativeDriver implements Driver {
private Method sendGE;
private Method _startFrameRecording;
private Method _stopFrameRecording;
private Method _getPixels;
public FennecNativeDriver(Activity activity, Solo robocop){
this.activity = activity;
@ -107,6 +110,9 @@ public class FennecNativeDriver implements Driver {
Class gfx = classLoader.loadClass("org.mozilla.gecko.gfx.PanningPerfAPI");
_startFrameRecording = gfx.getDeclaredMethod("startFrameTimeRecording");
_stopFrameRecording = gfx.getDeclaredMethod("stopFrameTimeRecording");
Class layerView = classLoader.loadClass("org.mozilla.gecko.gfx.LayerView");
_getPixels = layerView.getDeclaredMethod("getPixels");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SecurityException e) {
@ -212,6 +218,43 @@ public class FennecNativeDriver implements Driver {
return 0;
}
private GLSurfaceView getSurfaceView() {
for (View v : solo.getCurrentViews()) {
if (v instanceof GLSurfaceView) {
return (GLSurfaceView)v;
}
}
return null;
}
public int[][] getPaintedSurface() {
GLSurfaceView view = getSurfaceView();
if (view == null) {
return null;
}
IntBuffer pixelBuffer;
try {
pixelBuffer = (IntBuffer)_getPixels.invoke(view);
} catch (Exception e) {
e.printStackTrace();
return null;
}
// now we need to (1) flip the image, because GL likes to do things up-side-down,
// and (2) rearrange the bits from AGBR-8888 to ARGB-8888.
int w = view.getWidth();
int h = view.getHeight();
pixelBuffer.position(0);
int[][] pixels = new int[h][w];
for (int y = h - 1; y >= 0; y--) {
for (int x = 0; x < w; x++) {
int agbr = pixelBuffer.get();
pixels[y][x] = (agbr & 0xFF00FF00) | ((agbr >> 16) & 0x000000FF) | ((agbr << 16) & 0x00FF0000);
}
}
return pixels;
}
class scrollHandler implements InvocationHandler {
public scrollHandler(){};
public Object invoke(Object proxy, Method method, Object[] args) {

View File

@ -68,6 +68,7 @@ _TEST_FILES = \
$(TESTPATH)/robocop_blank_01.html \
$(TESTPATH)/robocop_blank_02.html \
$(TESTPATH)/robocop_blank_03.html \
$(TESTPATH)/robocop_boxes.html \
$(NULL)
_ROBOCOP_TOOLS = \

View File

@ -70,6 +70,6 @@ JAVAC_FLAGS = \
-classpath $(JAVA_CLASSPATH) \
-bootclasspath $(JAVA_BOOTCLASSPATH) \
-encoding UTF8 \
-g \
-g:source,lines \
-Werror \
$(NULL)

View File

@ -4906,12 +4906,14 @@ cairo-android)
cairo-gonk)
AC_DEFINE(MOZ_WIDGET_GONK)
AC_DEFINE(MOZ_TOUCH)
MOZ_WIDGET_TOOLKIT=gonk
TK_CFLAGS='$(MOZ_CAIRO_CFLAGS)'
TK_LIBS='$(MOZ_CAIRO_LIBS)'
MOZ_WEBGL=1
MOZ_PDF_PRINTING=1
MOZ_B2G_RIL=1
MOZ_TOUCH=1
;;
esac

View File

@ -178,6 +178,48 @@ enum EventNameType {
EventNameType_All = 0xFFFF
};
/**
* Information retrieved from the <meta name="viewport"> tag. See
* GetViewportInfo for more information on this functionality.
*/
struct ViewportInfo
{
// Default zoom indicates the level at which the display is 'zoomed in'
// initially for the user, upon loading of the page.
double defaultZoom;
// The minimum zoom level permitted by the page.
double minZoom;
// The maximum zoom level permitted by the page.
double maxZoom;
// The width of the viewport, specified by the <meta name="viewport"> tag,
// in CSS pixels.
PRUint32 width;
// The height of the viewport, specified by the <meta name="viewport"> tag,
// in CSS pixels.
PRUint32 height;
// Whether or not we should automatically size the viewport to the device's
// width. This is true if the document has been optimized for mobile, and
// the width property of a specified <meta name="viewport"> tag is either
// not specified, or is set to the special value 'device-width'.
bool autoSize;
// Whether or not the user can zoom in and out on the page. Default is true.
bool allowZoom;
// This is a holdover from e10s fennec, and might be removed in the future.
// It's a hack to work around bugs that didn't allow zooming of documents
// from within the parent process. It is still used in native Fennec for XUL
// documents, but it should probably be removed.
// Currently, from, within GetViewportInfo(), This is only set to false
// if the document is a XUL document.
bool autoScale;
};
struct EventNameMapping
{
nsIAtom* mAtom;
@ -1489,6 +1531,18 @@ public:
return sScriptBlockerCount == 0;
}
/**
* Retrieve information about the viewport as a data structure.
* This will return information in the viewport META data section
* of the document. This can be used in lieu of ProcessViewportInfo(),
* which places the viewport information in the document header instead
* of returning it directly.
*
* NOTE: If the site is optimized for mobile (via the doctype), this
* will return viewport information that specifies default information.
*/
static ViewportInfo GetViewportInfo(nsIDocument* aDocument);
/* Process viewport META data. This gives us information for the scale
* and zoom of a page on mobile devices. We stick the information in
* the document header and use it later on after rendering.

View File

@ -211,6 +211,8 @@ static NS_DEFINE_CID(kXTFServiceCID, NS_XTFSERVICE_CID);
#include "mozilla/Preferences.h"
#include "nsWrapperCacheInlines.h"
#include "nsIDOMDocumentType.h"
#include "nsIDOMWindowUtils.h"
#include "nsCharSeparatedTokenizer.h"
#include "nsUnicharUtils.h"
@ -221,6 +223,17 @@ using namespace mozilla;
const char kLoadAsData[] = "loadAsData";
/**
* Default values for the ViewportInfo structure.
*/
static const float kViewportMinScale = 0.0;
static const float kViewportMaxScale = 10.0;
static const PRUint32 kViewportMinWidth = 200;
static const PRUint32 kViewportMaxWidth = 10000;
static const PRUint32 kViewportMinHeight = 223;
static const PRUint32 kViewportMaxHeight = 10000;
static const PRInt32 kViewportDefaultScreenWidth = 980;
static const char kJSStackContractID[] = "@mozilla.org/js/xpc/ContextStack;1";
static NS_DEFINE_CID(kParserServiceCID, NS_PARSERSERVICE_CID);
static NS_DEFINE_CID(kCParserCID, NS_PARSER_CID);
@ -4556,6 +4569,198 @@ static void ProcessViewportToken(nsIDocument *aDocument,
#define IS_SEPARATOR(c) ((c == '=') || (c == ',') || (c == ';') || \
(c == '\t') || (c == '\n') || (c == '\r'))
/* static */
ViewportInfo
nsContentUtils::GetViewportInfo(nsIDocument *aDocument)
{
ViewportInfo ret;
ret.defaultZoom = 1.0;
ret.autoSize = true;
ret.allowZoom = true;
ret.autoScale = true;
// If the docType specifies that we are on a site optimized for mobile,
// then we want to return specially crafted defaults for the viewport info.
nsCOMPtr<nsIDOMDocument>
domDoc(do_QueryInterface(aDocument));
nsCOMPtr<nsIDOMDocumentType> docType;
nsresult rv = domDoc->GetDoctype(getter_AddRefs(docType));
if (NS_SUCCEEDED(rv) && docType) {
nsAutoString docId;
rv = docType->GetPublicId(docId);
if (NS_SUCCEEDED(rv)) {
if ((docId.Find("WAP") != -1) ||
(docId.Find("Mobile") != -1) ||
(docId.Find("WML") != -1))
{
return ret;
}
}
}
if (aDocument->IsXUL()) {
ret.autoScale = false;
return ret;
}
nsIDOMWindow* window = aDocument->GetWindow();
nsCOMPtr<nsIDOMWindowUtils> windowUtils(do_GetInterface(window));
if (!windowUtils) {
return ret;
}
nsAutoString handheldFriendly;
aDocument->GetHeaderData(nsGkAtoms::handheldFriendly, handheldFriendly);
if (handheldFriendly.EqualsLiteral("true")) {
return ret;
}
PRInt32 errorCode;
nsAutoString minScaleStr;
aDocument->GetHeaderData(nsGkAtoms::minimum_scale, minScaleStr);
float scaleMinFloat = minScaleStr.ToFloat(&errorCode);
if (errorCode) {
scaleMinFloat = kViewportMinScale;
}
scaleMinFloat = NS_MIN(scaleMinFloat, kViewportMaxScale);
scaleMinFloat = NS_MAX(scaleMinFloat, kViewportMinScale);
nsAutoString maxScaleStr;
aDocument->GetHeaderData(nsGkAtoms::maximum_scale, maxScaleStr);
// We define a special error code variable for the scale and max scale,
// because they are used later (see the width calculations).
PRInt32 scaleMaxErrorCode;
float scaleMaxFloat = maxScaleStr.ToFloat(&scaleMaxErrorCode);
if (scaleMaxErrorCode) {
scaleMaxFloat = kViewportMaxScale;
}
scaleMaxFloat = NS_MIN(scaleMaxFloat, kViewportMaxScale);
scaleMaxFloat = NS_MAX(scaleMaxFloat, kViewportMinScale);
nsAutoString scaleStr;
aDocument->GetHeaderData(nsGkAtoms::viewport_initial_scale, scaleStr);
PRInt32 scaleErrorCode;
float scaleFloat = scaleStr.ToFloat(&scaleErrorCode);
scaleFloat = NS_MIN(scaleFloat, scaleMaxFloat);
scaleFloat = NS_MAX(scaleFloat, scaleMinFloat);
nsAutoString widthStr, heightStr;
aDocument->GetHeaderData(nsGkAtoms::viewport_height, heightStr);
aDocument->GetHeaderData(nsGkAtoms::viewport_width, widthStr);
bool autoSize = false;
if (widthStr.EqualsLiteral("device-width")) {
autoSize = true;
}
if (widthStr.IsEmpty() &&
(heightStr.EqualsLiteral("device-height") ||
scaleFloat == 1.0))
{
autoSize = true;
}
// XXXjwir3:
// See bug 706918, comment 23 for more information on this particular section
// of the code. We're using "screen size" in place of the size of the content
// area, because on mobile, these are close or equal. This will work for our
// purposes (bug 706198), but it will need to be changed in the future to be
// more correct when we bring the rest of the viewport code into platform.
// We actually want the size of the content area, in the event that we don't
// have any metadata about the width and/or height. On mobile, the screen size
// and the size of the content area are very close, or the same value.
// In XUL fennec, the content area is the size of the <browser> widget, but
// in native fennec, the content area is the size of the Gecko LayerView
// object.
// TODO:
// Once bug 716575 has been resolved, this code should be changed so that it
// does the right thing on all platforms.
nsresult result;
PRInt32 screenLeft, screenTop, screenWidth, screenHeight;
nsCOMPtr<nsIScreenManager> screenMgr =
do_GetService("@mozilla.org/gfx/screenmanager;1", &result);
nsCOMPtr<nsIScreen> screen;
screenMgr->GetPrimaryScreen(getter_AddRefs(screen));
screen->GetRect(&screenLeft, &screenTop, &screenWidth, &screenHeight);
PRUint32 width = widthStr.ToInteger(&errorCode);
if (errorCode) {
if (autoSize) {
width = screenWidth;
} else {
width = Preferences::GetInt("browser.viewport.desktopWidth", 0);
}
}
width = NS_MIN(width, kViewportMaxWidth);
width = NS_MAX(width, kViewportMinWidth);
// Also recalculate the default zoom, if it wasn't specified in the metadata,
// and the width is specified.
if (scaleStr.IsEmpty() && !widthStr.IsEmpty()) {
scaleFloat = NS_MAX(scaleFloat, (float)(screenWidth/width));
}
PRUint32 height = heightStr.ToInteger(&errorCode);
if (errorCode) {
height = width * ((float)screenHeight / screenWidth);
}
// If height was provided by the user, but width wasn't, then we should
// calculate the width.
if (widthStr.IsEmpty() && !heightStr.IsEmpty()) {
width = (PRUint32) ((height * screenWidth) / screenHeight);
}
height = NS_MIN(height, kViewportMaxHeight);
height = NS_MAX(height, kViewportMinHeight);
// We need to perform a conversion, but only if the initial or maximum
// scale were set explicitly by the user.
if (!scaleStr.IsEmpty() && !scaleErrorCode) {
width = NS_MAX(width, (PRUint32)(screenWidth / scaleFloat));
height = NS_MAX(height, (PRUint32)(screenHeight / scaleFloat));
} else if (!maxScaleStr.IsEmpty() && !scaleMaxErrorCode) {
width = NS_MAX(width, (PRUint32)(screenWidth / scaleMaxFloat));
height = NS_MAX(height, (PRUint32)(screenHeight / scaleMaxFloat));
}
bool allowZoom = true;
nsAutoString userScalable;
aDocument->GetHeaderData(nsGkAtoms::viewport_user_scalable, userScalable);
if ((userScalable.EqualsLiteral("0")) ||
(userScalable.EqualsLiteral("no")) ||
(userScalable.EqualsLiteral("false"))) {
allowZoom = false;
}
ret.allowZoom = allowZoom;
ret.width = width;
ret.height = height;
ret.defaultZoom = scaleFloat;
ret.minZoom = scaleMinFloat;
ret.maxZoom = scaleMaxFloat;
ret.autoSize = autoSize;
return ret;
}
/* static */
nsresult
nsContentUtils::ProcessViewportInfo(nsIDocument *aDocument,

View File

@ -995,7 +995,7 @@ NS_NewCanvasRenderingContext2DAzure(nsIDOMCanvasRenderingContext2D** aResult)
!Preferences::GetBool("gfx.canvas.azure.prefer-skia", false)) {
return NS_ERROR_NOT_AVAILABLE;
}
#elif !defined(XP_MACOSX) && !defined(ANDROID) && !defined(XP_LINUX)
#elif !defined(XP_MACOSX) && !defined(ANDROID) && !defined(LINUX)
return NS_ERROR_NOT_AVAILABLE;
#endif

View File

@ -283,6 +283,9 @@ static bool gDragServiceDisabled = false;
static FILE *gDumpFile = nsnull;
static PRUint64 gNextWindowID = 0;
static PRUint32 gSerialCounter = 0;
static PRUint32 gTimeoutsRecentlySet = 0;
static TimeStamp gLastRecordedRecentTimeouts;
#define STATISTICS_INTERVAL (30 * PR_MSEC_PER_SEC)
#ifdef DEBUG_jst
PRInt32 gTimeoutCnt = 0;
@ -9054,6 +9057,7 @@ nsGlobalWindow::SetTimeoutOrInterval(nsIScriptTimeoutHandler *aHandler,
timeout->mPrincipal = ourPrincipal;
}
++gTimeoutsRecentlySet;
TimeDuration delta = TimeDuration::FromMilliseconds(realInterval);
if (!IsFrozen() && !mTimeoutsSuspendDepth) {
@ -9228,6 +9232,16 @@ nsGlobalWindow::RunTimeout(nsTimeout *aTimeout)
return;
}
// Record telemetry information about timers set recently.
TimeDuration recordingInterval = TimeDuration::FromMilliseconds(STATISTICS_INTERVAL);
if (gLastRecordedRecentTimeouts.IsNull() ||
now - gLastRecordedRecentTimeouts > recordingInterval) {
PRUint32 count = gTimeoutsRecentlySet;
gTimeoutsRecentlySet = 0;
Telemetry::Accumulate(Telemetry::DOM_TIMERS_RECENTLY_SET, count);
gLastRecordedRecentTimeouts = now;
}
// Insert a dummy timeout into the list of timeouts between the
// portion of the list that we are about to process now and those
// timeouts that will be processed in a future call to

View File

@ -483,15 +483,34 @@ var WifiManager = (function() {
}
}
function parseStatus(status) {
if (status === null) {
debug("Unable to get wpa supplicant's status");
return;
}
var lines = status.split("\n");
for (let i = 0; i < lines.length; ++i) {
let [key, value] = lines[i].split("=");
if (key === "wpa_state") {
if (value === "COMPLETED")
onconnected();
}
}
}
// try to connect to the supplicant
var connectTries = 0;
var retryTimer = null;
function connectCallback(ok) {
if (ok === 0) {
// tell the event worker to start waiting for events
// Tell the event worker to start waiting for events.
retryTimer = null;
waitForEvent();
notify("supplicantconnection");
// Load up the supplicant state.
statusCommand(parseStatus);
return;
}
if (connectTries++ < 3) {
@ -788,12 +807,9 @@ function nsWifiWorker() {
var networks = Object.create(null);
WifiManager.onscanresultsavailable = function() {
debug("Scan results are available! Asking for them.");
if (networks["Mozilla Guest"])
return;
WifiManager.getScanResults(function(r) {
let lines = r.split("\n");
// NB: Skip the header line.
let added = !("Mozilla Guest" in networks);
for (let i = 1; i < lines.length; ++i) {
// bssid / frequency / signal level / flags / ssid
var match = /([\S]+)\s+([\S]+)\s+([\S]+)\s+(\[[\S]+\])?\s+(.*)/.exec(lines[i])
@ -802,27 +818,6 @@ function nsWifiWorker() {
else
debug("Match didn't find anything for: " + lines[i]);
}
if (("Mozilla Guest" in networks) && added) {
debug("Mozilla Guest exists in networks, trying to connect!");
var config = Object.create(null);
config["ssid"] = '"Mozilla Guest"';
//config["bssid"] = '"' + networks["Mozilla Guest"] + '"';
config["key_mgmt"] = "NONE";
config["scan_ssid"] = 1;
WifiManager.addNetwork(config, function (ok) {
if (ok) {
WifiManager.enableNetwork(config.netId, false, function (ok) {
if (ok)
debug("Enabled the network!");
else
debug("Failed to enable the network :(");
});
} else {
debug("Failed to add the network :(");
}
});
}
});
}

View File

@ -232,16 +232,16 @@ public:
{
AssertIsOnMainThread();
JS::IterateData data(xpc::JsMallocSizeOf, xpc::GetCompartmentName,
xpc::DestroyCompartmentName);
nsresult rv = CollectForRuntime(/* isQuick = */false, &data);
JS::RuntimeStats rtStats(xpc::JsMallocSizeOf, xpc::GetCompartmentName,
xpc::DestroyCompartmentName);
nsresult rv = CollectForRuntime(/* isQuick = */false, &rtStats);
if (NS_FAILED(rv)) {
return rv;
}
// Always report, even if we're disabled, so that we at least get an entry
// in about::memory.
ReportJSRuntimeStats(data, mPathPrefix, aCallback, aClosure);
ReportJSRuntimeStats(rtStats, mPathPrefix, aCallback, aClosure);
return NS_OK;
}
@ -1524,7 +1524,7 @@ public:
*mSucceeded = mIsQuick
? JS::GetExplicitNonHeapForRuntime(JS_GetRuntime(aCx), static_cast<int64_t*>(mData), xpc::JsMallocSizeOf)
: JS::CollectCompartmentStatsForRuntime(JS_GetRuntime(aCx), static_cast<JS::IterateData*>(mData));
: JS::CollectRuntimeStats(JS_GetRuntime(aCx), static_cast<JS::RuntimeStats*>(mData));
{
MutexAutoLock lock(mMutex);

View File

@ -165,7 +165,8 @@ gssInit()
const char *const verLibNames[] = {
"libgssapi_krb5.so.2", /* MIT - FC, Suse10, Debian */
"libgssapi.so.4", /* Heimdal - Suse10, MDK */
"libgssapi.so.1" /* Heimdal - Suse9, CITI - FC, MDK, Suse10*/
"libgssapi.so.1", /* Heimdal - Suse9, CITI - FC, MDK, Suse10*/
"libgssapi.so" /* OpenBSD */
};
for (size_t i = 0; i < ArrayLength(verLibNames) && !lib; ++i) {

View File

@ -9143,423 +9143,425 @@
15629,15630d21435
< carburetter/SM
< carburettor/SM
15788d21592
15701a21507
> carnitas
15788d21593
< cashpoint/S
15797d21600
15797d21601
< cassino/M
15832a21636
15832a21637
> catalyses
15940d21743
15940d21744
< caviare/M
16372c22175
16372c22176
< chickenshit/S!
---
> chickenshit/SM!
16404c22207
16404c22208
< children
---
> children/M
16488d22290
16488d22291
< chlorophyl/M
16629,16630c22431
16629,16630c22432
< cider's
< cider/S
---
> cider/MS
17072d22872
17072d22873
< cocain/M
17102,17103c22902
17102,17103c22903
< cocksucker's
< cocksucker/S!
---
> cocksucker/SM!
17755c23554
17755c23555
< confer/S
---
> confer/SB
18151d23949
18151d23950
< convenor/S
18206c24004
18206c24005
< cookie/M
---
> cookie/SM
18467a24266
18467a24267
> could've
19246c25045
19246c25046
< cysteine
---
> cysteine/M
20196,20197c25995,25996
20196,20197c25996,25997
< dialog/SM
< dialogue/SM
---
> dialog/SMGD
> dialogue/SMRGD
20481a26281
20481a26282
> disclose/DSG
20830c26630
20830c26631
< dogie/M
---
> dogie/SM
20895a26696
20895a26697
> donator/MS
21820a27622
21820a27623
> elicitor/MS
22071a27874
22071a27875
> encyclopaedia
22556a28360
22556a28361
> estoppel
22638c28442
22638c28443
< euthanize
---
> euthanize/DSG
22719a28524
22719a28525
> exabyte/MS
22947a28753
22947a28754
> experimentalism
23207,23208d29012
23207,23208d29013
< faecal
< faeces/M
23215c29019
23215c29020
< faggoting's
---
> faggot/SMG
23701a29506
23701a29507
> filesystem/MS
24155c29960
24155c29961
< fluidized
---
> fluidize/DSG
24216a30022
24216a30023
> foci
24736d30541
24736d30542
< frier/M
24855,24856c30660,30661
24855,24856c30661,30662
< fucker/M!
< fuckhead/S!
---
> fucker/SM!
> fuckhead/SM!
24953d30757
24953d30758
< furore/MS
25125c30929
25125c30930
< gaolbird/S
---
> gaolbirds
25180d30983
25180d30984
< gasolene/M
25190a30994
25190a30995
> gastroenterologist/M
25262c31066
25262c31067
< geezer/M
---
> geezer/MS
25327c31131
25327c31132
< genomic
---
> genomic/S
25462a31267
25462a31268
> gigabit/MS
25464a31270,31272
25464a31271,31273
> gigajoule/MS
> gigapixel/MS
> gigawatt/MS
25560d31367
25560d31368
< glamourize/DSG
25674c31481
25674c31482
< glycerine's
---
> glycerine/M
25905c31712
25905c31713
< gram/MS
---
> gram/KMS
25909d31715
25909d31716
< gramme/SM
26063c31869,31870
26063c31870,31871
< greybeard
---
> grey/MDRTGSP
> greybeard/SM
26066c31873
26066c31874
< greyness
---
> greyness/M
26246,26247d32052
26246,26247d32053
< guerilla's
< guerillas
26432,26436d32236
26432,26436d32237
< haemoglobin's
< haemophilia/M
< haemorrhage/DSMG
< haemorrhoid/S
< haemorrhoids/M
27167c32967
27167c32968
< hexane
---
> hexane/SM
27273a33074
27273a33075
> hippopotami
27875d33675
27875d33676
< hyaena/SM
28017c33817
28017c33818
< iPod/M
---
> iPod/MS
28105a33906
28105a33907
> idolator/SM
28513c34314
28513c34315
< inbound
---
> inbound/s
28650a34452
28650a34453
> indices
28812d34613
28812d34614
< inflexion/SM
29216a35018
29216a35019
> intern/GDL
29272a35075,35078
29272a35076,35079
> intersex
> intersexual/MS
> intersexualism
> intersexuality
29724c35530
29724c35531
< jewellery's
---
> jewellery/M
29870a35677
29870a35678
> judgement/MS
30066c35873
30066c35874
< kiddie/M
---
> kiddie/SM
30262,30263c36069
30262,30263c36070
< kraut's
< kraut/S!
---
> kraut/MS!
30665a36472
30665a36473
> lector/MS
31031c36838
31031c36839
< linguini's
---
> linguini/M
31151,31152c36958
31151,31152c36959
< liver's
< liver/S
---
> liver/MS
32230c38036
32230c38037
< meanie/M
---
> meanie/MS
32317,32318c38123
32317,32318c38124
< megadeath/M
< megadeaths
---
> megadeath/SM
32320c38125
32320c38126
< megajoules
---
> megajoule/SM
32329c38134
32329c38135
< megapixel/S
---
> megapixel/MS
32708a38514
32708a38515
> might've
32777d38582
32777d38583
< millionnaire/M
32934a38740
32934a38741
> miscommunication/S
32991a38798
32991a38799
> misjudgement/MS
33784a39592
33784a39593
> must've
33963c39771
33963c39772
< native/MS
---
> native/MSY
34169,34171c39977,39978
34169,34171c39978,39979
< neurone/S
< neurophysiology
< neuroscience
---
> neurophysiology/M
> neuroscience/MS
34275c40082
34275c40083
< nightie/M
---
> nightie/SM
35104a40912
35104a40913
> octopi
35219d41026
35219d41027
< oleomargarin/M
35226a41034
35226a41035
> oligo
35913c41721
35913c41722
< oversize/D
---
> oversize
36056,36059d41863
36056,36059d41864
< paederast/S
< paediatrician's
< paediatricians
< paediatrics/M
36291a42096
36291a42097
> paralyses
36403d42207
36403d42208
< parrakeet/MS
36449d42252
36449d42253
< partizan/SM
37093a42897
37093a42898
> petabyte/MS
37102c42906
37102c42907
< petitioner/M
---
> petitioner/MS
37264a43069
37264a43070
> phosphorylate/DSGN
37316d43120
37316d43121
< phrenetic
37796a43601
37796a43602
> plugin/MS
37987c43792
37987c43793
< polypeptide/S
---
> polypeptide/MS
38291d44095
38291d44096
< practise's
38451a44256
38451a44257
> prejudgement/MS
38891a44697,44698
38891a44698,44699
> pronate/DSGN
> pronator/MS
38951c44758
38951c44759
< proprietorship/M
---
> proprietorship/MS
39039a44847
39039a44848
> provender/M
40036a45845
40036a45846
> recency
40141a45951
40141a45952
> recuse/DGS
40208a46019
40208a46020
> refactor/SMDG
40244d46054
40244d46055
< reflexion/SM
40829c46639
40829c46640
< reverie/M
---
> reverie/MS
41415a47226
41415a47227
> sabre/MS
41914c47725
41914c47726
< schnaps's
---
> schnaps/M
41949c47760
41949c47761
< schrod's
---
> schrod/SM
41998a42010
41998a47811
> scot-free
42883,42885c48695
42883,42885c48696
< shit's
< shit/S!
< shite/S!
---
> shit/MS!
42887,42888c48697,48698
42887,42888c48698,48699
< shithead/S!
< shitload/!
---
> shithead/MS!
> shitload/MS!
42891c48701
42891c48702
< shitty/RT!
---
> shitty/TR!
42976a48787
42976a48788
> should've
43008c48819
43008c48820
< showtime
---
> showtime/MS
43724,43726c49535
43724,43726c49536
< smoulder's
< smouldered
< smoulders
---
> smoulder/GSMD
44062c49871
44062c49872
< sonofabitch
---
> sonofabitch/!
44371a50181
44371a50182
> spick/S!
44383c50193
44383c50194
< spik/S
---
> spik/S!
46106a51917
46106a51918
> syllabi
46160c51971
46160c51972
< synch/GMD
---
> synch/GMDS
46167d51977
46167d51978
< synchs
46203,46204c52013,52014
46203,46204c52014,52015
< sysadmin/S
< sysop/S
---
> sysadmin/MS
> sysop/MS
46752a52563
46752a52564
> terabit/MS
46753a52565,52566
46753a52566,52567
> terahertz/M
> terapixel/MS
46817a52631
46817a52632
> testcase/MS
46831a52646
46831a52647
> testsuite/MS
46925a52741
46925a52742
> theremin/MS
47755a53572
47755a53573
> transfect/DSMG
47774a53592,53593
47774a53593,53594
> transgenderism
> transgene/MS
47951c53770
47951c53771
< triage/M
---
> triage/MG
48869a54689
48869a54690
> unlikeable
49211c55031
49211c55032
< vagina/M
---
> vagina/MS
49368,49369c55188
49368,49369c55189
< velour's
< velours's
---
> velour/MS
49478a55298
49478a55299
> vertices
50148a55969
50148a55970
> weaponize/DSG
50260,50261d56080
50260,50261d56081
< werwolf/M
< werwolves
50728c56547
50728c56548
< women
---
> women/M
50794c56613
50794c56614
< wop/S!
---
> wop/MS!

View File

@ -1,4 +1,4 @@
57435
57436
0/nm
0th/pt
1/n1
@ -21765,6 +21765,7 @@ carnality/M
carnation/IMS
carnelian/MS
carney/MS
carnitas
carnival/MS
carnivore/SM
carnivorous/YP

View File

@ -901,6 +901,14 @@ DrawTargetCG::Init(const IntSize &aSize, SurfaceFormat &)
// so flip it to the top left
CGContextTranslateCTM(mCg, 0, mSize.height);
CGContextScaleCTM(mCg, 1, -1);
// See Bug 722164 for performance details
// Medium or higher quality lead to expensive interpolation
// for canvas we want to use low quality interpolation
// to have competitive performance with other canvas
// implementation.
// XXX: Create input parameter to control interpolation and
// use the default for content.
CGContextSetInterpolationQuality(mCg, kCGInterpolationLow);
//XXX: set correct format
mFormat = FORMAT_B8G8R8A8;

View File

@ -1985,6 +1985,12 @@ DrawTargetD2D::CreatePartialBitmapForSurface(SourceSurfaceD2D *aSurface, Matrix
// surface.
uploadRect = uploadRect.Intersect(rect);
if (uploadRect.IsEmpty()) {
// This bitmap does not cover anything on the screen. XXX -
// we need to deal with EXTEND modes here!
return NULL;
}
if (uploadRect.width <= mRT->GetMaximumBitmapSize() &&
uploadRect.height <= mRT->GetMaximumBitmapSize()) {

View File

@ -97,7 +97,7 @@ Factory::CreateDrawTarget(BackendType aBackend, const IntSize &aSize, SurfaceFor
}
break;
}
#elif defined XP_MACOSX || defined ANDROID
#elif defined XP_MACOSX || defined ANDROID || defined LINUX
#ifdef USE_SKIA
case BACKEND_SKIA:
{

View File

@ -166,12 +166,37 @@ SourceSurfaceD2DTarget::GetBitmap(ID2D1RenderTarget *aRT)
AlphaMode(mFormat))),
byRef(mBitmap));
RefPtr<ID2D1RenderTarget> rt;
if (mDrawTarget) {
mBitmap->CopyFromRenderTarget(NULL, mDrawTarget->mRT, NULL);
return mBitmap;
rt = mDrawTarget->mRT;
}
gfxWarning() << "Failed to create shared bitmap for DrawTarget snapshot. Code: " << hr;
return NULL;
if (!rt) {
// Okay, we already separated from our drawtarget. And we're an A8
// surface the only way we can get to a bitmap is by creating a
// a rendertarget and from there copying to a bitmap! Terrible!
RefPtr<IDXGISurface> surface;
hr = mTexture->QueryInterface((IDXGISurface**)byRef(surface));
if (FAILED(hr)) {
gfxWarning() << "Failed to QI texture to surface.";
return NULL;
}
D2D1_RENDER_TARGET_PROPERTIES props =
D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_DEFAULT, D2D1::PixelFormat(DXGIFormat(mFormat), AlphaMode(mFormat)));
hr = DrawTargetD2D::factory()->CreateDxgiSurfaceRenderTarget(surface, props, byRef(rt));
if (FAILED(hr)) {
gfxWarning() << "Failed to create D2D render target for texture.";
return NULL;
}
}
mBitmap->CopyFromRenderTarget(NULL, rt, NULL);
return mBitmap;
}
return mBitmap;

View File

@ -178,6 +178,8 @@ unicode-printing.patch: Print as unicode (bug 454532)
quartz-mark-dirty.patch: Add a quartz implementation of mark_dirty_rectangle (bug 715704)
expose-snapshot.patch: Make functions to add snapshots public, as well as allow creating null surfaces publically. (bug 715658)
==== pixman patches ====
pixman-android-cpu-detect.patch: Add CPU detection support for Android, where we can't reliably access /proc/self/auxv.

View File

@ -70,9 +70,6 @@ cairo_private cairo_int_status_t
_cairo_analysis_surface_merge_status (cairo_int_status_t status_a,
cairo_int_status_t status_b);
cairo_private cairo_surface_t *
_cairo_null_surface_create (cairo_content_t content);
CAIRO_END_DECLS
#endif /* CAIRO_ANALYSIS_SURFACE_H */

View File

@ -907,7 +907,7 @@ static const cairo_surface_backend_t cairo_null_surface_backend = {
};
cairo_surface_t *
_cairo_null_surface_create (cairo_content_t content)
cairo_null_surface_create (cairo_content_t content)
{
cairo_surface_t *surface;

View File

@ -1956,14 +1956,14 @@ _cairo_d2d_create_brush_for_pattern(cairo_d2d_surface_t *d2dsurf,
srcSurf->data,
srcSurf->stride);
cairo_surface_t *nullSurf =
_cairo_null_surface_create(CAIRO_CONTENT_COLOR_ALPHA);
cairo_null_surface_create(CAIRO_CONTENT_COLOR_ALPHA);
cachebitmap->refs++;
cachebitmap->dirty = false;
cairo_surface_set_user_data(nullSurf,
&bitmap_key_snapshot,
cachebitmap,
NULL);
_cairo_surface_attach_snapshot(surfacePattern->surface,
cairo_surface_attach_snapshot(surfacePattern->surface,
nullSurf,
_d2d_snapshot_detached);
}
@ -2020,12 +2020,12 @@ _cairo_d2d_create_brush_for_pattern(cairo_d2d_surface_t *d2dsurf,
cachebitmap,
_d2d_release_bitmap);
cairo_surface_t *nullSurf =
_cairo_null_surface_create(CAIRO_CONTENT_COLOR_ALPHA);
cairo_null_surface_create(CAIRO_CONTENT_COLOR_ALPHA);
cairo_surface_set_user_data(nullSurf,
&bitmap_key_snapshot,
cachebitmap,
NULL);
_cairo_surface_attach_snapshot(surfacePattern->surface,
cairo_surface_attach_snapshot(surfacePattern->surface,
nullSurf,
_d2d_snapshot_detached);
cache_usage += _d2d_compute_bitmap_mem_size(sourceBitmap);

View File

@ -281,7 +281,7 @@ _cairo_recording_surface_acquire_source_image (void *abstract_surface,
return status;
}
_cairo_surface_attach_snapshot (&surface->base, image, NULL);
cairo_surface_attach_snapshot (&surface->base, image, NULL);
*image_out = (cairo_image_surface_t *) image;
*image_extra = NULL;
@ -1051,7 +1051,7 @@ _recording_surface_get_ink_bbox (cairo_recording_surface_t *surface,
cairo_surface_t *analysis_surface;
cairo_status_t status;
null_surface = _cairo_null_surface_create (surface->content);
null_surface = cairo_null_surface_create (surface->content);
analysis_surface = _cairo_analysis_surface_create (null_surface);
cairo_surface_destroy (null_surface);

View File

@ -45,8 +45,6 @@
#include "cairo-reference-count-private.h"
#include "cairo-clip-private.h"
typedef void (*cairo_surface_func_t) (cairo_surface_t *);
struct _cairo_surface {
const cairo_surface_backend_t *backend;
cairo_device_t *device;

View File

@ -214,7 +214,7 @@ _cairo_surface_snapshot (cairo_surface_t *surface)
snap->device_transform = surface->device_transform;
snap->device_transform_inverse = surface->device_transform_inverse;
_cairo_surface_attach_snapshot (surface, snap, NULL);
cairo_surface_attach_snapshot (surface, snap, NULL);
return snap;
}
@ -247,7 +247,7 @@ _cairo_surface_snapshot (cairo_surface_t *surface)
snapshot->base.device_transform = surface->device_transform;
snapshot->base.device_transform_inverse = surface->device_transform_inverse;
_cairo_surface_attach_snapshot (surface,
cairo_surface_attach_snapshot (surface,
&snapshot->base,
_cairo_surface_snapshot_copy_on_write);

View File

@ -331,7 +331,7 @@ _cairo_surface_subsurface_acquire_source_image (void *abstrac
cairo_surface_paint_to_target (&image->base, surface);
_cairo_surface_attach_snapshot (&surface->base, &image->base, NULL);
cairo_surface_attach_snapshot (&surface->base, &image->base, NULL);
*image_out = image;
*extra_out = NULL;

View File

@ -310,17 +310,17 @@ _cairo_surface_detach_mime_data (cairo_surface_t *surface)
}
static void
_cairo_surface_detach_snapshots (cairo_surface_t *surface)
cairo_surface_detach_snapshots (cairo_surface_t *surface)
{
while (_cairo_surface_has_snapshots (surface)) {
_cairo_surface_detach_snapshot (cairo_list_first_entry (&surface->snapshots,
cairo_surface_detach_snapshot (cairo_list_first_entry (&surface->snapshots,
cairo_surface_t,
snapshot));
}
}
void
_cairo_surface_detach_snapshot (cairo_surface_t *snapshot)
cairo_surface_detach_snapshot (cairo_surface_t *snapshot)
{
assert (snapshot->snapshot_of != NULL);
@ -334,7 +334,7 @@ _cairo_surface_detach_snapshot (cairo_surface_t *snapshot)
}
void
_cairo_surface_attach_snapshot (cairo_surface_t *surface,
cairo_surface_attach_snapshot (cairo_surface_t *surface,
cairo_surface_t *snapshot,
cairo_surface_func_t detach_func)
{
@ -344,7 +344,7 @@ _cairo_surface_attach_snapshot (cairo_surface_t *surface,
cairo_surface_reference (snapshot);
if (snapshot->snapshot_of != NULL)
_cairo_surface_detach_snapshot (snapshot);
cairo_surface_detach_snapshot (snapshot);
snapshot->snapshot_of = surface;
snapshot->snapshot_detach = detach_func;
@ -387,7 +387,7 @@ _cairo_surface_begin_modification (cairo_surface_t *surface)
assert (! surface->finished);
assert (surface->snapshot_of == NULL);
_cairo_surface_detach_snapshots (surface);
cairo_surface_detach_snapshots (surface);
_cairo_surface_detach_mime_data (surface);
}
@ -716,9 +716,9 @@ cairo_surface_finish (cairo_surface_t *surface)
return;
/* update the snapshots *before* we declare the surface as finished */
_cairo_surface_detach_snapshots (surface);
cairo_surface_detach_snapshots (surface);
if (surface->snapshot_of != NULL)
_cairo_surface_detach_snapshot (surface);
cairo_surface_detach_snapshot (surface);
cairo_surface_flush (surface);
surface->finished = TRUE;
@ -1111,7 +1111,7 @@ cairo_surface_flush (cairo_surface_t *surface)
return;
/* update the current snapshots *before* the user updates the surface */
_cairo_surface_detach_snapshots (surface);
cairo_surface_detach_snapshots (surface);
if (surface->backend->flush) {
status = surface->backend->flush (surface);
@ -1633,7 +1633,7 @@ _cairo_recording_surface_clone_similar (cairo_surface_t *surface,
return status;
}
_cairo_surface_attach_snapshot (src, similar, NULL);
cairo_surface_attach_snapshot (src, similar, NULL);
src_x = src_y = 0;
}

View File

@ -982,7 +982,7 @@ _vg_setup_surface_source (cairo_vg_context_t *context,
return status;
}
_cairo_surface_attach_snapshot (spat->surface, &clone->base,
cairo_surface_attach_snapshot (spat->surface, &clone->base,
_vg_surface_remove_from_cache);
DONE:

View File

@ -565,7 +565,7 @@ _cairo_xcb_surface_acquire_source_image (void *abstract_surface,
if (unlikely (status))
return status;
_cairo_surface_attach_snapshot (&surface->base, &image->base, NULL);
cairo_surface_attach_snapshot (&surface->base, &image->base, NULL);
DONE:
*image_out = image;
@ -718,7 +718,7 @@ _cairo_xcb_surface_flush (void *abstract_surface)
}
if (status == CAIRO_STATUS_SUCCESS) {
_cairo_surface_attach_snapshot (&surface->base,
cairo_surface_attach_snapshot (&surface->base,
surface->fallback,
cairo_surface_finish);
}

View File

@ -218,6 +218,15 @@ typedef struct _cairo_pattern cairo_pattern_t;
**/
typedef void (*cairo_destroy_func_t) (void *data);
/**
* cairo_surface_func_t:
* @surface: The surface being referred to.
*
* #cairo_surface_func_t the type of function which is used for callback
* when a surface needs to be apssed as a parameter.
*/
typedef void (*cairo_surface_func_t) (cairo_surface_t *surface);
/**
* cairo_user_data_key_t:
* @unused: not used; ignore.
@ -2155,6 +2164,14 @@ cairo_surface_set_user_data (cairo_surface_t *surface,
void *user_data,
cairo_destroy_func_t destroy);
cairo_public void
cairo_surface_attach_snapshot (cairo_surface_t *surface,
cairo_surface_t *snapshot,
cairo_surface_func_t detach_func);
cairo_public void
cairo_surface_detach_snapshot (cairo_surface_t *snapshot);
#define CAIRO_MIME_TYPE_JPEG "image/jpeg"
#define CAIRO_MIME_TYPE_PNG "image/png"
#define CAIRO_MIME_TYPE_JP2 "image/jp2"
@ -2333,6 +2350,11 @@ cairo_recording_surface_ink_extents (cairo_surface_t *surface,
double *width,
double *height);
/* Null-surface functions */
cairo_public cairo_surface_t *
cairo_null_surface_create (cairo_content_t content);
/* Pattern creation functions */
cairo_public cairo_pattern_t *

View File

@ -1775,17 +1775,9 @@ _cairo_surface_clone_similar (cairo_surface_t *surface,
cairo_private cairo_surface_t *
_cairo_surface_snapshot (cairo_surface_t *surface);
cairo_private void
_cairo_surface_attach_snapshot (cairo_surface_t *surface,
cairo_surface_t *snapshot,
cairo_surface_func_t detach_func);
cairo_private cairo_surface_t *
_cairo_surface_has_snapshot (cairo_surface_t *surface,
const cairo_surface_backend_t *backend);
cairo_private void
_cairo_surface_detach_snapshot (cairo_surface_t *snapshot);
const cairo_surface_backend_t *backend);
cairo_private cairo_bool_t
_cairo_surface_is_similar (cairo_surface_t *surface_a,

View File

@ -0,0 +1,528 @@
diff --git a/gfx/cairo/cairo/src/cairo-analysis-surface-private.h b/gfx/cairo/cairo/src/cairo-analysis-surface-private.h
--- a/gfx/cairo/cairo/src/cairo-analysis-surface-private.h
+++ b/gfx/cairo/cairo/src/cairo-analysis-surface-private.h
@@ -65,14 +65,11 @@ _cairo_analysis_surface_has_unsupported
cairo_private void
_cairo_analysis_surface_get_bounding_box (cairo_surface_t *surface,
cairo_box_t *bbox);
cairo_private cairo_int_status_t
_cairo_analysis_surface_merge_status (cairo_int_status_t status_a,
cairo_int_status_t status_b);
-cairo_private cairo_surface_t *
-_cairo_null_surface_create (cairo_content_t content);
-
CAIRO_END_DECLS
#endif /* CAIRO_ANALYSIS_SURFACE_H */
diff --git a/gfx/cairo/cairo/src/cairo-analysis-surface.c b/gfx/cairo/cairo/src/cairo-analysis-surface.c
--- a/gfx/cairo/cairo/src/cairo-analysis-surface.c
+++ b/gfx/cairo/cairo/src/cairo-analysis-surface.c
@@ -902,17 +902,17 @@ static const cairo_surface_backend_t cai
NULL, /* fill_stroke */
NULL, /* create_solid_pattern_surface */
NULL, /* can_repaint_solid_pattern_surface */
NULL, /* has_show_text_glyphs */
NULL /* show_text_glyphs */
};
cairo_surface_t *
-_cairo_null_surface_create (cairo_content_t content)
+cairo_null_surface_create (cairo_content_t content)
{
cairo_surface_t *surface;
surface = malloc (sizeof (cairo_surface_t));
if (unlikely (surface == NULL)) {
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
}
diff --git a/gfx/cairo/cairo/src/cairo-d2d-surface.cpp b/gfx/cairo/cairo/src/cairo-d2d-surface.cpp
--- a/gfx/cairo/cairo/src/cairo-d2d-surface.cpp
+++ b/gfx/cairo/cairo/src/cairo-d2d-surface.cpp
@@ -1951,24 +1951,24 @@ _cairo_d2d_create_brush_for_pattern(cair
rect = D2D1::RectU(1, 1, srcSurf->width + 1, srcSurf->height + 1);
} else {
rect = D2D1::RectU(0, 0, srcSurf->width, srcSurf->height);
}
sourceBitmap->CopyFromMemory(&rect,
srcSurf->data,
srcSurf->stride);
cairo_surface_t *nullSurf =
- _cairo_null_surface_create(CAIRO_CONTENT_COLOR_ALPHA);
+ cairo_null_surface_create(CAIRO_CONTENT_COLOR_ALPHA);
cachebitmap->refs++;
cachebitmap->dirty = false;
cairo_surface_set_user_data(nullSurf,
&bitmap_key_snapshot,
cachebitmap,
NULL);
- _cairo_surface_attach_snapshot(surfacePattern->surface,
+ cairo_surface_attach_snapshot(surfacePattern->surface,
nullSurf,
_d2d_snapshot_detached);
}
} else {
if (pattern->extend != CAIRO_EXTEND_NONE) {
d2dsurf->rt->CreateBitmap(D2D1::SizeU(width, height),
data + yoffset * stride + xoffset * Bpp,
stride,
@@ -2015,22 +2015,22 @@ _cairo_d2d_create_brush_for_pattern(cair
* and one more in the user data structure.
*/
cachebitmap->refs = 2;
cairo_surface_set_user_data(surfacePattern->surface,
key,
cachebitmap,
_d2d_release_bitmap);
cairo_surface_t *nullSurf =
- _cairo_null_surface_create(CAIRO_CONTENT_COLOR_ALPHA);
+ cairo_null_surface_create(CAIRO_CONTENT_COLOR_ALPHA);
cairo_surface_set_user_data(nullSurf,
&bitmap_key_snapshot,
cachebitmap,
NULL);
- _cairo_surface_attach_snapshot(surfacePattern->surface,
+ cairo_surface_attach_snapshot(surfacePattern->surface,
nullSurf,
_d2d_snapshot_detached);
cache_usage += _d2d_compute_bitmap_mem_size(sourceBitmap);
}
if (pix_image) {
pixman_image_unref(pix_image);
}
}
diff --git a/gfx/cairo/cairo/src/cairo-recording-surface.c b/gfx/cairo/cairo/src/cairo-recording-surface.c
--- a/gfx/cairo/cairo/src/cairo-recording-surface.c
+++ b/gfx/cairo/cairo/src/cairo-recording-surface.c
@@ -276,17 +276,17 @@ _cairo_recording_surface_acquire_source_
-surface->extents.y);
status = _cairo_recording_surface_replay (&surface->base, image);
if (unlikely (status)) {
cairo_surface_destroy (image);
return status;
}
- _cairo_surface_attach_snapshot (&surface->base, image, NULL);
+ cairo_surface_attach_snapshot (&surface->base, image, NULL);
*image_out = (cairo_image_surface_t *) image;
*image_extra = NULL;
return CAIRO_STATUS_SUCCESS;
}
static void
_cairo_recording_surface_release_source_image (void *abstract_surface,
@@ -1046,17 +1046,17 @@ static cairo_status_t
_recording_surface_get_ink_bbox (cairo_recording_surface_t *surface,
cairo_box_t *bbox,
const cairo_matrix_t *transform)
{
cairo_surface_t *null_surface;
cairo_surface_t *analysis_surface;
cairo_status_t status;
- null_surface = _cairo_null_surface_create (surface->content);
+ null_surface = cairo_null_surface_create (surface->content);
analysis_surface = _cairo_analysis_surface_create (null_surface);
cairo_surface_destroy (null_surface);
status = analysis_surface->status;
if (unlikely (status))
return status;
if (transform != NULL)
diff --git a/gfx/cairo/cairo/src/cairo-surface-private.h b/gfx/cairo/cairo/src/cairo-surface-private.h
--- a/gfx/cairo/cairo/src/cairo-surface-private.h
+++ b/gfx/cairo/cairo/src/cairo-surface-private.h
@@ -40,18 +40,16 @@
#include "cairo.h"
#include "cairo-types-private.h"
#include "cairo-list-private.h"
#include "cairo-reference-count-private.h"
#include "cairo-clip-private.h"
-typedef void (*cairo_surface_func_t) (cairo_surface_t *);
-
struct _cairo_surface {
const cairo_surface_backend_t *backend;
cairo_device_t *device;
/* We allow surfaces to override the backend->type by shoving something
* else into surface->type. This is for "wrapper" surfaces that want to
* hide their internal type from the user-level API. */
cairo_surface_type_t type;
diff --git a/gfx/cairo/cairo/src/cairo-surface-snapshot.c b/gfx/cairo/cairo/src/cairo-surface-snapshot.c
--- a/gfx/cairo/cairo/src/cairo-surface-snapshot.c
+++ b/gfx/cairo/cairo/src/cairo-surface-snapshot.c
@@ -209,17 +209,17 @@ _cairo_surface_snapshot (cairo_surface_t
if (unlikely (status)) {
cairo_surface_destroy (snap);
return _cairo_surface_create_in_error (status);
}
snap->device_transform = surface->device_transform;
snap->device_transform_inverse = surface->device_transform_inverse;
- _cairo_surface_attach_snapshot (surface, snap, NULL);
+ cairo_surface_attach_snapshot (surface, snap, NULL);
return snap;
}
}
snapshot = (cairo_surface_snapshot_t *)
_cairo_surface_has_snapshot (surface, &_cairo_surface_snapshot_backend);
if (snapshot != NULL)
@@ -242,14 +242,14 @@ _cairo_surface_snapshot (cairo_surface_t
if (unlikely (status)) {
cairo_surface_destroy (&snapshot->base);
return _cairo_surface_create_in_error (status);
}
snapshot->base.device_transform = surface->device_transform;
snapshot->base.device_transform_inverse = surface->device_transform_inverse;
- _cairo_surface_attach_snapshot (surface,
+ cairo_surface_attach_snapshot (surface,
&snapshot->base,
_cairo_surface_snapshot_copy_on_write);
return &snapshot->base;
}
diff --git a/gfx/cairo/cairo/src/cairo-surface-subsurface.c b/gfx/cairo/cairo/src/cairo-surface-subsurface.c
--- a/gfx/cairo/cairo/src/cairo-surface-subsurface.c
+++ b/gfx/cairo/cairo/src/cairo-surface-subsurface.c
@@ -326,17 +326,17 @@ _cairo_surface_subsurface_acquire_source
_cairo_image_surface_create_with_content (meta->content,
surface->extents.width,
surface->extents.height);
if (unlikely (image->base.status))
return image->base.status;
cairo_surface_paint_to_target (&image->base, surface);
- _cairo_surface_attach_snapshot (&surface->base, &image->base, NULL);
+ cairo_surface_attach_snapshot (&surface->base, &image->base, NULL);
*image_out = image;
*extra_out = NULL;
return CAIRO_STATUS_SUCCESS;
}
}
extra = malloc (sizeof (struct extra));
diff --git a/gfx/cairo/cairo/src/cairo-surface.c b/gfx/cairo/cairo/src/cairo-surface.c
--- a/gfx/cairo/cairo/src/cairo-surface.c
+++ b/gfx/cairo/cairo/src/cairo-surface.c
@@ -305,51 +305,51 @@ _cairo_surface_detach_mime_data (cairo_s
if (! _cairo_surface_has_mime_data (surface))
return;
_cairo_user_data_array_fini (&surface->mime_data);
_cairo_user_data_array_init (&surface->mime_data);
}
static void
-_cairo_surface_detach_snapshots (cairo_surface_t *surface)
+cairo_surface_detach_snapshots (cairo_surface_t *surface)
{
while (_cairo_surface_has_snapshots (surface)) {
- _cairo_surface_detach_snapshot (cairo_list_first_entry (&surface->snapshots,
+ cairo_surface_detach_snapshot (cairo_list_first_entry (&surface->snapshots,
cairo_surface_t,
snapshot));
}
}
void
-_cairo_surface_detach_snapshot (cairo_surface_t *snapshot)
+cairo_surface_detach_snapshot (cairo_surface_t *snapshot)
{
assert (snapshot->snapshot_of != NULL);
snapshot->snapshot_of = NULL;
cairo_list_del (&snapshot->snapshot);
if (snapshot->snapshot_detach != NULL)
snapshot->snapshot_detach (snapshot);
cairo_surface_destroy (snapshot);
}
void
-_cairo_surface_attach_snapshot (cairo_surface_t *surface,
+cairo_surface_attach_snapshot (cairo_surface_t *surface,
cairo_surface_t *snapshot,
cairo_surface_func_t detach_func)
{
assert (surface != snapshot);
assert (snapshot->snapshot_of != surface);
cairo_surface_reference (snapshot);
if (snapshot->snapshot_of != NULL)
- _cairo_surface_detach_snapshot (snapshot);
+ cairo_surface_detach_snapshot (snapshot);
snapshot->snapshot_of = surface;
snapshot->snapshot_detach = detach_func;
cairo_list_add (&snapshot->snapshot, &surface->snapshots);
assert (_cairo_surface_has_snapshot (surface, snapshot->backend) == snapshot);
}
@@ -382,17 +382,17 @@ _cairo_surface_is_writable (cairo_surfac
static void
_cairo_surface_begin_modification (cairo_surface_t *surface)
{
assert (surface->status == CAIRO_STATUS_SUCCESS);
assert (! surface->finished);
assert (surface->snapshot_of == NULL);
- _cairo_surface_detach_snapshots (surface);
+ cairo_surface_detach_snapshots (surface);
_cairo_surface_detach_mime_data (surface);
}
void
_cairo_surface_init (cairo_surface_t *surface,
const cairo_surface_backend_t *backend,
cairo_device_t *device,
cairo_content_t content)
@@ -711,19 +711,19 @@ cairo_surface_finish (cairo_surface_t *s
if (CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count))
return;
if (surface->finished)
return;
/* update the snapshots *before* we declare the surface as finished */
- _cairo_surface_detach_snapshots (surface);
+ cairo_surface_detach_snapshots (surface);
if (surface->snapshot_of != NULL)
- _cairo_surface_detach_snapshot (surface);
+ cairo_surface_detach_snapshot (surface);
cairo_surface_flush (surface);
surface->finished = TRUE;
/* call finish even if in error mode */
if (surface->backend->finish) {
status = surface->backend->finish (surface);
if (unlikely (status))
@@ -1106,17 +1106,17 @@ cairo_surface_flush (cairo_surface_t *su
if (surface->status)
return;
if (surface->finished)
return;
/* update the current snapshots *before* the user updates the surface */
- _cairo_surface_detach_snapshots (surface);
+ cairo_surface_detach_snapshots (surface);
if (surface->backend->flush) {
status = surface->backend->flush (surface);
if (unlikely (status))
status = _cairo_surface_set_error (surface, status);
}
}
slim_hidden_def (cairo_surface_flush);
@@ -1628,17 +1628,17 @@ _cairo_recording_surface_clone_similar (
return similar->status;
status = _cairo_recording_surface_replay (src, similar);
if (unlikely (status)) {
cairo_surface_destroy (similar);
return status;
}
- _cairo_surface_attach_snapshot (src, similar, NULL);
+ cairo_surface_attach_snapshot (src, similar, NULL);
src_x = src_y = 0;
}
*clone_out = similar;
*clone_offset_x = src_x;
*clone_offset_y = src_y;
return CAIRO_STATUS_SUCCESS;
diff --git a/gfx/cairo/cairo/src/cairo-vg-surface.c b/gfx/cairo/cairo/src/cairo-vg-surface.c
--- a/gfx/cairo/cairo/src/cairo-vg-surface.c
+++ b/gfx/cairo/cairo/src/cairo-vg-surface.c
@@ -977,17 +977,17 @@ _vg_setup_surface_source (cairo_vg_conte
status = _cairo_cache_insert (&context->snapshot_cache,
&clone->snapshot_cache_entry);
if (unlikely (status)) {
clone->snapshot_cache_entry.hash = 0;
cairo_surface_destroy (&clone->base);
return status;
}
- _cairo_surface_attach_snapshot (spat->surface, &clone->base,
+ cairo_surface_attach_snapshot (spat->surface, &clone->base,
_vg_surface_remove_from_cache);
DONE:
cairo_surface_destroy (&context->source->base);
context->source = clone;
vgSetParameteri (context->paint, VG_PAINT_TYPE, VG_PAINT_TYPE_PATTERN);
diff --git a/gfx/cairo/cairo/src/cairo-xcb-surface.c b/gfx/cairo/cairo/src/cairo-xcb-surface.c
--- a/gfx/cairo/cairo/src/cairo-xcb-surface.c
+++ b/gfx/cairo/cairo/src/cairo-xcb-surface.c
@@ -560,17 +560,17 @@ _cairo_xcb_surface_acquire_source_image
image = (cairo_image_surface_t *) cairo_surface_reference (&image->base);
goto DONE;
}
status = _get_image (surface, FALSE, &image);
if (unlikely (status))
return status;
- _cairo_surface_attach_snapshot (&surface->base, &image->base, NULL);
+ cairo_surface_attach_snapshot (&surface->base, &image->base, NULL);
DONE:
*image_out = image;
*image_extra = NULL;
return CAIRO_STATUS_SUCCESS;
}
static void
@@ -713,17 +713,17 @@ _cairo_xcb_surface_flush (void *abstract
status = cairo_surface_status (surface->fallback);
if (status == CAIRO_STATUS_SUCCESS) {
status = _put_image (surface,
(cairo_image_surface_t *) surface->fallback);
}
if (status == CAIRO_STATUS_SUCCESS) {
- _cairo_surface_attach_snapshot (&surface->base,
+ cairo_surface_attach_snapshot (&surface->base,
surface->fallback,
cairo_surface_finish);
}
}
cairo_surface_destroy (surface->fallback);
surface->fallback = NULL;
diff --git a/gfx/cairo/cairo/src/cairo.h b/gfx/cairo/cairo/src/cairo.h
--- a/gfx/cairo/cairo/src/cairo.h
+++ b/gfx/cairo/cairo/src/cairo.h
@@ -214,16 +214,25 @@ typedef struct _cairo_pattern cairo_patt
*
* #cairo_destroy_func_t the type of function which is called when a
* data element is destroyed. It is passed the pointer to the data
* element and should free any memory and resources allocated for it.
**/
typedef void (*cairo_destroy_func_t) (void *data);
/**
+ * cairo_surface_func_t:
+ * @surface: The surface being referred to.
+ *
+ * #cairo_surface_func_t the type of function which is used for callback
+ * when a surface needs to be apssed as a parameter.
+ */
+typedef void (*cairo_surface_func_t) (cairo_surface_t *surface);
+
+/**
* cairo_user_data_key_t:
* @unused: not used; ignore.
*
* #cairo_user_data_key_t is used for attaching user data to cairo
* data structures. The actual contents of the struct is never used,
* and there is no need to initialize the object; only the unique
* address of a #cairo_data_key_t object is used. Typically, you
* would just use the address of a static #cairo_data_key_t object.
@@ -2150,16 +2159,24 @@ cairo_surface_get_user_data (cairo_surfa
const cairo_user_data_key_t *key);
cairo_public cairo_status_t
cairo_surface_set_user_data (cairo_surface_t *surface,
const cairo_user_data_key_t *key,
void *user_data,
cairo_destroy_func_t destroy);
+cairo_public void
+cairo_surface_attach_snapshot (cairo_surface_t *surface,
+ cairo_surface_t *snapshot,
+ cairo_surface_func_t detach_func);
+
+cairo_public void
+cairo_surface_detach_snapshot (cairo_surface_t *snapshot);
+
#define CAIRO_MIME_TYPE_JPEG "image/jpeg"
#define CAIRO_MIME_TYPE_PNG "image/png"
#define CAIRO_MIME_TYPE_JP2 "image/jp2"
#define CAIRO_MIME_TYPE_URI "text/x-uri"
cairo_public void
cairo_surface_get_mime_data (cairo_surface_t *surface,
const char *mime_type,
@@ -2328,16 +2345,21 @@ cairo_recording_surface_create (cairo_co
cairo_public void
cairo_recording_surface_ink_extents (cairo_surface_t *surface,
double *x0,
double *y0,
double *width,
double *height);
+/* Null-surface functions */
+
+cairo_public cairo_surface_t *
+cairo_null_surface_create (cairo_content_t content);
+
/* Pattern creation functions */
cairo_public cairo_pattern_t *
cairo_pattern_create_rgb (double red, double green, double blue);
cairo_public cairo_pattern_t *
cairo_pattern_create_rgba (double red, double green, double blue,
double alpha);
diff --git a/gfx/cairo/cairo/src/cairoint.h b/gfx/cairo/cairo/src/cairoint.h
--- a/gfx/cairo/cairo/src/cairoint.h
+++ b/gfx/cairo/cairo/src/cairoint.h
@@ -1770,27 +1770,19 @@ _cairo_surface_clone_similar (cairo_surf
int height,
int *clone_offset_x,
int *clone_offset_y,
cairo_surface_t **clone_out);
cairo_private cairo_surface_t *
_cairo_surface_snapshot (cairo_surface_t *surface);
-cairo_private void
-_cairo_surface_attach_snapshot (cairo_surface_t *surface,
- cairo_surface_t *snapshot,
- cairo_surface_func_t detach_func);
-
cairo_private cairo_surface_t *
_cairo_surface_has_snapshot (cairo_surface_t *surface,
- const cairo_surface_backend_t *backend);
-
-cairo_private void
-_cairo_surface_detach_snapshot (cairo_surface_t *snapshot);
+ const cairo_surface_backend_t *backend);
cairo_private cairo_bool_t
_cairo_surface_is_similar (cairo_surface_t *surface_a,
cairo_surface_t *surface_b);
cairo_private cairo_bool_t
_cairo_surface_get_extents (cairo_surface_t *surface,
cairo_rectangle_int_t *extents);

View File

@ -309,7 +309,9 @@ endif
ifeq (android,$(MOZ_WIDGET_TOOLKIT))
CPPSRCS += \
SkFontHost_none.cpp \
SkFontHost_FreeType.cpp \
SkFontHost_android.cpp \
SkFontHost_gamma.cpp \
SkMMapStream.cpp \
SkTime_Unix.cpp \
$(NULL)
@ -321,8 +323,8 @@ endif
ifeq (gtk2,$(MOZ_WIDGET_TOOLKIT))
CPPSRCS += \
SkFontHost_FreeType.cpp \
SkFontHost_gamma_none.cpp \
SkFontHost_linux.cpp \
SkFontHost_gamma.cpp \
SkTime_Unix.cpp \
SkMMapStream.cpp \
SkOSFile.cpp \

View File

@ -0,0 +1,530 @@
# HG changeset patch
# Parent 9ee29e4aace683ddf6cf8ddb2893cd34fcfc772c
# User James Willcox <jwillcox@mozilla.com>
diff --git a/gfx/skia/Makefile.in b/gfx/skia/Makefile.in
--- a/gfx/skia/Makefile.in
+++ b/gfx/skia/Makefile.in
@@ -305,21 +305,20 @@ CPPSRCS += \
SkFontHost_mac_coretext.cpp \
SkTime_Unix.cpp \
$(NULL)
endif
ifeq (android,$(MOZ_WIDGET_TOOLKIT))
CPPSRCS += \
SkFontHost_FreeType.cpp \
SkFontHost_android.cpp \
SkFontHost_gamma.cpp \
- FontHostConfiguration_android.cpp \
SkMMapStream.cpp \
SkTime_Unix.cpp \
$(NULL)
DEFINES += -DSK_BUILD_FOR_ANDROID_NDK
OS_CXXFLAGS += $(CAIRO_FT_CFLAGS)
endif
ifeq (gtk2,$(MOZ_WIDGET_TOOLKIT))
CPPSRCS += \
diff --git a/gfx/skia/src/ports/SkFontHost_android.cpp b/gfx/skia/src/ports/SkFontHost_android.cpp
--- a/gfx/skia/src/ports/SkFontHost_android.cpp
+++ b/gfx/skia/src/ports/SkFontHost_android.cpp
@@ -1,38 +1,31 @@
+
/*
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
+ * Copyright 2006 The Android Open Source Project
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
#include "SkFontHost.h"
#include "SkDescriptor.h"
#include "SkMMapStream.h"
#include "SkPaint.h"
#include "SkString.h"
#include "SkStream.h"
#include "SkThread.h"
#include "SkTSearch.h"
-#include "FontHostConfiguration_android.h"
#include <stdio.h>
+#define FONT_CACHE_MEMORY_BUDGET (768 * 1024)
+
#ifndef SK_FONT_FILE_PREFIX
#define SK_FONT_FILE_PREFIX "/fonts/"
#endif
SkTypeface::Style find_name_and_attributes(SkStream* stream, SkString* name,
bool* isFixedWidth);
static void GetFullPathForSysFonts(SkString* full, const char name[]) {
full->set(getenv("ANDROID_ROOT"));
full->append(SK_FONT_FILE_PREFIX);
@@ -99,21 +92,21 @@ static SkTypeface* find_best_face(const
if (faces[SkTypeface::kNormal] != NULL) {
return faces[SkTypeface::kNormal];
}
// look for anything
for (int i = 0; i < 4; i++) {
if (faces[i] != NULL) {
return faces[i];
}
}
// should never get here, since the faces list should not be empty
- SkDEBUGFAIL("faces list is empty");
+ SkASSERT(!"faces list is empty");
return NULL;
}
static FamilyRec* find_family(const SkTypeface* member) {
FamilyRec* curr = gFamilyHead;
while (curr != NULL) {
for (int i = 0; i < 4; i++) {
if (curr->fFaces[i] == member) {
return curr;
}
@@ -138,31 +131,27 @@ static SkTypeface* find_from_uniqueID(ui
curr = curr->fNext;
}
return NULL;
}
/* Remove reference to this face from its family. If the resulting family
is empty (has no faces), return that family, otherwise return NULL
*/
static FamilyRec* remove_from_family(const SkTypeface* face) {
FamilyRec* family = find_family(face);
- if (family) {
- SkASSERT(family->fFaces[face->style()] == face);
- family->fFaces[face->style()] = NULL;
+ SkASSERT(family->fFaces[face->style()] == face);
+ family->fFaces[face->style()] = NULL;
- for (int i = 0; i < 4; i++) {
- if (family->fFaces[i] != NULL) { // family is non-empty
- return NULL;
- }
+ for (int i = 0; i < 4; i++) {
+ if (family->fFaces[i] != NULL) { // family is non-empty
+ return NULL;
}
- } else {
-// SkDebugf("remove_from_family(%p) face not found", face);
}
return family; // return the empty family
}
// maybe we should make FamilyRec be doubly-linked
static void detach_and_delete_family(FamilyRec* family) {
FamilyRec* curr = gFamilyHead;
FamilyRec* prev = NULL;
while (curr != NULL) {
@@ -172,21 +161,21 @@ static void detach_and_delete_family(Fam
gFamilyHead = next;
} else {
prev->fNext = next;
}
SkDELETE(family);
return;
}
prev = curr;
curr = next;
}
- SkDEBUGFAIL("Yikes, couldn't find family in our list to remove/delete");
+ SkASSERT(!"Yikes, couldn't find family in our list to remove/delete");
}
static SkTypeface* find_typeface(const char name[], SkTypeface::Style style) {
NameFamilyPair* list = gNameList.begin();
int count = gNameList.count();
int index = SkStrLCSearch(&list[0].fName, count, name, sizeof(list[0]));
if (index >= 0) {
return find_best_face(list[index].fFamily, style);
@@ -387,111 +376,90 @@ static bool get_name_and_style(const cha
}
return false;
}
// used to record our notion of the pre-existing fonts
struct FontInitRec {
const char* fFileName;
const char* const* fNames; // null-terminated list
};
+static const char* gSansNames[] = {
+ "sans-serif", "arial", "helvetica", "tahoma", "verdana", NULL
+};
+
+static const char* gSerifNames[] = {
+ "serif", "times", "times new roman", "palatino", "georgia", "baskerville",
+ "goudy", "fantasy", "cursive", "ITC Stone Serif", NULL
+};
+
+static const char* gMonoNames[] = {
+ "monospace", "courier", "courier new", "monaco", NULL
+};
+
// deliberately empty, but we use the address to identify fallback fonts
static const char* gFBNames[] = { NULL };
+/* Fonts must be grouped by family, with the first font in a family having the
+ list of names (even if that list is empty), and the following members having
+ null for the list. The names list must be NULL-terminated
+*/
+static const FontInitRec gSystemFonts[] = {
+ { "DroidSans.ttf", gSansNames },
+ { "DroidSans-Bold.ttf", NULL },
+ { "DroidSerif-Regular.ttf", gSerifNames },
+ { "DroidSerif-Bold.ttf", NULL },
+ { "DroidSerif-Italic.ttf", NULL },
+ { "DroidSerif-BoldItalic.ttf", NULL },
+ { "DroidSansMono.ttf", gMonoNames },
+ /* These are optional, and can be ignored if not found in the file system.
+ These are appended to gFallbackFonts[] as they are seen, so we list
+ them in the order we want them to be accessed by NextLogicalFont().
+ */
+ { "DroidSansArabic.ttf", gFBNames },
+ { "DroidSansHebrew.ttf", gFBNames },
+ { "DroidSansThai.ttf", gFBNames },
+ { "MTLmr3m.ttf", gFBNames }, // Motoya Japanese Font
+ { "MTLc3m.ttf", gFBNames }, // Motoya Japanese Font
+ { "DroidSansJapanese.ttf", gFBNames },
+ { "DroidSansFallback.ttf", gFBNames }
+};
-/* Fonts are grouped by family, with the first font in a family having the
- list of names (even if that list is empty), and the following members having
- null for the list. The names list must be NULL-terminated.
-*/
-static FontInitRec *gSystemFonts;
-static size_t gNumSystemFonts = 0;
-
-#define SYSTEM_FONTS_FILE "/system/etc/system_fonts.cfg"
+#define DEFAULT_NAMES gSansNames
// these globals are assigned (once) by load_system_fonts()
static FamilyRec* gDefaultFamily;
static SkTypeface* gDefaultNormal;
-static char** gDefaultNames = NULL;
-static uint32_t *gFallbackFonts;
-/* Load info from a configuration file that populates the system/fallback font structures
-*/
-static void load_font_info() {
-// load_font_info_xml("/system/etc/system_fonts.xml");
- SkTDArray<FontFamily*> fontFamilies;
- getFontFamilies(fontFamilies);
-
- SkTDArray<FontInitRec> fontInfo;
- bool firstInFamily = false;
- for (int i = 0; i < fontFamilies.count(); ++i) {
- FontFamily *family = fontFamilies[i];
- firstInFamily = true;
- for (int j = 0; j < family->fFileNames.count(); ++j) {
- FontInitRec fontInfoRecord;
- fontInfoRecord.fFileName = family->fFileNames[j];
- if (j == 0) {
- if (family->fNames.count() == 0) {
- // Fallback font
- fontInfoRecord.fNames = (char **)gFBNames;
- } else {
- SkTDArray<const char*> names = family->fNames;
- const char **nameList = (const char**)
- malloc((names.count() + 1) * sizeof(char*));
- if (nameList == NULL) {
- // shouldn't get here
- break;
- }
- if (gDefaultNames == NULL) {
- gDefaultNames = (char**) nameList;
- }
- for (int i = 0; i < names.count(); ++i) {
- nameList[i] = names[i];
- }
- nameList[names.count()] = NULL;
- fontInfoRecord.fNames = nameList;
- }
- } else {
- fontInfoRecord.fNames = NULL;
- }
- *fontInfo.append() = fontInfoRecord;
- }
- }
- gNumSystemFonts = fontInfo.count();
- gSystemFonts = (FontInitRec*) malloc(gNumSystemFonts * sizeof(FontInitRec));
- gFallbackFonts = (uint32_t*) malloc((gNumSystemFonts + 1) * sizeof(uint32_t));
- if (gSystemFonts == NULL) {
- // shouldn't get here
- gNumSystemFonts = 0;
- }
- for (size_t i = 0; i < gNumSystemFonts; ++i) {
- gSystemFonts[i].fFileName = fontInfo[i].fFileName;
- gSystemFonts[i].fNames = fontInfo[i].fNames;
- }
- fontFamilies.deleteAll();
-}
+/* This is sized conservatively, assuming that it will never be a size issue.
+ It will be initialized in load_system_fonts(), and will be filled with the
+ fontIDs that can be used for fallback consideration, in sorted order (sorted
+ meaning element[0] should be used first, then element[1], etc. When we hit
+ a fontID==0 in the array, the list is done, hence our allocation size is
+ +1 the total number of possible system fonts. Also see NextLogicalFont().
+ */
+static uint32_t gFallbackFonts[SK_ARRAY_COUNT(gSystemFonts)+1];
/* Called once (ensured by the sentinel check at the beginning of our body).
Initializes all the globals, and register the system fonts.
*/
static void load_system_fonts() {
// check if we've already be called
if (NULL != gDefaultNormal) {
return;
}
- load_font_info();
-
const FontInitRec* rec = gSystemFonts;
SkTypeface* firstInFamily = NULL;
int fallbackCount = 0;
- for (size_t i = 0; i < gNumSystemFonts; i++) {
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gSystemFonts); i++) {
// if we're the first in a new family, clear firstInFamily
if (rec[i].fNames != NULL) {
firstInFamily = NULL;
}
bool isFixedWidth;
SkString name;
SkTypeface::Style style;
// we expect all the fonts, except the "fallback" fonts
@@ -515,120 +483,75 @@ static void load_system_fonts() {
// SkDebugf("---- adding %s as fallback[%d] fontID %d\n",
// rec[i].fFileName, fallbackCount, tf->uniqueID());
gFallbackFonts[fallbackCount++] = tf->uniqueID();
}
firstInFamily = tf;
FamilyRec* family = find_family(tf);
const char* const* names = rec[i].fNames;
// record the default family if this is it
- if (names == gDefaultNames) {
+ if (names == DEFAULT_NAMES) {
gDefaultFamily = family;
}
// add the names to map to this family
while (*names) {
add_name(*names, family);
names += 1;
}
}
}
// do this after all fonts are loaded. This is our default font, and it
// acts as a sentinel so we only execute load_system_fonts() once
gDefaultNormal = find_best_face(gDefaultFamily, SkTypeface::kNormal);
// now terminate our fallback list with the sentinel value
gFallbackFonts[fallbackCount] = 0;
}
///////////////////////////////////////////////////////////////////////////////
void SkFontHost::Serialize(const SkTypeface* face, SkWStream* stream) {
- // lookup and record if the font is custom (i.e. not a system font)
- bool isCustomFont = !((FamilyTypeface*)face)->isSysFont();
- stream->writeBool(isCustomFont);
+ const char* name = ((FamilyTypeface*)face)->getUniqueString();
- if (isCustomFont) {
- SkStream* fontStream = ((FamilyTypeface*)face)->openStream();
+ stream->write8((uint8_t)face->style());
- // store the length of the custom font
- uint32_t len = fontStream->getLength();
- stream->write32(len);
-
- // store the entire font in the serialized stream
- void* fontData = malloc(len);
-
- fontStream->read(fontData, len);
- stream->write(fontData, len);
-
- fontStream->unref();
- free(fontData);
-// SkDebugf("--- fonthost custom serialize %d %d\n", face->style(), len);
-
+ if (NULL == name || 0 == *name) {
+ stream->writePackedUInt(0);
+// SkDebugf("--- fonthost serialize null\n");
} else {
- const char* name = ((FamilyTypeface*)face)->getUniqueString();
-
- stream->write8((uint8_t)face->style());
-
- if (NULL == name || 0 == *name) {
- stream->writePackedUInt(0);
-// SkDebugf("--- fonthost serialize null\n");
- } else {
- uint32_t len = strlen(name);
- stream->writePackedUInt(len);
- stream->write(name, len);
-// SkDebugf("--- fonthost serialize <%s> %d\n", name, face->style());
- }
+ uint32_t len = strlen(name);
+ stream->writePackedUInt(len);
+ stream->write(name, len);
+// SkDebugf("--- fonthost serialize <%s> %d\n", name, face->style());
}
}
SkTypeface* SkFontHost::Deserialize(SkStream* stream) {
load_system_fonts();
- // check if the font is a custom or system font
- bool isCustomFont = stream->readBool();
+ int style = stream->readU8();
- if (isCustomFont) {
+ int len = stream->readPackedUInt();
+ if (len > 0) {
+ SkString str;
+ str.resize(len);
+ stream->read(str.writable_str(), len);
- // read the length of the custom font from the stream
- uint32_t len = stream->readU32();
-
- // generate a new stream to store the custom typeface
- SkMemoryStream* fontStream = new SkMemoryStream(len);
- stream->read((void*)fontStream->getMemoryBase(), len);
-
- SkTypeface* face = CreateTypefaceFromStream(fontStream);
-
- fontStream->unref();
-
-// SkDebugf("--- fonthost custom deserialize %d %d\n", face->style(), len);
- return face;
-
- } else {
- int style = stream->readU8();
-
- int len = stream->readPackedUInt();
- if (len > 0) {
- SkString str;
- str.resize(len);
- stream->read(str.writable_str(), len);
-
- const FontInitRec* rec = gSystemFonts;
- for (size_t i = 0; i < gNumSystemFonts; i++) {
- if (strcmp(rec[i].fFileName, str.c_str()) == 0) {
- // backup until we hit the fNames
- for (int j = i; j >= 0; --j) {
- if (rec[j].fNames != NULL) {
- return SkFontHost::CreateTypeface(NULL,
- rec[j].fNames[0], NULL, 0,
- (SkTypeface::Style)style);
- }
+ const FontInitRec* rec = gSystemFonts;
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gSystemFonts); i++) {
+ if (strcmp(rec[i].fFileName, str.c_str()) == 0) {
+ // backup until we hit the fNames
+ for (int j = i; j >= 0; --j) {
+ if (rec[j].fNames != NULL) {
+ return SkFontHost::CreateTypeface(NULL,
+ rec[j].fNames[0], NULL, 0, (SkTypeface::Style)style);
}
}
}
}
}
return NULL;
}
///////////////////////////////////////////////////////////////////////////////
@@ -697,49 +620,32 @@ size_t SkFontHost::GetFileName(SkFontID
}
return size;
} else {
return 0;
}
}
SkFontID SkFontHost::NextLogicalFont(SkFontID currFontID, SkFontID origFontID) {
load_system_fonts();
- const SkTypeface* origTypeface = find_from_uniqueID(origFontID);
- const SkTypeface* currTypeface = find_from_uniqueID(currFontID);
-
- SkASSERT(origTypeface != 0);
- SkASSERT(currTypeface != 0);
-
- // Our fallback list always stores the id of the plain in each fallback
- // family, so we transform currFontID to its plain equivalent.
- currFontID = find_typeface(currTypeface, SkTypeface::kNormal)->uniqueID();
-
/* First see if fontID is already one of our fallbacks. If so, return
its successor. If fontID is not in our list, then return the first one
in our list. Note: list is zero-terminated, and returning zero means
we have no more fonts to use for fallbacks.
*/
const uint32_t* list = gFallbackFonts;
for (int i = 0; list[i] != 0; i++) {
if (list[i] == currFontID) {
- if (list[i+1] == 0)
- return 0;
- const SkTypeface* nextTypeface = find_from_uniqueID(list[i+1]);
- return find_typeface(nextTypeface, origTypeface->style())->uniqueID();
+ return list[i+1];
}
}
-
- // If we get here, currFontID was not a fallback, so we start at the
- // beginning of our list.
- const SkTypeface* firstTypeface = find_from_uniqueID(list[0]);
- return find_typeface(firstTypeface, origTypeface->style())->uniqueID();
+ return list[0];
}
///////////////////////////////////////////////////////////////////////////////
SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) {
if (NULL == stream || stream->getLength() <= 0) {
return NULL;
}
bool isFixedWidth;
@@ -754,10 +660,11 @@ SkTypeface* SkFontHost::CreateTypefaceFr
}
SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) {
SkStream* stream = SkNEW_ARGS(SkMMAPStream, (path));
SkTypeface* face = SkFontHost::CreateTypefaceFromStream(stream);
// since we created the stream, we let go of our ref() here
stream->unref();
return face;
}
+///////////////////////////////////////////////////////////////////////////////

View File

@ -16,6 +16,7 @@
*/
#include "FontHostConfiguration_android.h"
#include <expat_config.h>
#include <expat.h>
#include "SkTDArray.h"

View File

@ -1,19 +1,11 @@
/*
**
** Copyright 2006, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
* Copyright 2006 The Android Open Source Project
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkFontHost.h"
#include "SkDescriptor.h"
@ -23,9 +15,10 @@
#include "SkStream.h"
#include "SkThread.h"
#include "SkTSearch.h"
#include "FontHostConfiguration_android.h"
#include <stdio.h>
#define FONT_CACHE_MEMORY_BUDGET (768 * 1024)
#ifndef SK_FONT_FILE_PREFIX
#define SK_FONT_FILE_PREFIX "/fonts/"
#endif
@ -106,7 +99,7 @@ static SkTypeface* find_best_face(const FamilyRec* family,
}
}
// should never get here, since the faces list should not be empty
SkDEBUGFAIL("faces list is empty");
SkASSERT(!"faces list is empty");
return NULL;
}
@ -145,17 +138,13 @@ static SkTypeface* find_from_uniqueID(uint32_t uniqueID) {
*/
static FamilyRec* remove_from_family(const SkTypeface* face) {
FamilyRec* family = find_family(face);
if (family) {
SkASSERT(family->fFaces[face->style()] == face);
family->fFaces[face->style()] = NULL;
SkASSERT(family->fFaces[face->style()] == face);
family->fFaces[face->style()] = NULL;
for (int i = 0; i < 4; i++) {
if (family->fFaces[i] != NULL) { // family is non-empty
return NULL;
}
for (int i = 0; i < 4; i++) {
if (family->fFaces[i] != NULL) { // family is non-empty
return NULL;
}
} else {
// SkDebugf("remove_from_family(%p) face not found", face);
}
return family; // return the empty family
}
@ -179,7 +168,7 @@ static void detach_and_delete_family(FamilyRec* family) {
prev = curr;
curr = next;
}
SkDEBUGFAIL("Yikes, couldn't find family in our list to remove/delete");
SkASSERT(!"Yikes, couldn't find family in our list to remove/delete");
}
static SkTypeface* find_typeface(const char name[], SkTypeface::Style style) {
@ -394,80 +383,61 @@ struct FontInitRec {
const char* const* fNames; // null-terminated list
};
static const char* gSansNames[] = {
"sans-serif", "arial", "helvetica", "tahoma", "verdana", NULL
};
static const char* gSerifNames[] = {
"serif", "times", "times new roman", "palatino", "georgia", "baskerville",
"goudy", "fantasy", "cursive", "ITC Stone Serif", NULL
};
static const char* gMonoNames[] = {
"monospace", "courier", "courier new", "monaco", NULL
};
// deliberately empty, but we use the address to identify fallback fonts
static const char* gFBNames[] = { NULL };
/* Fonts are grouped by family, with the first font in a family having the
/* Fonts must be grouped by family, with the first font in a family having the
list of names (even if that list is empty), and the following members having
null for the list. The names list must be NULL-terminated.
null for the list. The names list must be NULL-terminated
*/
static FontInitRec *gSystemFonts;
static size_t gNumSystemFonts = 0;
static const FontInitRec gSystemFonts[] = {
{ "DroidSans.ttf", gSansNames },
{ "DroidSans-Bold.ttf", NULL },
{ "DroidSerif-Regular.ttf", gSerifNames },
{ "DroidSerif-Bold.ttf", NULL },
{ "DroidSerif-Italic.ttf", NULL },
{ "DroidSerif-BoldItalic.ttf", NULL },
{ "DroidSansMono.ttf", gMonoNames },
/* These are optional, and can be ignored if not found in the file system.
These are appended to gFallbackFonts[] as they are seen, so we list
them in the order we want them to be accessed by NextLogicalFont().
*/
{ "DroidSansArabic.ttf", gFBNames },
{ "DroidSansHebrew.ttf", gFBNames },
{ "DroidSansThai.ttf", gFBNames },
{ "MTLmr3m.ttf", gFBNames }, // Motoya Japanese Font
{ "MTLc3m.ttf", gFBNames }, // Motoya Japanese Font
{ "DroidSansJapanese.ttf", gFBNames },
{ "DroidSansFallback.ttf", gFBNames }
};
#define SYSTEM_FONTS_FILE "/system/etc/system_fonts.cfg"
#define DEFAULT_NAMES gSansNames
// these globals are assigned (once) by load_system_fonts()
static FamilyRec* gDefaultFamily;
static SkTypeface* gDefaultNormal;
static char** gDefaultNames = NULL;
static uint32_t *gFallbackFonts;
/* Load info from a configuration file that populates the system/fallback font structures
*/
static void load_font_info() {
// load_font_info_xml("/system/etc/system_fonts.xml");
SkTDArray<FontFamily*> fontFamilies;
getFontFamilies(fontFamilies);
SkTDArray<FontInitRec> fontInfo;
bool firstInFamily = false;
for (int i = 0; i < fontFamilies.count(); ++i) {
FontFamily *family = fontFamilies[i];
firstInFamily = true;
for (int j = 0; j < family->fFileNames.count(); ++j) {
FontInitRec fontInfoRecord;
fontInfoRecord.fFileName = family->fFileNames[j];
if (j == 0) {
if (family->fNames.count() == 0) {
// Fallback font
fontInfoRecord.fNames = (char **)gFBNames;
} else {
SkTDArray<const char*> names = family->fNames;
const char **nameList = (const char**)
malloc((names.count() + 1) * sizeof(char*));
if (nameList == NULL) {
// shouldn't get here
break;
}
if (gDefaultNames == NULL) {
gDefaultNames = (char**) nameList;
}
for (int i = 0; i < names.count(); ++i) {
nameList[i] = names[i];
}
nameList[names.count()] = NULL;
fontInfoRecord.fNames = nameList;
}
} else {
fontInfoRecord.fNames = NULL;
}
*fontInfo.append() = fontInfoRecord;
}
}
gNumSystemFonts = fontInfo.count();
gSystemFonts = (FontInitRec*) malloc(gNumSystemFonts * sizeof(FontInitRec));
gFallbackFonts = (uint32_t*) malloc((gNumSystemFonts + 1) * sizeof(uint32_t));
if (gSystemFonts == NULL) {
// shouldn't get here
gNumSystemFonts = 0;
}
for (size_t i = 0; i < gNumSystemFonts; ++i) {
gSystemFonts[i].fFileName = fontInfo[i].fFileName;
gSystemFonts[i].fNames = fontInfo[i].fNames;
}
fontFamilies.deleteAll();
}
/* This is sized conservatively, assuming that it will never be a size issue.
It will be initialized in load_system_fonts(), and will be filled with the
fontIDs that can be used for fallback consideration, in sorted order (sorted
meaning element[0] should be used first, then element[1], etc. When we hit
a fontID==0 in the array, the list is done, hence our allocation size is
+1 the total number of possible system fonts. Also see NextLogicalFont().
*/
static uint32_t gFallbackFonts[SK_ARRAY_COUNT(gSystemFonts)+1];
/* Called once (ensured by the sentinel check at the beginning of our body).
Initializes all the globals, and register the system fonts.
@ -478,13 +448,11 @@ static void load_system_fonts() {
return;
}
load_font_info();
const FontInitRec* rec = gSystemFonts;
SkTypeface* firstInFamily = NULL;
int fallbackCount = 0;
for (size_t i = 0; i < gNumSystemFonts; i++) {
for (size_t i = 0; i < SK_ARRAY_COUNT(gSystemFonts); i++) {
// if we're the first in a new family, clear firstInFamily
if (rec[i].fNames != NULL) {
firstInFamily = NULL;
@ -522,7 +490,7 @@ static void load_system_fonts() {
const char* const* names = rec[i].fNames;
// record the default family if this is it
if (names == gDefaultNames) {
if (names == DEFAULT_NAMES) {
gDefaultFamily = family;
}
// add the names to map to this family
@ -543,85 +511,40 @@ static void load_system_fonts() {
///////////////////////////////////////////////////////////////////////////////
void SkFontHost::Serialize(const SkTypeface* face, SkWStream* stream) {
// lookup and record if the font is custom (i.e. not a system font)
bool isCustomFont = !((FamilyTypeface*)face)->isSysFont();
stream->writeBool(isCustomFont);
const char* name = ((FamilyTypeface*)face)->getUniqueString();
if (isCustomFont) {
SkStream* fontStream = ((FamilyTypeface*)face)->openStream();
// store the length of the custom font
uint32_t len = fontStream->getLength();
stream->write32(len);
// store the entire font in the serialized stream
void* fontData = malloc(len);
fontStream->read(fontData, len);
stream->write(fontData, len);
fontStream->unref();
free(fontData);
// SkDebugf("--- fonthost custom serialize %d %d\n", face->style(), len);
stream->write8((uint8_t)face->style());
if (NULL == name || 0 == *name) {
stream->writePackedUInt(0);
// SkDebugf("--- fonthost serialize null\n");
} else {
const char* name = ((FamilyTypeface*)face)->getUniqueString();
stream->write8((uint8_t)face->style());
if (NULL == name || 0 == *name) {
stream->writePackedUInt(0);
// SkDebugf("--- fonthost serialize null\n");
} else {
uint32_t len = strlen(name);
stream->writePackedUInt(len);
stream->write(name, len);
// SkDebugf("--- fonthost serialize <%s> %d\n", name, face->style());
}
uint32_t len = strlen(name);
stream->writePackedUInt(len);
stream->write(name, len);
// SkDebugf("--- fonthost serialize <%s> %d\n", name, face->style());
}
}
SkTypeface* SkFontHost::Deserialize(SkStream* stream) {
load_system_fonts();
// check if the font is a custom or system font
bool isCustomFont = stream->readBool();
int style = stream->readU8();
if (isCustomFont) {
int len = stream->readPackedUInt();
if (len > 0) {
SkString str;
str.resize(len);
stream->read(str.writable_str(), len);
// read the length of the custom font from the stream
uint32_t len = stream->readU32();
// generate a new stream to store the custom typeface
SkMemoryStream* fontStream = new SkMemoryStream(len);
stream->read((void*)fontStream->getMemoryBase(), len);
SkTypeface* face = CreateTypefaceFromStream(fontStream);
fontStream->unref();
// SkDebugf("--- fonthost custom deserialize %d %d\n", face->style(), len);
return face;
} else {
int style = stream->readU8();
int len = stream->readPackedUInt();
if (len > 0) {
SkString str;
str.resize(len);
stream->read(str.writable_str(), len);
const FontInitRec* rec = gSystemFonts;
for (size_t i = 0; i < gNumSystemFonts; i++) {
if (strcmp(rec[i].fFileName, str.c_str()) == 0) {
// backup until we hit the fNames
for (int j = i; j >= 0; --j) {
if (rec[j].fNames != NULL) {
return SkFontHost::CreateTypeface(NULL,
rec[j].fNames[0], NULL, 0,
(SkTypeface::Style)style);
}
const FontInitRec* rec = gSystemFonts;
for (size_t i = 0; i < SK_ARRAY_COUNT(gSystemFonts); i++) {
if (strcmp(rec[i].fFileName, str.c_str()) == 0) {
// backup until we hit the fNames
for (int j = i; j >= 0; --j) {
if (rec[j].fNames != NULL) {
return SkFontHost::CreateTypeface(NULL,
rec[j].fNames[0], NULL, 0, (SkTypeface::Style)style);
}
}
}
@ -704,16 +627,6 @@ size_t SkFontHost::GetFileName(SkFontID fontID, char path[], size_t length,
SkFontID SkFontHost::NextLogicalFont(SkFontID currFontID, SkFontID origFontID) {
load_system_fonts();
const SkTypeface* origTypeface = find_from_uniqueID(origFontID);
const SkTypeface* currTypeface = find_from_uniqueID(currFontID);
SkASSERT(origTypeface != 0);
SkASSERT(currTypeface != 0);
// Our fallback list always stores the id of the plain in each fallback
// family, so we transform currFontID to its plain equivalent.
currFontID = find_typeface(currTypeface, SkTypeface::kNormal)->uniqueID();
/* First see if fontID is already one of our fallbacks. If so, return
its successor. If fontID is not in our list, then return the first one
in our list. Note: list is zero-terminated, and returning zero means
@ -722,17 +635,10 @@ SkFontID SkFontHost::NextLogicalFont(SkFontID currFontID, SkFontID origFontID) {
const uint32_t* list = gFallbackFonts;
for (int i = 0; list[i] != 0; i++) {
if (list[i] == currFontID) {
if (list[i+1] == 0)
return 0;
const SkTypeface* nextTypeface = find_from_uniqueID(list[i+1]);
return find_typeface(nextTypeface, origTypeface->style())->uniqueID();
return list[i+1];
}
}
// If we get here, currFontID was not a fallback, so we start at the
// beginning of our list.
const SkTypeface* firstTypeface = find_from_uniqueID(list[0]);
return find_typeface(firstTypeface, origTypeface->style())->uniqueID();
return list[0];
}
///////////////////////////////////////////////////////////////////////////////
@ -761,3 +667,4 @@ SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) {
return face;
}
///////////////////////////////////////////////////////////////////////////////

View File

@ -30,8 +30,7 @@ SkTypeface* SkFontHost::CreateTypefaceFromFile(char const*) {
// static
SkAdvancedTypefaceMetrics* SkFontHost::GetAdvancedTypefaceMetrics(
uint32_t fontID,
SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo,
const uint32_t*, uint32_t) {
SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo) {
SkDEBUGFAIL("SkFontHost::GetAdvancedTypefaceMetrics unimplemented");
return NULL;
}

View File

@ -110,3 +110,5 @@ patch -p3 < user-config.patch
patch -p3 < uninitialized-margin.patch
# Bug 722011 - Fix comma at end of enum list
patch -p3 < fix-comma-end-enum-list.patch
# Bug 719872 - Fix crash on Android by reverting to older FontHost impl
patch -p3 < old-android-fonthost.patch

View File

@ -436,6 +436,14 @@ void SourceBufferDestroy(void *srcBuffer)
static_cast<SourceSurface*>(srcBuffer)->Release();
}
void SourceSnapshotDetached(cairo_surface_t *nullSurf)
{
gfxImageSurface* origSurf =
static_cast<gfxImageSurface*>(cairo_surface_get_user_data(nullSurf, &kSourceSurface));
origSurf->SetData(&kSourceSurface, NULL, NULL);
}
RefPtr<SourceSurface>
gfxPlatform::GetSourceSurfaceForSurface(DrawTarget *aTarget, gfxASurface *aSurface)
{
@ -503,6 +511,15 @@ gfxPlatform::GetSourceSurfaceForSurface(DrawTarget *aTarget, gfxASurface *aSurfa
IntSize(imgSurface->GetSize().width, imgSurface->GetSize().height),
imgSurface->Stride(),
format);
cairo_surface_t *nullSurf =
cairo_null_surface_create(CAIRO_CONTENT_COLOR_ALPHA);
cairo_surface_set_user_data(nullSurf,
&kSourceSurface,
imgSurface,
NULL);
cairo_surface_attach_snapshot(imgSurface->CairoSurface(), nullSurf, SourceSnapshotDetached);
cairo_surface_destroy(nullSurf);
}
srcBuffer->AddRef();

View File

@ -342,6 +342,12 @@ gfxWindowsPlatform::VerifyD2DDevice(bool aAttemptForce)
nsRefPtr<IDXGIFactory1> factory1;
HRESULT hr = createDXGIFactory1(__uuidof(IDXGIFactory1),
getter_AddRefs(factory1));
if (FAILED(hr) || !factory1) {
// This seems to happen with some people running the iZ3D driver.
// They won't get acceleration.
return;
}
nsRefPtr<IDXGIAdapter1> adapter1;
hr = factory1->EnumAdapters1(0, getter_AddRefs(adapter1));

View File

@ -61,8 +61,8 @@ SyncChannel::SyncChannel(SyncListener* aListener)
, mPendingReply(0)
, mProcessingSyncMessage(false)
, mNextSeqno(0)
, mTimeoutMs(kNoTimeout)
, mInTimeoutSecondHalf(false)
, mTimeoutMs(kNoTimeout)
#ifdef OS_WIN
, mTopFrame(NULL)
#endif

View File

@ -1061,6 +1061,7 @@ XPCShellEnvironment::~XPCShellEnvironment()
JSRuntime* rt = gOldContextCallback ? JS_GetRuntime(mCx) : NULL;
JS_EndRequest(mCx);
JS_DestroyContext(mCx);
if (gOldContextCallback) {

View File

@ -53,12 +53,12 @@
namespace JS {
/* Data for tracking analysis/inference memory usage. */
struct TypeInferenceMemoryStats
struct TypeInferenceSizes
{
int64_t scripts;
int64_t objects;
int64_t tables;
int64_t temporary;
size_t scripts;
size_t objects;
size_t tables;
size_t temporary;
};
typedef void* (* GetNameCallback)(JSContext *cx, JSCompartment *c);
@ -86,40 +86,40 @@ struct CompartmentStats
void *name;
DestroyNameCallback destroyNameCb;
int64_t gcHeapArenaHeaders;
int64_t gcHeapArenaPadding;
int64_t gcHeapArenaUnused;
size_t gcHeapArenaHeaders;
size_t gcHeapArenaPadding;
size_t gcHeapArenaUnused;
int64_t gcHeapObjectsNonFunction;
int64_t gcHeapObjectsFunction;
int64_t gcHeapStrings;
int64_t gcHeapShapesTree;
int64_t gcHeapShapesDict;
int64_t gcHeapShapesBase;
int64_t gcHeapScripts;
int64_t gcHeapTypeObjects;
int64_t gcHeapXML;
size_t gcHeapObjectsNonFunction;
size_t gcHeapObjectsFunction;
size_t gcHeapStrings;
size_t gcHeapShapesTree;
size_t gcHeapShapesDict;
size_t gcHeapShapesBase;
size_t gcHeapScripts;
size_t gcHeapTypeObjects;
size_t gcHeapXML;
int64_t objectSlots;
int64_t objectElements;
int64_t stringChars;
int64_t shapesExtraTreeTables;
int64_t shapesExtraDictTables;
int64_t shapesExtraTreeShapeKids;
int64_t shapesCompartmentTables;
int64_t scriptData;
size_t objectSlots;
size_t objectElements;
size_t stringChars;
size_t shapesExtraTreeTables;
size_t shapesExtraDictTables;
size_t shapesExtraTreeShapeKids;
size_t shapesCompartmentTables;
size_t scriptData;
#ifdef JS_METHODJIT
int64_t mjitCode;
int64_t mjitData;
size_t mjitCode;
size_t mjitData;
#endif
TypeInferenceMemoryStats typeInferenceMemory;
TypeInferenceSizes typeInferenceSizes;
};
struct IterateData
struct RuntimeStats
{
IterateData(JSMallocSizeOfFun mallocSizeOf, GetNameCallback getNameCb,
DestroyNameCallback destroyNameCb)
RuntimeStats(JSMallocSizeOfFun mallocSizeOf, GetNameCallback getNameCb,
DestroyNameCallback destroyNameCb)
: runtimeObject(0)
, runtimeAtomsTable(0)
, runtimeContexts(0)
@ -151,30 +151,30 @@ struct IterateData
, destroyNameCb(destroyNameCb)
{}
int64_t runtimeObject;
int64_t runtimeAtomsTable;
int64_t runtimeContexts;
int64_t runtimeNormal;
int64_t runtimeTemporary;
int64_t runtimeRegexpCode;
int64_t runtimeStackCommitted;
int64_t gcHeapChunkTotal;
int64_t gcHeapChunkCleanUnused;
int64_t gcHeapChunkDirtyUnused;
int64_t gcHeapChunkCleanDecommitted;
int64_t gcHeapChunkDirtyDecommitted;
int64_t gcHeapArenaUnused;
int64_t gcHeapChunkAdmin;
int64_t gcHeapUnusedPercentage;
int64_t totalObjects;
int64_t totalShapes;
int64_t totalScripts;
int64_t totalStrings;
size_t runtimeObject;
size_t runtimeAtomsTable;
size_t runtimeContexts;
size_t runtimeNormal;
size_t runtimeTemporary;
size_t runtimeRegexpCode;
size_t runtimeStackCommitted;
size_t gcHeapChunkTotal;
size_t gcHeapChunkCleanUnused;
size_t gcHeapChunkDirtyUnused;
size_t gcHeapChunkCleanDecommitted;
size_t gcHeapChunkDirtyDecommitted;
size_t gcHeapArenaUnused;
size_t gcHeapChunkAdmin;
size_t gcHeapUnusedPercentage;
size_t totalObjects;
size_t totalShapes;
size_t totalScripts;
size_t totalStrings;
#ifdef JS_METHODJIT
int64_t totalMjit;
size_t totalMjit;
#endif
int64_t totalTypeInference;
int64_t totalAnalysisTemp;
size_t totalTypeInference;
size_t totalAnalysisTemp;
js::Vector<CompartmentStats, 0, js::SystemAllocPolicy> compartmentStatsVector;
CompartmentStats *currCompartmentStats;
@ -187,7 +187,7 @@ struct IterateData
#ifdef JS_THREADSAFE
extern JS_PUBLIC_API(bool)
CollectCompartmentStatsForRuntime(JSRuntime *rt, IterateData *data);
CollectRuntimeStats(JSRuntime *rt, RuntimeStats *rtStats);
extern JS_PUBLIC_API(bool)
GetExplicitNonHeapForRuntime(JSRuntime *rt, int64_t *amount,
@ -195,19 +195,6 @@ GetExplicitNonHeapForRuntime(JSRuntime *rt, int64_t *amount,
#endif /* JS_THREADSAFE */
extern void
SizeOfCompartmentTypeInferenceData(JSContext *cx, JSCompartment *compartment,
TypeInferenceMemoryStats *stats,
JSMallocSizeOfFun mallocSizeOf);
extern void
SizeOfTypeObjectExcludingThis(/*TypeObject*/ void *object,
TypeInferenceMemoryStats *stats,
JSMallocSizeOfFun mallocSizeOf);
extern size_t
SizeOfCompartmentShapeTable(JSCompartment *c, JSMallocSizeOfFun mallocSizeOf);
extern JS_PUBLIC_API(size_t)
SystemCompartmentCount(const JSRuntime *rt);

View File

@ -55,26 +55,23 @@ namespace JS {
using namespace js;
static void
CompartmentMemoryCallback(JSContext *cx, void *vdata, JSCompartment *compartment)
CompartmentStatsCallback(JSContext *cx, void *vdata, JSCompartment *compartment)
{
// Append a new CompartmentStats to the vector.
IterateData *data = static_cast<IterateData *>(vdata);
RuntimeStats *rtStats = static_cast<RuntimeStats *>(vdata);
// CollectCompartmentStatsForRuntime reserves enough space.
MOZ_ALWAYS_TRUE(data->compartmentStatsVector.growBy(1));
CompartmentStats &curr = data->compartmentStatsVector.back();
curr.init(data->getNameCb(cx, compartment), data->destroyNameCb);
data->currCompartmentStats = &curr;
// CollectRuntimeStats reserves enough space.
MOZ_ALWAYS_TRUE(rtStats->compartmentStatsVector.growBy(1));
CompartmentStats &cStats = rtStats->compartmentStatsVector.back();
cStats.init(rtStats->getNameCb(cx, compartment), rtStats->destroyNameCb);
rtStats->currCompartmentStats = &cStats;
// Get the compartment-level numbers.
#ifdef JS_METHODJIT
curr.mjitCode = compartment->sizeOfMjitCode();
cStats.mjitCode = compartment->sizeOfMjitCode();
#endif
SizeOfCompartmentTypeInferenceData(cx, compartment,
&curr.typeInferenceMemory,
data->mallocSizeOf);
curr.shapesCompartmentTables =
SizeOfCompartmentShapeTable(compartment, data->mallocSizeOf);
compartment->sizeOfTypeInferenceData(cx, &cStats.typeInferenceSizes, rtStats->mallocSizeOf);
cStats.shapesCompartmentTables = compartment->sizeOfShapeTable(rtStats->mallocSizeOf);
}
static void
@ -91,109 +88,107 @@ ChunkCallback(JSContext *cx, void *vdata, gc::Chunk *chunk)
{
// Nb: This function is only called for dirty chunks, which is why we
// increment gcHeapChunkDirtyDecommitted.
IterateData *data = static_cast<IterateData *>(vdata);
RuntimeStats *rtStats = static_cast<RuntimeStats *>(vdata);
for (size_t i = 0; i < gc::ArenasPerChunk; i++)
if (chunk->decommittedArenas.get(i))
data->gcHeapChunkDirtyDecommitted += gc::ArenaSize;
rtStats->gcHeapChunkDirtyDecommitted += gc::ArenaSize;
}
static void
ArenaCallback(JSContext *cx, void *vdata, gc::Arena *arena,
JSGCTraceKind traceKind, size_t thingSize)
{
IterateData *data = static_cast<IterateData *>(vdata);
RuntimeStats *rtStats = static_cast<RuntimeStats *>(vdata);
data->currCompartmentStats->gcHeapArenaHeaders +=
sizeof(gc::ArenaHeader);
rtStats->currCompartmentStats->gcHeapArenaHeaders += sizeof(gc::ArenaHeader);
size_t allocationSpace = arena->thingsSpan(thingSize);
data->currCompartmentStats->gcHeapArenaPadding +=
rtStats->currCompartmentStats->gcHeapArenaPadding +=
gc::ArenaSize - allocationSpace - sizeof(gc::ArenaHeader);
// We don't call the callback on unused things. So we compute the
// unused space like this: arenaUnused = maxArenaUnused - arenaUsed.
// We do this by setting arenaUnused to maxArenaUnused here, and then
// subtracting thingSize for every used cell, in CellCallback().
data->currCompartmentStats->gcHeapArenaUnused += allocationSpace;
rtStats->currCompartmentStats->gcHeapArenaUnused += allocationSpace;
}
static void
CellCallback(JSContext *cx, void *vdata, void *thing, JSGCTraceKind traceKind,
size_t thingSize)
{
IterateData *data = static_cast<IterateData *>(vdata);
CompartmentStats *curr = data->currCompartmentStats;
RuntimeStats *rtStats = static_cast<RuntimeStats *>(vdata);
CompartmentStats *cStats = rtStats->currCompartmentStats;
switch (traceKind) {
case JSTRACE_OBJECT:
{
JSObject *obj = static_cast<JSObject *>(thing);
if (obj->isFunction()) {
curr->gcHeapObjectsFunction += thingSize;
cStats->gcHeapObjectsFunction += thingSize;
} else {
curr->gcHeapObjectsNonFunction += thingSize;
cStats->gcHeapObjectsNonFunction += thingSize;
}
size_t slotsSize, elementsSize;
obj->sizeOfExcludingThis(data->mallocSizeOf, &slotsSize, &elementsSize);
curr->objectSlots += slotsSize;
curr->objectElements += elementsSize;
obj->sizeOfExcludingThis(rtStats->mallocSizeOf, &slotsSize, &elementsSize);
cStats->objectSlots += slotsSize;
cStats->objectElements += elementsSize;
break;
}
case JSTRACE_STRING:
{
JSString *str = static_cast<JSString *>(thing);
curr->gcHeapStrings += thingSize;
curr->stringChars += str->sizeOfExcludingThis(data->mallocSizeOf);
cStats->gcHeapStrings += thingSize;
cStats->stringChars += str->sizeOfExcludingThis(rtStats->mallocSizeOf);
break;
}
case JSTRACE_SHAPE:
{
Shape *shape = static_cast<Shape*>(thing);
size_t propTableSize, kidsSize;
shape->sizeOfExcludingThis(data->mallocSizeOf, &propTableSize, &kidsSize);
shape->sizeOfExcludingThis(rtStats->mallocSizeOf, &propTableSize, &kidsSize);
if (shape->inDictionary()) {
curr->gcHeapShapesDict += thingSize;
curr->shapesExtraDictTables += propTableSize;
cStats->gcHeapShapesDict += thingSize;
cStats->shapesExtraDictTables += propTableSize;
JS_ASSERT(kidsSize == 0);
} else {
curr->gcHeapShapesTree += thingSize;
curr->shapesExtraTreeTables += propTableSize;
curr->shapesExtraTreeShapeKids += kidsSize;
cStats->gcHeapShapesTree += thingSize;
cStats->shapesExtraTreeTables += propTableSize;
cStats->shapesExtraTreeShapeKids += kidsSize;
}
break;
}
case JSTRACE_BASE_SHAPE:
{
curr->gcHeapShapesBase += thingSize;
cStats->gcHeapShapesBase += thingSize;
break;
}
case JSTRACE_SCRIPT:
{
JSScript *script = static_cast<JSScript *>(thing);
curr->gcHeapScripts += thingSize;
curr->scriptData += script->sizeOfData(data->mallocSizeOf);
cStats->gcHeapScripts += thingSize;
cStats->scriptData += script->sizeOfData(rtStats->mallocSizeOf);
#ifdef JS_METHODJIT
curr->mjitData += script->sizeOfJitScripts(data->mallocSizeOf);
cStats->mjitData += script->sizeOfJitScripts(rtStats->mallocSizeOf);
#endif
break;
}
case JSTRACE_TYPE_OBJECT:
{
types::TypeObject *obj = static_cast<types::TypeObject *>(thing);
curr->gcHeapTypeObjects += thingSize;
SizeOfTypeObjectExcludingThis(obj, &curr->typeInferenceMemory,
data->mallocSizeOf);
cStats->gcHeapTypeObjects += thingSize;
obj->sizeOfExcludingThis(&cStats->typeInferenceSizes, rtStats->mallocSizeOf);
break;
}
case JSTRACE_XML:
{
curr->gcHeapXML += thingSize;
cStats->gcHeapXML += thingSize;
break;
}
}
// Yes, this is a subtraction: see ArenaCallback() for details.
curr->gcHeapArenaUnused -= thingSize;
cStats->gcHeapArenaUnused -= thingSize;
}
JS_PUBLIC_API(bool)
CollectCompartmentStatsForRuntime(JSRuntime *rt, IterateData *data)
CollectRuntimeStats(JSRuntime *rt, RuntimeStats *rtStats)
{
JSContext *cx = JS_NewContext(rt, 0);
if (!cx)
@ -202,119 +197,110 @@ CollectCompartmentStatsForRuntime(JSRuntime *rt, IterateData *data)
{
JSAutoRequest ar(cx);
if (!data->compartmentStatsVector.reserve(rt->compartments.length()))
if (!rtStats->compartmentStatsVector.reserve(rt->compartments.length()))
return false;
data->gcHeapChunkCleanDecommitted =
rt->gcChunkPool.countCleanDecommittedArenas(rt) *
gc::ArenaSize;
data->gcHeapChunkCleanUnused =
int64_t(JS_GetGCParameter(rt, JSGC_UNUSED_CHUNKS)) *
gc::ChunkSize -
data->gcHeapChunkCleanDecommitted;
data->gcHeapChunkTotal =
int64_t(JS_GetGCParameter(rt, JSGC_TOTAL_CHUNKS)) *
gc::ChunkSize;
rtStats->gcHeapChunkCleanDecommitted =
rt->gcChunkPool.countCleanDecommittedArenas(rt) * gc::ArenaSize;
rtStats->gcHeapChunkCleanUnused =
size_t(JS_GetGCParameter(rt, JSGC_UNUSED_CHUNKS)) * gc::ChunkSize -
rtStats->gcHeapChunkCleanDecommitted;
rtStats->gcHeapChunkTotal =
size_t(JS_GetGCParameter(rt, JSGC_TOTAL_CHUNKS)) * gc::ChunkSize;
IterateCompartmentsArenasCells(cx, data, CompartmentMemoryCallback,
IterateCompartmentsArenasCells(cx, rtStats, CompartmentStatsCallback,
ArenaCallback, CellCallback);
IterateChunks(cx, data, ChunkCallback);
IterateChunks(cx, rtStats, ChunkCallback);
data->runtimeObject = data->mallocSizeOf(rt);
rtStats->runtimeObject = rtStats->mallocSizeOf(rt);
size_t normal, temporary, regexpCode, stackCommitted;
rt->sizeOfExcludingThis(data->mallocSizeOf,
&normal,
&temporary,
&regexpCode,
&stackCommitted);
data->runtimeNormal = normal;
data->runtimeTemporary = temporary;
data->runtimeRegexpCode = regexpCode;
data->runtimeStackCommitted = stackCommitted;
rt->sizeOfExcludingThis(rtStats->mallocSizeOf,
&rtStats->runtimeNormal,
&rtStats->runtimeTemporary,
&rtStats->runtimeRegexpCode,
&rtStats->runtimeStackCommitted);
// Nb: we use sizeOfExcludingThis() because atomState.atoms is within
// JSRuntime, and so counted when JSRuntime is counted.
data->runtimeAtomsTable =
rt->atomState.atoms.sizeOfExcludingThis(data->mallocSizeOf);
rtStats->runtimeAtomsTable =
rt->atomState.atoms.sizeOfExcludingThis(rtStats->mallocSizeOf);
JSContext *acx, *iter = NULL;
while ((acx = JS_ContextIteratorUnlocked(rt, &iter)) != NULL)
data->runtimeContexts += acx->sizeOfIncludingThis(data->mallocSizeOf);
rtStats->runtimeContexts += acx->sizeOfIncludingThis(rtStats->mallocSizeOf);
}
JS_DestroyContextNoGC(cx);
// This is initialized to all bytes stored in used chunks, and then we
// subtract used space from it each time around the loop.
data->gcHeapChunkDirtyUnused = data->gcHeapChunkTotal -
data->gcHeapChunkCleanUnused -
data->gcHeapChunkCleanDecommitted -
data->gcHeapChunkDirtyDecommitted;
rtStats->gcHeapChunkDirtyUnused = rtStats->gcHeapChunkTotal -
rtStats->gcHeapChunkCleanUnused -
rtStats->gcHeapChunkCleanDecommitted -
rtStats->gcHeapChunkDirtyDecommitted;
for (size_t index = 0;
index < data->compartmentStatsVector.length();
index < rtStats->compartmentStatsVector.length();
index++) {
CompartmentStats &stats = data->compartmentStatsVector[index];
CompartmentStats &cStats = rtStats->compartmentStatsVector[index];
int64_t used = stats.gcHeapArenaHeaders +
stats.gcHeapArenaPadding +
stats.gcHeapArenaUnused +
stats.gcHeapObjectsNonFunction +
stats.gcHeapObjectsFunction +
stats.gcHeapStrings +
stats.gcHeapShapesTree +
stats.gcHeapShapesDict +
stats.gcHeapShapesBase +
stats.gcHeapScripts +
stats.gcHeapTypeObjects +
stats.gcHeapXML;
size_t used = cStats.gcHeapArenaHeaders +
cStats.gcHeapArenaPadding +
cStats.gcHeapArenaUnused +
cStats.gcHeapObjectsNonFunction +
cStats.gcHeapObjectsFunction +
cStats.gcHeapStrings +
cStats.gcHeapShapesTree +
cStats.gcHeapShapesDict +
cStats.gcHeapShapesBase +
cStats.gcHeapScripts +
cStats.gcHeapTypeObjects +
cStats.gcHeapXML;
data->gcHeapChunkDirtyUnused -= used;
data->gcHeapArenaUnused += stats.gcHeapArenaUnused;
data->totalObjects += stats.gcHeapObjectsNonFunction +
stats.gcHeapObjectsFunction +
stats.objectSlots +
stats.objectElements;
data->totalShapes += stats.gcHeapShapesTree +
stats.gcHeapShapesDict +
stats.gcHeapShapesBase +
stats.shapesExtraTreeTables +
stats.shapesExtraDictTables +
stats.shapesCompartmentTables;
data->totalScripts += stats.gcHeapScripts +
stats.scriptData;
data->totalStrings += stats.gcHeapStrings +
stats.stringChars;
rtStats->gcHeapChunkDirtyUnused -= used;
rtStats->gcHeapArenaUnused += cStats.gcHeapArenaUnused;
rtStats->totalObjects += cStats.gcHeapObjectsNonFunction +
cStats.gcHeapObjectsFunction +
cStats.objectSlots +
cStats.objectElements;
rtStats->totalShapes += cStats.gcHeapShapesTree +
cStats.gcHeapShapesDict +
cStats.gcHeapShapesBase +
cStats.shapesExtraTreeTables +
cStats.shapesExtraDictTables +
cStats.shapesCompartmentTables;
rtStats->totalScripts += cStats.gcHeapScripts +
cStats.scriptData;
rtStats->totalStrings += cStats.gcHeapStrings +
cStats.stringChars;
#ifdef JS_METHODJIT
data->totalMjit += stats.mjitCode +
stats.mjitData;
rtStats->totalMjit += cStats.mjitCode +
cStats.mjitData;
#endif
data->totalTypeInference += stats.gcHeapTypeObjects +
stats.typeInferenceMemory.objects +
stats.typeInferenceMemory.scripts +
stats.typeInferenceMemory.tables;
data->totalAnalysisTemp += stats.typeInferenceMemory.temporary;
rtStats->totalTypeInference += cStats.gcHeapTypeObjects +
cStats.typeInferenceSizes.objects +
cStats.typeInferenceSizes.scripts +
cStats.typeInferenceSizes.tables;
rtStats->totalAnalysisTemp += cStats.typeInferenceSizes.temporary;
}
size_t numDirtyChunks = (data->gcHeapChunkTotal -
data->gcHeapChunkCleanUnused) /
size_t numDirtyChunks = (rtStats->gcHeapChunkTotal -
rtStats->gcHeapChunkCleanUnused) /
gc::ChunkSize;
int64_t perChunkAdmin =
size_t perChunkAdmin =
sizeof(gc::Chunk) - (sizeof(gc::Arena) * gc::ArenasPerChunk);
data->gcHeapChunkAdmin = numDirtyChunks * perChunkAdmin;
data->gcHeapChunkDirtyUnused -= data->gcHeapChunkAdmin;
rtStats->gcHeapChunkAdmin = numDirtyChunks * perChunkAdmin;
rtStats->gcHeapChunkDirtyUnused -= rtStats->gcHeapChunkAdmin;
// Why 10000x? 100x because it's a percentage, and another 100x
// because nsIMemoryReporter requires that for percentage amounts so
// they can be fractional.
data->gcHeapUnusedPercentage = (data->gcHeapChunkCleanUnused +
data->gcHeapChunkDirtyUnused +
data->gcHeapChunkCleanDecommitted +
data->gcHeapChunkDirtyDecommitted +
data->gcHeapArenaUnused) * 10000 /
data->gcHeapChunkTotal;
rtStats->gcHeapUnusedPercentage = (rtStats->gcHeapChunkCleanUnused +
rtStats->gcHeapChunkDirtyUnused +
rtStats->gcHeapChunkCleanDecommitted +
rtStats->gcHeapChunkDirtyDecommitted +
rtStats->gcHeapArenaUnused) * 10000 /
rtStats->gcHeapChunkTotal;
return true;
}

View File

@ -70,6 +70,22 @@ static bool isVFPPresent()
}
#endif
#if defined(__GNUC__) && defined(__VFP_FP__)
return true;
#endif
#ifdef WTF_OS_ANDROID
FILE *fp = fopen("/proc/cpuinfo", "r");
if (!fp)
return false;
char buf[1024];
fread(buf, sizeof(char), sizeof(buf), fp);
fclose(fp);
if (strstr(buf, "vfp"))
return true;
#endif
return false;
}

View File

@ -434,18 +434,47 @@ struct TreeContext { /* tree context for semantic checks */
return flags & TCF_FUN_MUTATES_PARAMETER;
}
void noteArgumentsUse(ParseNode *pn) {
/*
* Accessing the implicit |arguments| local binding in a function must
* trigger appropriate code generation such that the access works.
*/
void noteArgumentsNameUse(ParseNode *node) {
JS_ASSERT(inFunction());
countArgumentsUse(pn);
JS_ASSERT(node->isKind(PNK_NAME));
JS_ASSERT(node->pn_atom == parser->context->runtime->atomState.argumentsAtom);
countArgumentsUse(node);
flags |= TCF_FUN_USES_ARGUMENTS;
if (funbox)
funbox->node->pn_dflags |= PND_FUNARG;
}
void countArgumentsUse(ParseNode *pn) {
JS_ASSERT(pn->pn_atom == parser->context->runtime->atomState.argumentsAtom);
/*
* Non-dynamic accesses to a property named "arguments" inside a function
* have to deoptimize the function in case those accesses are to the
* function's arguments. (However, this is unnecessary in strict mode
* functions because of the f.arguments poison-pill. O frabjous day!)
*/
void noteArgumentsPropertyAccess(ParseNode *node) {
JS_ASSERT(inFunction());
JS_ASSERT(&node->asPropertyAccess().name() ==
parser->context->runtime->atomState.argumentsAtom);
if (!inStrictMode()) {
flags |= TCF_FUN_USES_ARGUMENTS;
if (funbox)
funbox->node->pn_dflags |= PND_FUNARG;
}
}
/*
* Uses of |arguments| must be noted so that such uses can be forbidden if
* they occur inside generator expressions (which desugar to functions and
* yields, in which |arguments| would have an entirely different meaning).
*/
void countArgumentsUse(ParseNode *node) {
JS_ASSERT(node->isKind(PNK_NAME));
JS_ASSERT(node->pn_atom == parser->context->runtime->atomState.argumentsAtom);
argumentsCount++;
argumentsNode = pn;
argumentsNode = node;
}
bool needsEagerArguments() const {

View File

@ -484,6 +484,7 @@ class BreakStatement;
class ContinueStatement;
class XMLProcessingInstruction;
class ConditionalExpression;
class PropertyAccess;
struct ParseNode {
private:
@ -927,6 +928,7 @@ struct ParseNode {
inline XMLProcessingInstruction &asXMLProcessingInstruction();
#endif
inline ConditionalExpression &asConditionalExpression();
inline PropertyAccess &asPropertyAccess();
};
struct NullaryNode : public ParseNode {
@ -1230,6 +1232,14 @@ class PropertyAccess : public ParseNode {
}
};
inline PropertyAccess &
ParseNode::asPropertyAccess()
{
JS_ASSERT(isKind(PNK_DOT));
JS_ASSERT(pn_arity == PN_NAME);
return *static_cast<PropertyAccess *>(this);
}
class PropertyByValue : public ParseNode {
public:
PropertyByValue(ParseNode *lhs, ParseNode *propExpr,

View File

@ -4393,7 +4393,7 @@ Parser::variables(ParseNodeKind kind, StaticBlockObject *blockObj, VarContext va
pn2->pn_pos.end = init->pn_pos.end;
if (tc->inFunction() && name == context->runtime->atomState.argumentsAtom) {
tc->noteArgumentsUse(pn2);
tc->noteArgumentsNameUse(pn2);
if (!blockObj)
tc->flags |= TCF_FUN_HEAVYWEIGHT;
}
@ -5746,11 +5746,21 @@ Parser::memberExpr(JSBool allowCallSyntax)
} else
#endif
{
nextMember = new_<PropertyAccess>(lhs, tokenStream.currentToken().name(),
PropertyName *field = tokenStream.currentToken().name();
nextMember = new_<PropertyAccess>(lhs, field,
lhs->pn_pos.begin,
tokenStream.currentToken().pos.end);
if (!nextMember)
return NULL;
/*
* A property access of the form |<expr>.arguments| might
* access this function's arguments, so we need to flag a
* potential arguments use to ensure an arguments object
* will be created. See bug 721322.
*/
if (tc->inFunction() && field == context->runtime->atomState.argumentsAtom)
tc->noteArgumentsPropertyAccess(nextMember);
}
}
#if JS_HAS_XML_SUPPORT
@ -6614,7 +6624,7 @@ Parser::propertyQualifiedIdentifier()
#endif
ParseNode *
Parser::identifierName(bool afterDot)
Parser::identifierName(bool afterDoubleDot)
{
JS_ASSERT(tokenStream.isCurrentTokenType(TOK_NAME));
@ -6626,26 +6636,25 @@ Parser::identifierName(bool afterDot)
node->setOp(JSOP_NAME);
if ((tc->flags & (TCF_IN_FUNCTION | TCF_FUN_PARAM_ARGUMENTS)) == TCF_IN_FUNCTION &&
name == context->runtime->atomState.argumentsAtom) {
/*
* Flag arguments usage so we can avoid unsafe optimizations such
* as formal parameter assignment analysis (because of the hated
* feature whereby arguments alias formals). We do this even for
* a reference of the form foo.arguments, which ancient code may
* still use instead of arguments (more hate).
*/
tc->noteArgumentsUse(node);
name == context->runtime->atomState.argumentsAtom)
{
/*
* Bind early to JSOP_ARGUMENTS to relieve later code from having
* to do this work (new rule for the emitter to count on).
*/
if (!afterDot && !(tc->flags & TCF_DECL_DESTRUCTURING)
&& !tc->inStatement(STMT_WITH)) {
node->setOp(JSOP_ARGUMENTS);
node->pn_dflags |= PND_BOUND;
if (!afterDoubleDot) {
/*
* Note use of |arguments| to ensure we can properly create the
* |arguments| object for this function.
*/
tc->noteArgumentsNameUse(node);
if (!(tc->flags & TCF_DECL_DESTRUCTURING) && !tc->inStatement(STMT_WITH)) {
node->setOp(JSOP_ARGUMENTS);
node->pn_dflags |= PND_BOUND;
}
}
} else if ((!afterDot
} else if ((!afterDoubleDot
#if JS_HAS_XML_SUPPORT
|| (!tc->inStrictMode() && tokenStream.peekToken() == TOK_DBLCOLON)
#endif
@ -6708,7 +6717,7 @@ Parser::identifierName(bool afterDot)
#if JS_HAS_XML_SUPPORT
if (!tc->inStrictMode() && tokenStream.matchToken(TOK_DBLCOLON)) {
if (afterDot) {
if (afterDoubleDot) {
if (!checkForFunctionNode(name, node))
return NULL;
}
@ -6735,7 +6744,7 @@ Parser::starOrAtPropertyIdentifier(TokenKind tt)
#endif
ParseNode *
Parser::primaryExpr(TokenKind tt, JSBool afterDot)
Parser::primaryExpr(TokenKind tt, bool afterDoubleDot)
{
JS_ASSERT(tokenStream.isCurrentTokenType(tt));
@ -7168,7 +7177,7 @@ Parser::primaryExpr(TokenKind tt, JSBool afterDot)
#endif
case TOK_NAME:
pn = identifierName(afterDot);
pn = identifierName(afterDoubleDot);
break;
case TOK_REGEXP:

View File

@ -234,7 +234,7 @@ struct Parser : private AutoGCRooter
ParseNode *mulExpr1n();
ParseNode *unaryExpr();
ParseNode *memberExpr(JSBool allowCallSyntax);
ParseNode *primaryExpr(TokenKind tt, JSBool afterDot);
ParseNode *primaryExpr(TokenKind tt, bool afterDoubleDot);
ParseNode *parenExpr(JSBool *genexp = NULL);
/*
@ -259,7 +259,7 @@ struct Parser : private AutoGCRooter
bool checkForFunctionNode(PropertyName *name, ParseNode *node);
ParseNode *identifierName(bool afterDot);
ParseNode *identifierName(bool afterDoubleDot);
#if JS_HAS_XML_SUPPORT
ParseNode *endBracketedExpr();

View File

@ -0,0 +1,6 @@
function f()
{
var x = <><arguments/><arguments/></>;
x..arguments;
}
f();

View File

@ -0,0 +1,8 @@
array1 = new Array();
size = 10;
for (i = 0; i < size; (array1.length)++)
{
array1.push(array1.shift());
++i
}

View File

@ -0,0 +1,13 @@
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/
*/
function testProperty(i)
{
actual = obj[String(i)];
}
var obj = {};
var index = [null, 1073741824, 1073741825];
for (var j in index)
testProperty(index[j]);

View File

@ -765,7 +765,6 @@ JSRuntime::JSRuntime()
data(NULL),
#ifdef JS_THREADSAFE
gcLock(NULL),
requestCount(0),
gcHelperThread(thisFromCtor()),
#endif
debuggerMutations(0),
@ -1013,10 +1012,9 @@ StartRequest(JSContext *cx)
AutoLockGC lock(rt);
/* Indicate that a request is running. */
rt->requestCount++;
rt->requestDepth = 1;
if (rt->requestCount == 1 && rt->activityCallback)
if (rt->activityCallback)
rt->activityCallback(rt->activityCallbackArg, true);
}
}
@ -1037,13 +1035,8 @@ StopRequest(JSContext *cx)
rt->requestDepth = 0;
/* Give the GC a chance to run if this was the last request running. */
JS_ASSERT(rt->requestCount > 0);
rt->requestCount--;
if (rt->requestCount == 0) {
if (rt->activityCallback)
rt->activityCallback(rt->activityCallbackArg, false);
}
if (rt->activityCallback)
rt->activityCallback(rt->activityCallbackArg, false);
}
}
#endif /* JS_THREADSAFE */
@ -2216,7 +2209,7 @@ JS_free(JSContext *cx, void *p)
JS_PUBLIC_API(void)
JS_updateMallocCounter(JSContext *cx, size_t nbytes)
{
return cx->runtime->updateMallocCounter(nbytes);
return cx->runtime->updateMallocCounter(cx, nbytes);
}
JS_PUBLIC_API(char *)

View File

@ -2506,7 +2506,7 @@ mjit::stubs::ArrayShift(VMFrame &f)
* themselves.
*/
uint32_t initlen = obj->getDenseArrayInitializedLength();
obj->moveDenseArrayElements(0, 1, initlen);
obj->moveDenseArrayElementsUnbarriered(0, 1, initlen);
}
#endif /* JS_METHODJIT */
@ -2533,7 +2533,7 @@ js::array_shift(JSContext *cx, uintN argc, Value *vp)
args.rval() = obj->getDenseArrayElement(0);
if (args.rval().isMagic(JS_ARRAY_HOLE))
args.rval().setUndefined();
obj->moveDenseArrayElements(0, 1, length);
obj->moveDenseArrayElements(0, 1, obj->getDenseArrayInitializedLength() - 1);
obj->setDenseArrayInitializedLength(obj->getDenseArrayInitializedLength() - 1);
obj->setArrayLength(cx, length);
if (!js_SuppressDeletedProperty(cx, obj, INT_TO_JSID(length)))

View File

@ -245,13 +245,7 @@ js_DestroyContext(JSContext *cx, JSDestroyContextMode mode)
JS_ASSERT(!cx->enumerators);
#ifdef JS_THREADSAFE
/*
* For API compatibility we support destroying contexts with non-zero
* cx->outstandingRequests but we assume that all JS_BeginRequest calls
* on this cx contributes to cx->thread->data.requestDepth and there is no
* JS_SuspendRequest calls that set aside the counter.
*/
JS_ASSERT(cx->outstandingRequests <= cx->runtime->requestDepth);
JS_ASSERT(cx->outstandingRequests == 0);
#endif
if (mode != JSDCM_NEW_FAILED) {
@ -268,11 +262,7 @@ js_DestroyContext(JSContext *cx, JSDestroyContextMode mode)
JS_LOCK_GC(rt);
JS_REMOVE_LINK(&cx->link);
bool last = !rt->hasContexts();
if (last || mode == JSDCM_FORCE_GC || mode == JSDCM_MAYBE_GC
#ifdef JS_THREADSAFE
|| cx->outstandingRequests != 0
#endif
) {
if (last || mode == JSDCM_FORCE_GC || mode == JSDCM_MAYBE_GC) {
JS_ASSERT(!rt->gcRunning);
#ifdef JS_THREADSAFE
@ -281,16 +271,6 @@ js_DestroyContext(JSContext *cx, JSDestroyContextMode mode)
JS_UNLOCK_GC(rt);
if (last) {
#ifdef JS_THREADSAFE
/*
* If this thread is not in a request already, begin one now so
* that we wait for any racing GC started on a not-last context to
* finish, before we plow ahead and unpin atoms.
*/
if (cx->runtime->requestDepth == 0)
JS_BeginRequest(cx);
#endif
/*
* Dump remaining type inference results first. This printing
* depends on atoms still existing.
@ -308,27 +288,15 @@ js_DestroyContext(JSContext *cx, JSDestroyContextMode mode)
for (CompartmentsIter c(rt); !c.done(); c.next())
c->clearTraps(cx);
JS_ClearAllWatchPoints(cx);
}
#ifdef JS_THREADSAFE
/* Destroying a context implicitly calls JS_EndRequest(). */
while (cx->outstandingRequests != 0)
JS_EndRequest(cx);
#endif
if (last) {
js_GC(cx, NULL, GC_NORMAL, gcreason::LAST_CONTEXT);
/* Take the runtime down, now that it has no contexts or atoms. */
JS_LOCK_GC(rt);
} else {
if (mode == JSDCM_FORCE_GC)
js_GC(cx, NULL, GC_NORMAL, gcreason::DESTROY_CONTEXT);
else if (mode == JSDCM_MAYBE_GC)
JS_MaybeGC(cx);
JS_LOCK_GC(rt);
} else if (mode == JSDCM_FORCE_GC) {
js_GC(cx, NULL, GC_NORMAL, gcreason::DESTROY_CONTEXT);
} else if (mode == JSDCM_MAYBE_GC) {
JS_MaybeGC(cx);
}
JS_LOCK_GC(rt);
}
#ifdef JS_THREADSAFE
rt->gcHelperThread.waitBackgroundSweepEnd();
@ -352,21 +320,6 @@ js_ContextIterator(JSRuntime *rt, JSBool unlocked, JSContext **iterp)
return cx;
}
JS_FRIEND_API(JSContext *)
js_NextActiveContext(JSRuntime *rt, JSContext *cx)
{
JSContext *iter = cx;
#ifdef JS_THREADSAFE
while ((cx = js_ContextIterator(rt, JS_FALSE, &iter)) != NULL) {
if (cx->outstandingRequests && cx->runtime->requestDepth)
break;
}
return cx;
#else
return js_ContextIterator(rt, JS_FALSE, &iter);
#endif
}
namespace js {
bool
@ -1170,6 +1123,19 @@ JSContext::runningWithTrustedPrincipals() const
return !compartment || compartment->principals == runtime->trustedPrincipals();
}
void
JSRuntime::updateMallocCounter(JSContext *cx, size_t nbytes)
{
/* We tolerate any thread races when updating gcMallocBytes. */
ptrdiff_t oldCount = gcMallocBytes;
ptrdiff_t newCount = oldCount - ptrdiff_t(nbytes);
gcMallocBytes = newCount;
if (JS_UNLIKELY(newCount <= 0 && oldCount > 0))
onTooMuchMalloc();
else if (cx && cx->compartment)
cx->compartment->updateMallocCounter(nbytes);
}
JS_FRIEND_API(void)
JSRuntime::onTooMuchMalloc()
{

View File

@ -453,7 +453,6 @@ struct JSRuntime
#ifdef JS_THREADSAFE
/* These combine to interlock the GC and new requests. */
PRLock *gcLock;
uint32_t requestCount;
js::GCHelperThread gcHelperThread;
#endif /* JS_THREADSAFE */
@ -559,7 +558,7 @@ struct JSRuntime
* reporting OOM error when cx is not null. We will not GC from here.
*/
void* malloc_(size_t bytes, JSContext *cx = NULL) {
updateMallocCounter(bytes);
updateMallocCounter(cx, bytes);
void *p = ::js_malloc(bytes);
return JS_LIKELY(!!p) ? p : onOutOfMemory(NULL, bytes, cx);
}
@ -569,14 +568,14 @@ struct JSRuntime
* reporting OOM error when cx is not null. We will not GC from here.
*/
void* calloc_(size_t bytes, JSContext *cx = NULL) {
updateMallocCounter(bytes);
updateMallocCounter(cx, bytes);
void *p = ::js_calloc(bytes);
return JS_LIKELY(!!p) ? p : onOutOfMemory(reinterpret_cast<void *>(1), bytes, cx);
}
void* realloc_(void* p, size_t oldBytes, size_t newBytes, JSContext *cx = NULL) {
JS_ASSERT(oldBytes < newBytes);
updateMallocCounter(newBytes - oldBytes);
updateMallocCounter(cx, newBytes - oldBytes);
void *p2 = ::js_realloc(p, newBytes);
return JS_LIKELY(!!p2) ? p2 : onOutOfMemory(p, newBytes, cx);
}
@ -587,7 +586,7 @@ struct JSRuntime
* previously allocated memory.
*/
if (!p)
updateMallocCounter(bytes);
updateMallocCounter(cx, bytes);
void *p2 = ::js_realloc(p, bytes);
return JS_LIKELY(!!p2) ? p2 : onOutOfMemory(p, bytes, cx);
}
@ -621,13 +620,7 @@ struct JSRuntime
* The function must be called outside the GC lock and in case of OOM error
* the caller must ensure that no deadlock possible during OOM reporting.
*/
void updateMallocCounter(size_t nbytes) {
/* We tolerate any thread races when updating gcMallocBytes. */
ptrdiff_t newCount = gcMallocBytes - ptrdiff_t(nbytes);
gcMallocBytes = newCount;
if (JS_UNLIKELY(newCount <= 0))
onTooMuchMalloc();
}
void updateMallocCounter(JSContext *cx, size_t nbytes);
/*
* The function must be called outside the GC lock.
@ -1364,14 +1357,6 @@ js_DestroyContext(JSContext *cx, JSDestroyContextMode mode);
extern JSContext *
js_ContextIterator(JSRuntime *rt, JSBool unlocked, JSContext **iterp);
/*
* Iterate through contexts with active requests. The caller must be holding
* rt->gcLock in case of a thread-safe build, or otherwise guarantee that the
* context list is not alternated asynchroniously.
*/
extern JS_FRIEND_API(JSContext *)
js_NextActiveContext(JSRuntime *, JSContext *);
#ifdef va_start
extern JSBool
js_ReportErrorVA(JSContext *cx, uintN flags, const char *format, va_list ap);

View File

@ -92,6 +92,7 @@ JSCompartment::JSCompartment(JSRuntime *rt)
watchpointMap(NULL)
{
PodArrayZero(evalCache);
setGCMaxMallocBytes(rt->gcMaxMallocBytes * 0.9);
}
JSCompartment::~JSCompartment()
@ -569,6 +570,30 @@ JSCompartment::purge(JSContext *cx)
toSourceCache.destroyIfConstructed();
}
void
JSCompartment::resetGCMallocBytes()
{
gcMallocBytes = ptrdiff_t(gcMaxMallocBytes);
}
void
JSCompartment::setGCMaxMallocBytes(size_t value)
{
/*
* For compatibility treat any value that exceeds PTRDIFF_T_MAX to
* mean that value.
*/
gcMaxMallocBytes = (ptrdiff_t(value) >= 0) ? value : size_t(-1) >> 1;
resetGCMallocBytes();
}
void
JSCompartment::onTooMuchMalloc()
{
TriggerCompartmentGC(this, gcreason::TOO_MUCH_MALLOC);
}
MathCache *
JSCompartment::allocMathCache(JSContext *cx)
{
@ -745,10 +770,10 @@ JSCompartment::createBarrierTracer()
}
size_t
JS::SizeOfCompartmentShapeTable(JSCompartment *c, JSMallocSizeOfFun mallocSizeOf)
JSCompartment::sizeOfShapeTable(JSMallocSizeOfFun mallocSizeOf)
{
return c->baseShapes.sizeOfExcludingThis(mallocSizeOf)
+ c->initialShapes.sizeOfExcludingThis(mallocSizeOf)
+ c->newTypeObjects.sizeOfExcludingThis(mallocSizeOf)
+ c->lazyTypeObjects.sizeOfExcludingThis(mallocSizeOf);
return baseShapes.sizeOfExcludingThis(mallocSizeOf)
+ initialShapes.sizeOfExcludingThis(mallocSizeOf)
+ newTypeObjects.sizeOfExcludingThis(mallocSizeOf)
+ lazyTypeObjects.sizeOfExcludingThis(mallocSizeOf);
}

View File

@ -164,6 +164,10 @@ typedef HashSet<ScriptFilenameEntry *,
} /* namespace js */
namespace JS {
struct TypeInferenceSizes;
}
struct JSCompartment
{
JSRuntime *rt;
@ -188,6 +192,7 @@ struct JSCompartment
size_t gcBytes;
size_t gcTriggerBytes;
size_t gcLastBytes;
size_t gcMaxMallocBytes;
bool hold;
bool isSystemCompartment;
@ -239,6 +244,10 @@ struct JSCompartment
size_t sizeOfMjitCode() const;
#endif
size_t sizeOfShapeTable(JSMallocSizeOfFun mallocSizeOf);
void sizeOfTypeInferenceData(JSContext *cx, JS::TypeInferenceSizes *stats,
JSMallocSizeOfFun mallocSizeOf);
/*
* Shared scope property tree, and arena-pool for allocating its nodes.
*/
@ -279,6 +288,12 @@ struct JSCompartment
enum { DebugFromC = 1, DebugFromJS = 2 };
uintN debugModeBits; // see debugMode() below
/*
* Malloc counter to measure memory pressure for GC scheduling. It runs
* from gcMaxMallocBytes down to zero.
*/
volatile ptrdiff_t gcMallocBytes;
public:
js::NativeIterCache nativeIterCache;
@ -312,6 +327,18 @@ struct JSCompartment
void setGCLastBytes(size_t lastBytes, JSGCInvocationKind gckind);
void reduceGCTriggerBytes(size_t amount);
void resetGCMallocBytes();
void setGCMaxMallocBytes(size_t value);
void updateMallocCounter(size_t nbytes) {
ptrdiff_t oldCount = gcMallocBytes;
ptrdiff_t newCount = oldCount - ptrdiff_t(nbytes);
gcMallocBytes = newCount;
if (JS_UNLIKELY(newCount <= 0 && oldCount > 0))
onTooMuchMalloc();
}
void onTooMuchMalloc();
js::DtoaCache dtoaCache;

View File

@ -2850,6 +2850,16 @@ MarkAndSweep(JSContext *cx, JSGCInvocationKind gckind)
/* Clear gcIsNeeded now, when we are about to start a normal GC cycle. */
rt->gcIsNeeded = false;
rt->gcTriggerCompartment = NULL;
/* Clear gcMallocBytes for all compartments */
JSCompartment **read = rt->compartments.begin();
JSCompartment **end = rt->compartments.end();
JS_ASSERT(rt->compartments.length() >= 1);
while (read < end) {
JSCompartment *compartment = *read++;
compartment->resetGCMallocBytes();
}
/* Reset weak map list. */
WeakMapBase::resetWeakMapList(rt);

View File

@ -6258,12 +6258,12 @@ TypeScript::destroy()
}
inline size_t
TypeSet::dynamicSize()
TypeSet::computedSizeOfExcludingThis()
{
/*
* This memory is allocated within the temp pool (but accounted for
* elsewhere) so we can't use a JSMallocSizeOfFun to measure it. We must
* do it analytically.
* compute its size analytically.
*/
uint32_t count = baseObjectCount();
if (count >= 2)
@ -6272,12 +6272,12 @@ TypeSet::dynamicSize()
}
inline size_t
TypeObject::dynamicSize()
TypeObject::computedSizeOfExcludingThis()
{
/*
* This memory is allocated within the temp pool (but accounted for
* elsewhere) so we can't use a JSMallocSizeOfFun to measure it. We must
* do it analytically.
* compute its size analytically.
*/
size_t bytes = 0;
@ -6289,14 +6289,15 @@ TypeObject::dynamicSize()
for (unsigned i = 0; i < count; i++) {
Property *prop = getProperty(i);
if (prop)
bytes += sizeof(Property) + prop->types.dynamicSize();
bytes += sizeof(Property) + prop->types.computedSizeOfExcludingThis();
}
return bytes;
}
static void
GetScriptMemoryStats(JSScript *script, TypeInferenceMemoryStats *stats, JSMallocSizeOfFun mallocSizeOf)
SizeOfScriptTypeInferenceData(JSScript *script, TypeInferenceSizes *sizes,
JSMallocSizeOfFun mallocSizeOf)
{
TypeScript *typeScript = script->types;
if (!typeScript)
@ -6304,18 +6305,18 @@ GetScriptMemoryStats(JSScript *script, TypeInferenceMemoryStats *stats, JSMalloc
/* If TI is disabled, a single TypeScript is still present. */
if (!script->compartment()->types.inferenceEnabled) {
stats->scripts += mallocSizeOf(typeScript);
sizes->scripts += mallocSizeOf(typeScript);
return;
}
stats->scripts += mallocSizeOf(typeScript->nesting);
sizes->scripts += mallocSizeOf(typeScript->nesting);
unsigned count = TypeScript::NumTypeSets(script);
stats->scripts += mallocSizeOf(typeScript);
sizes->scripts += mallocSizeOf(typeScript);
TypeResult *result = typeScript->dynamicList;
while (result) {
stats->scripts += mallocSizeOf(result);
sizes->scripts += mallocSizeOf(result);
result = result->next;
}
@ -6325,15 +6326,14 @@ GetScriptMemoryStats(JSScript *script, TypeInferenceMemoryStats *stats, JSMalloc
*/
TypeSet *typeArray = typeScript->typeArray();
for (unsigned i = 0; i < count; i++) {
size_t bytes = typeArray[i].dynamicSize();
stats->scripts += bytes;
stats->temporary -= bytes;
size_t bytes = typeArray[i].computedSizeOfExcludingThis();
sizes->scripts += bytes;
sizes->temporary -= bytes;
}
}
void
JS::SizeOfCompartmentTypeInferenceData(JSContext *cx, JSCompartment *compartment,
TypeInferenceMemoryStats *stats,
JSCompartment::sizeOfTypeInferenceData(JSContext *cx, TypeInferenceSizes *sizes,
JSMallocSizeOfFun mallocSizeOf)
{
/*
@ -6341,28 +6341,27 @@ JS::SizeOfCompartmentTypeInferenceData(JSContext *cx, JSCompartment *compartment
* by being copied to the replacement pool. This memory will be counted
* elsewhere and deducted from the amount of temporary data.
*/
stats->temporary += compartment->typeLifoAlloc.sizeOfExcludingThis(mallocSizeOf);
sizes->temporary += typeLifoAlloc.sizeOfExcludingThis(mallocSizeOf);
/* Pending arrays are cleared on GC along with the analysis pool. */
stats->temporary +=
mallocSizeOf(compartment->types.pendingArray);
sizes->temporary += mallocSizeOf(types.pendingArray);
/* TypeCompartment::pendingRecompiles is non-NULL only while inference code is running. */
JS_ASSERT(!compartment->types.pendingRecompiles);
JS_ASSERT(!types.pendingRecompiles);
for (gc::CellIter i(cx, compartment, gc::FINALIZE_SCRIPT); !i.done(); i.next())
GetScriptMemoryStats(i.get<JSScript>(), stats, mallocSizeOf);
for (gc::CellIter i(cx, this, gc::FINALIZE_SCRIPT); !i.done(); i.next())
SizeOfScriptTypeInferenceData(i.get<JSScript>(), sizes, mallocSizeOf);
if (compartment->types.allocationSiteTable)
stats->tables += compartment->types.allocationSiteTable->sizeOfIncludingThis(mallocSizeOf);
if (types.allocationSiteTable)
sizes->tables += types.allocationSiteTable->sizeOfIncludingThis(mallocSizeOf);
if (compartment->types.arrayTypeTable)
stats->tables += compartment->types.arrayTypeTable->sizeOfIncludingThis(mallocSizeOf);
if (types.arrayTypeTable)
sizes->tables += types.arrayTypeTable->sizeOfIncludingThis(mallocSizeOf);
if (compartment->types.objectTypeTable) {
stats->tables += compartment->types.objectTypeTable->sizeOfIncludingThis(mallocSizeOf);
if (types.objectTypeTable) {
sizes->tables += types.objectTypeTable->sizeOfIncludingThis(mallocSizeOf);
for (ObjectTypeTable::Enum e(*compartment->types.objectTypeTable);
for (ObjectTypeTable::Enum e(*types.objectTypeTable);
!e.empty();
e.popFront())
{
@ -6370,34 +6369,31 @@ JS::SizeOfCompartmentTypeInferenceData(JSContext *cx, JSCompartment *compartment
const ObjectTableEntry &value = e.front().value;
/* key.ids and values.types have the same length. */
stats->tables += mallocSizeOf(key.ids) + mallocSizeOf(value.types);
sizes->tables += mallocSizeOf(key.ids) + mallocSizeOf(value.types);
}
}
}
void
JS::SizeOfTypeObjectExcludingThis(void *object_, TypeInferenceMemoryStats *stats, JSMallocSizeOfFun mallocSizeOf)
TypeObject::sizeOfExcludingThis(TypeInferenceSizes *sizes, JSMallocSizeOfFun mallocSizeOf)
{
TypeObject *object = (TypeObject *) object_;
if (object->singleton) {
if (singleton) {
/*
* Properties and associated type sets for singletons are cleared on
* every GC. The type object is normally destroyed too, but we don't
* charge this to 'temporary' as this is not for GC heap values.
*/
JS_ASSERT(!object->newScript);
JS_ASSERT(!newScript);
return;
}
if (object->newScript)
stats->objects += mallocSizeOf(object->newScript);
sizes->objects += mallocSizeOf(newScript);
/*
* This counts memory that is in the temp pool but gets attributed
* elsewhere. See JS_GetTypeInferenceMemoryStats for more details.
* elsewhere. See JSCompartment::sizeOfTypeInferenceData for more details.
*/
size_t bytes = object->dynamicSize();
stats->objects += bytes;
stats->temporary -= bytes;
size_t bytes = computedSizeOfExcludingThis();
sizes->objects += bytes;
sizes->temporary -= bytes;
}

View File

@ -51,6 +51,10 @@
#include "gc/Barrier.h"
#include "js/HashTable.h"
namespace JS {
struct TypeInferenceSizes;
}
namespace js {
namespace types {
@ -366,7 +370,7 @@ class TypeSet
void print(JSContext *cx);
inline void sweep(JSContext *cx, JSCompartment *compartment);
inline size_t dynamicSize();
inline size_t computedSizeOfExcludingThis();
/* Whether this set contains a specific type. */
inline bool hasType(Type type);
@ -865,7 +869,9 @@ struct TypeObject : gc::Cell
inline void clearProperties();
inline void sweep(JSContext *cx);
inline size_t dynamicSize();
inline size_t computedSizeOfExcludingThis();
void sizeOfExcludingThis(TypeInferenceSizes *sizes, JSMallocSizeOfFun mallocSizeOf);
/*
* Type objects don't have explicit finalizers. Memory owned by a type

View File

@ -1066,6 +1066,7 @@ struct JSObject : js::gc::Cell
inline void copyDenseArrayElements(uintN dstStart, const js::Value *src, uintN count);
inline void initDenseArrayElements(uintN dstStart, const js::Value *src, uintN count);
inline void moveDenseArrayElements(uintN dstStart, uintN srcStart, uintN count);
inline void moveDenseArrayElementsUnbarriered(uintN dstStart, uintN srcStart, uintN count);
inline bool denseArrayHasInlineSlots() const;
/* Packed information for this array. */

View File

@ -607,7 +607,7 @@ inline void
JSObject::moveDenseArrayElements(uintN dstStart, uintN srcStart, uintN count)
{
JS_ASSERT(dstStart + count <= getDenseArrayCapacity());
JS_ASSERT(srcStart + count <= getDenseArrayCapacity());
JS_ASSERT(srcStart + count <= getDenseArrayInitializedLength());
/*
* Use a custom write barrier here since it's performance sensitive. We
@ -626,6 +626,13 @@ JSObject::moveDenseArrayElements(uintN dstStart, uintN srcStart, uintN count)
memmove(elements + dstStart, elements + srcStart, count * sizeof(js::Value));
}
inline void
JSObject::moveDenseArrayElementsUnbarriered(uintN dstStart, uintN srcStart, uintN count)
{
JS_ASSERT(!compartment()->needsBarrier());
memmove(elements + dstStart, elements + srcStart, count * sizeof(js::Value));
}
inline bool
JSObject::denseArrayHasInlineSlots() const
{

View File

@ -2607,7 +2607,8 @@ GetElementIC::update(VMFrame &f, JSObject *obj, const Value &v, jsid id, Value *
* indexes in the emitter, i.e. js_GetProtoIfDenseArray is only valid to
* use when looking up non-integer identifiers.
*/
if (v.isString() && js_CheckForStringIndex(id) == id)
uint32_t dummy;
if (v.isString() && JSID_IS_ATOM(id) && !JSID_TO_ATOM(id)->isIndex(&dummy))
return attachGetProp(f, obj, v, JSID_TO_ATOM(id)->asPropertyName(), vp);
if (obj->isArguments())

View File

@ -3888,15 +3888,6 @@ MJitChunkLimit(JSContext *cx, uintN argc, jsval *vp)
return true;
}
JSBool
StringStats(JSContext *cx, uintN argc, jsval *vp)
{
// XXX: should report something meaningful; bug 625305 will probably fix
// this.
JS_SET_RVAL(cx, vp, INT_TO_JSVAL(0));
return true;
}
enum CompartmentKind { SAME_COMPARTMENT, NEW_COMPARTMENT };
static JSObject *
@ -4062,7 +4053,6 @@ static JSFunctionSpec shell_functions[] = {
JS_FN("mjitcodestats", MJitCodeStats, 0,0),
#endif
JS_FN("mjitChunkLimit", MJitChunkLimit, 1,0),
JS_FN("stringstats", StringStats, 0,0),
JS_FN("newGlobal", NewGlobal, 1,0),
JS_FN("parseLegacyJSON",ParseLegacyJSON,1,0),
JS_FN("enableStackWalkingAssertion",EnableStackWalkingAssertion,1,0),
@ -4211,7 +4201,6 @@ static const char *const shell_help_messages[] = {
"mjitcodestats() Return stats on mjit code memory usage.",
#endif
"mjitChunkLimit(N) Specify limit on compiled chunk size during mjit compilation.",
"stringstats() Return stats on string memory usage.",
"newGlobal(kind) Return a new global object, in the current\n"
" compartment if kind === 'same-compartment' or in a\n"
" new compartment if kind === 'new-compartment'",

View File

@ -0,0 +1,58 @@
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/
* Contributor:
* Jeff Walden <jwalden+code@mit.edu>
*/
//-----------------------------------------------------------------------------
var BUGNUMBER = 721322;
var summary =
'f.arguments must trigger an arguments object in non-strict mode functions';
print(BUGNUMBER + ": " + summary);
/**************
* BEGIN TEST *
**************/
var obj =
{
test: function()
{
var args = obj.test.arguments;
assertEq(args !== null, true);
assertEq(args[0], 5);
assertEq(args[1], undefined);
assertEq(args.length, 2);
}
};
obj.test(5, undefined);
var sobj =
{
test: function()
{
"use strict";
try
{
var args = sobj.test.arguments;
throw new Error("access to arguments property of strict mode " +
"function didn't throw");
}
catch (e)
{
assertEq(e instanceof TypeError, true,
"should have thrown TypeError, instead got: " + e);
}
}
};
sobj.test(5, undefined);
/******************************************************************************/
if (typeof reportCompare === "function")
reportCompare(true, true);
print("Tests complete");

View File

@ -1,4 +1,5 @@
url-prefix ../../jsreftest.html?test=ecma_5/extensions/
script arguments-property-access-in-function.js
script 8.12.5-01.js
script 15.4.4.11.js
script 15.9.4.2.js

View File

@ -0,0 +1,27 @@
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/
* Contributor:
* Jeff Walden <jwalden+code@mit.edu>
*/
//-----------------------------------------------------------------------------
var BUGNUMBER = 721322;
var summary = 'Allow f.arguments in generator expressions';
print(BUGNUMBER + ": " + summary);
/**************
* BEGIN TEST *
**************/
eval("(function() { return (f.arguments for (x in [1])); })()");
eval("(function() { var f = { arguments: 12 }; return [f.arguments for (x in [1])]; })()");
/******************************************************************************/
if (typeof reportCompare === "function")
reportCompare(true, true);
print("Tests complete");

View File

@ -1,4 +1,5 @@
url-prefix ../../jsreftest.html?test=js1_8/genexps/
script arguments-property-access-in-generator.js
script regress-347739.js
script regress-349012-01.js
script regress-349326.js

View File

@ -249,7 +249,7 @@ JSExternalString::new_(JSContext *cx, const jschar *chars, size_t length, intN t
if (!str)
return NULL;
str->init(chars, length, type, closure);
cx->runtime->updateMallocCounter((length + 1) * sizeof(jschar));
cx->runtime->updateMallocCounter(cx, (length + 1) * sizeof(jschar));
return str;
}

View File

@ -2012,6 +2012,7 @@ main(int argc, char **argv, char **envp)
cxstack = nsnull;
JS_GC(cx);
} //this scopes the JSAutoCrossCompartmentCall
JS_EndRequest(cx);
JS_DestroyContext(cx);
} // this scopes the nsCOMPtrs

View File

@ -1350,11 +1350,11 @@ ReportMemoryPercentage(const nsACString &path, PRInt32 kind, PRInt64 amount,
template <int N>
inline const nsCString
MakeMemoryReporterPath(const nsACString &pathPrefix,
const JS::CompartmentStats &compartmentStats,
const JS::CompartmentStats &cStats,
const char (&reporterName)[N])
{
return pathPrefix + NS_LITERAL_CSTRING("compartment(") +
*static_cast<nsCString*>(compartmentStats.name) +
*static_cast<nsCString*>(cStats.name) +
NS_LITERAL_CSTRING(")/") + nsDependentCString(reporterName);
}
@ -1421,56 +1421,53 @@ namespace mozilla {
namespace xpconnect {
namespace memory {
#define SLOP_BYTES_STRING \
" The measurement includes slop bytes caused by the heap allocator rounding up request sizes."
static PRInt64
ReportCompartmentStats(const JS::CompartmentStats &stats,
ReportCompartmentStats(const JS::CompartmentStats &cStats,
const nsACString &pathPrefix,
nsIMemoryMultiReporterCallback *callback,
nsISupports *closure)
{
PRInt64 gcTotal = 0;
ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, stats,
ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, cStats,
"gc-heap/arena/headers"),
&gcTotal, stats.gcHeapArenaHeaders,
&gcTotal, cStats.gcHeapArenaHeaders,
"Memory on the compartment's garbage-collected JavaScript heap, within "
"arenas, that is used to hold internal book-keeping information.",
callback, closure);
ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, stats,
ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, cStats,
"gc-heap/arena/padding"),
&gcTotal, stats.gcHeapArenaPadding,
&gcTotal, cStats.gcHeapArenaPadding,
"Memory on the compartment's garbage-collected JavaScript heap, within "
"arenas, that is unused and present only so that other data is aligned. "
"This constitutes internal fragmentation.",
callback, closure);
ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, stats,
ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, cStats,
"gc-heap/arena/unused"),
&gcTotal, stats.gcHeapArenaUnused,
&gcTotal, cStats.gcHeapArenaUnused,
"Memory on the compartment's garbage-collected JavaScript heap, within "
"arenas, that could be holding useful data but currently isn't.",
callback, closure);
ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, stats,
ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, cStats,
"gc-heap/objects/non-function"),
&gcTotal, stats.gcHeapObjectsNonFunction,
&gcTotal, cStats.gcHeapObjectsNonFunction,
"Memory on the compartment's garbage-collected JavaScript heap that holds "
"non-function objects.",
callback, closure);
ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, stats,
ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, cStats,
"gc-heap/objects/function"),
&gcTotal, stats.gcHeapObjectsFunction,
&gcTotal, cStats.gcHeapObjectsFunction,
"Memory on the compartment's garbage-collected JavaScript heap that holds "
"function objects.",
callback, closure);
ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, stats,
ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, cStats,
"gc-heap/strings"),
&gcTotal, stats.gcHeapStrings,
&gcTotal, cStats.gcHeapStrings,
"Memory on the compartment's garbage-collected JavaScript heap that holds "
"string headers. String headers contain various pieces of information "
"about a string, but do not contain (except in the case of very short "
@ -1478,69 +1475,69 @@ ReportCompartmentStats(const JS::CompartmentStats &stats,
"under 'gc-heap/string-chars' instead.",
callback, closure);
ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, stats,
ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, cStats,
"gc-heap/scripts"),
&gcTotal, stats.gcHeapScripts,
&gcTotal, cStats.gcHeapScripts,
"Memory on the compartment's garbage-collected JavaScript heap that holds "
"JSScript instances. A JSScript is created for each user-defined function "
"in a script. One is also created for the top-level code in a script.",
callback, closure);
ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, stats,
ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, cStats,
"gc-heap/shapes/tree"),
&gcTotal, stats.gcHeapShapesTree,
&gcTotal, cStats.gcHeapShapesTree,
"Memory on the compartment's garbage-collected JavaScript heap that holds "
"shapes that are in a property tree.",
callback, closure);
ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, stats,
ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, cStats,
"gc-heap/shapes/dict"),
&gcTotal, stats.gcHeapShapesDict,
&gcTotal, cStats.gcHeapShapesDict,
"Memory on the compartment's garbage-collected JavaScript heap that holds "
"shapes that are in dictionary mode.",
callback, closure);
ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, stats,
ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, cStats,
"gc-heap/shapes/base"),
&gcTotal, stats.gcHeapShapesBase,
&gcTotal, cStats.gcHeapShapesBase,
"Memory on the compartment's garbage-collected JavaScript heap that collates "
"data common to many shapes.",
callback, closure);
ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, stats,
ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, cStats,
"gc-heap/type-objects"),
&gcTotal, stats.gcHeapTypeObjects,
&gcTotal, cStats.gcHeapTypeObjects,
"Memory on the compartment's garbage-collected JavaScript heap that holds "
"type inference information.",
callback, closure);
ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, stats,
ReportGCHeapBytes0(MakeMemoryReporterPath(pathPrefix, cStats,
"gc-heap/xml"),
&gcTotal, stats.gcHeapXML,
&gcTotal, cStats.gcHeapXML,
"Memory on the compartment's garbage-collected JavaScript heap that holds "
"E4X XML objects.",
callback, closure);
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats,
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, cStats,
"object-slots"),
nsIMemoryReporter::KIND_HEAP, stats.objectSlots,
nsIMemoryReporter::KIND_HEAP, cStats.objectSlots,
"Memory allocated for the compartment's non-fixed object slot arrays, "
"which are used to represent object properties. Some objects also "
"contain a fixed number of slots which are stored on the compartment's "
"JavaScript heap; those slots are not counted here, but in "
"'gc-heap/objects' instead." SLOP_BYTES_STRING,
"'gc-heap/objects' instead.",
callback, closure);
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats,
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, cStats,
"object-elements"),
nsIMemoryReporter::KIND_HEAP, stats.objectElements,
nsIMemoryReporter::KIND_HEAP, cStats.objectElements,
"Memory allocated for the compartment's object element arrays, "
"which are used to represent indexed object properties." SLOP_BYTES_STRING,
"which are used to represent indexed object properties.",
callback, closure);
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats,
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, cStats,
"string-chars"),
nsIMemoryReporter::KIND_HEAP, stats.stringChars,
nsIMemoryReporter::KIND_HEAP, cStats.stringChars,
"Memory allocated to hold the compartment's string characters. Sometimes "
"more memory is allocated than necessary, to simplify string "
"concatenation. Each string also includes a header which is stored on the "
@ -1548,83 +1545,83 @@ ReportCompartmentStats(const JS::CompartmentStats &stats,
"'gc-heap/strings' instead.",
callback, closure);
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats,
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, cStats,
"shapes-extra/tree-tables"),
nsIMemoryReporter::KIND_HEAP, stats.shapesExtraTreeTables,
nsIMemoryReporter::KIND_HEAP, cStats.shapesExtraTreeTables,
"Memory allocated for the compartment's property tables that belong to "
"shapes that are in a property tree." SLOP_BYTES_STRING,
"shapes that are in a property tree.",
callback, closure);
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats,
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, cStats,
"shapes-extra/dict-tables"),
nsIMemoryReporter::KIND_HEAP, stats.shapesExtraDictTables,
nsIMemoryReporter::KIND_HEAP, cStats.shapesExtraDictTables,
"Memory allocated for the compartment's property tables that belong to "
"shapes that are in dictionary mode." SLOP_BYTES_STRING,
"shapes that are in dictionary mode.",
callback, closure);
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats,
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, cStats,
"shapes-extra/tree-shape-kids"),
nsIMemoryReporter::KIND_HEAP, stats.shapesExtraTreeShapeKids,
nsIMemoryReporter::KIND_HEAP, cStats.shapesExtraTreeShapeKids,
"Memory allocated for the compartment's kid hashes that belong to shapes "
"that are in a property tree.",
callback, closure);
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats,
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, cStats,
"shapes-extra/compartment-tables"),
nsIMemoryReporter::KIND_HEAP, stats.shapesCompartmentTables,
nsIMemoryReporter::KIND_HEAP, cStats.shapesCompartmentTables,
"Memory used by compartment wide tables storing shape information "
"for use during object construction.",
callback, closure);
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats,
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, cStats,
"script-data"),
nsIMemoryReporter::KIND_HEAP, stats.scriptData,
nsIMemoryReporter::KIND_HEAP, cStats.scriptData,
"Memory allocated for JSScript bytecode and various variable-length "
"tables." SLOP_BYTES_STRING,
"tables.",
callback, closure);
#ifdef JS_METHODJIT
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats,
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, cStats,
"mjit-code"),
nsIMemoryReporter::KIND_NONHEAP, stats.mjitCode,
nsIMemoryReporter::KIND_NONHEAP, cStats.mjitCode,
"Memory used by the method JIT to hold the compartment's generated code.",
callback, closure);
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats,
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, cStats,
"mjit-data"),
nsIMemoryReporter::KIND_HEAP, stats.mjitData,
nsIMemoryReporter::KIND_HEAP, cStats.mjitData,
"Memory used by the method JIT for the compartment's compilation data: "
"JITScripts, native maps, and inline cache structs." SLOP_BYTES_STRING,
"JITScripts, native maps, and inline cache structs.",
callback, closure);
#endif
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats,
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, cStats,
"type-inference/script-main"),
nsIMemoryReporter::KIND_HEAP,
stats.typeInferenceMemory.scripts,
cStats.typeInferenceSizes.scripts,
"Memory used during type inference to store type sets of variables "
"and dynamically observed types.",
callback, closure);
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats,
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, cStats,
"type-inference/object-main"),
nsIMemoryReporter::KIND_HEAP,
stats.typeInferenceMemory.objects,
cStats.typeInferenceSizes.objects,
"Memory used during type inference to store types and possible "
"property types of JS objects.",
callback, closure);
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats,
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, cStats,
"type-inference/tables"),
nsIMemoryReporter::KIND_HEAP,
stats.typeInferenceMemory.tables,
cStats.typeInferenceSizes.tables,
"Memory used during type inference for compartment-wide tables.",
callback, closure);
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats,
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, cStats,
"analysis-temporary"),
nsIMemoryReporter::KIND_HEAP,
stats.typeInferenceMemory.temporary,
cStats.typeInferenceSizes.temporary,
"Memory used during type inference and compilation to hold transient "
"analysis information. Cleared on GC.",
callback, closure);
@ -1633,55 +1630,54 @@ ReportCompartmentStats(const JS::CompartmentStats &stats,
}
void
ReportJSRuntimeStats(const JS::IterateData &data, const nsACString &pathPrefix,
ReportJSRuntimeStats(const JS::RuntimeStats &rtStats, const nsACString &pathPrefix,
nsIMemoryMultiReporterCallback *callback,
nsISupports *closure)
{
PRInt64 gcTotal = 0;
for (size_t index = 0;
index < data.compartmentStatsVector.length();
index < rtStats.compartmentStatsVector.length();
index++) {
gcTotal += ReportCompartmentStats(data.compartmentStatsVector[index], pathPrefix,
gcTotal += ReportCompartmentStats(rtStats.compartmentStatsVector[index], pathPrefix,
callback, closure);
}
ReportMemoryBytes(pathPrefix + NS_LITERAL_CSTRING("runtime/runtime-object"),
nsIMemoryReporter::KIND_HEAP, data.runtimeObject,
"Memory used by the JSRuntime object." SLOP_BYTES_STRING,
nsIMemoryReporter::KIND_HEAP, rtStats.runtimeObject,
"Memory used by the JSRuntime object.",
callback, closure);
ReportMemoryBytes(pathPrefix + NS_LITERAL_CSTRING("runtime/atoms-table"),
nsIMemoryReporter::KIND_HEAP, data.runtimeAtomsTable,
"Memory used by the atoms table." SLOP_BYTES_STRING,
nsIMemoryReporter::KIND_HEAP, rtStats.runtimeAtomsTable,
"Memory used by the atoms table.",
callback, closure);
ReportMemoryBytes(pathPrefix + NS_LITERAL_CSTRING("runtime/contexts"),
nsIMemoryReporter::KIND_HEAP, data.runtimeContexts,
nsIMemoryReporter::KIND_HEAP, rtStats.runtimeContexts,
"Memory used by JSContext objects and certain structures "
"hanging off them." SLOP_BYTES_STRING,
"hanging off them." ,
callback, closure);
ReportMemoryBytes(pathPrefix + NS_LITERAL_CSTRING("runtime/normal"),
nsIMemoryReporter::KIND_HEAP, data.runtimeNormal,
nsIMemoryReporter::KIND_HEAP, rtStats.runtimeNormal,
"Memory used by a JSRuntime, "
"excluding memory that is reported by "
"other reporters under 'explicit/js/runtime/'." SLOP_BYTES_STRING,
"other reporters under 'explicit/js/runtime/'.",
callback, closure);
ReportMemoryBytes(pathPrefix + NS_LITERAL_CSTRING("runtime/temporary"),
nsIMemoryReporter::KIND_HEAP, data.runtimeTemporary,
nsIMemoryReporter::KIND_HEAP, rtStats.runtimeTemporary,
"Memory held transiently in JSRuntime and used during "
"compilation. It mostly holds parse nodes."
SLOP_BYTES_STRING,
"compilation. It mostly holds parse nodes.",
callback, closure);
ReportMemoryBytes0(pathPrefix + NS_LITERAL_CSTRING("runtime/regexp-code"),
nsIMemoryReporter::KIND_NONHEAP, data.runtimeRegexpCode,
nsIMemoryReporter::KIND_NONHEAP, rtStats.runtimeRegexpCode,
"Memory used by the regexp JIT to hold generated code.",
callback, closure);
ReportMemoryBytes(pathPrefix + NS_LITERAL_CSTRING("runtime/stack-committed"),
nsIMemoryReporter::KIND_NONHEAP, data.runtimeStackCommitted,
nsIMemoryReporter::KIND_NONHEAP, rtStats.runtimeStackCommitted,
"Memory used for the JS call stack. This is the committed portion "
"of the stack; the uncommitted portion is not measured because it "
"hardly costs anything.",
@ -1689,7 +1685,7 @@ ReportJSRuntimeStats(const JS::IterateData &data, const nsACString &pathPrefix,
ReportGCHeapBytes(pathPrefix +
NS_LITERAL_CSTRING("gc-heap-chunk-dirty-unused"),
&gcTotal, data.gcHeapChunkDirtyUnused,
&gcTotal, rtStats.gcHeapChunkDirtyUnused,
"Memory on the garbage-collected JavaScript heap, within chunks with at "
"least one allocated GC thing, that could be holding useful data but "
"currently isn't. Memory here is mutually exclusive with memory reported"
@ -1698,7 +1694,7 @@ ReportJSRuntimeStats(const JS::IterateData &data, const nsACString &pathPrefix,
ReportGCHeapBytes(pathPrefix +
NS_LITERAL_CSTRING("gc-heap-chunk-clean-unused"),
&gcTotal, data.gcHeapChunkCleanUnused,
&gcTotal, rtStats.gcHeapChunkCleanUnused,
"Memory on the garbage-collected JavaScript heap taken by completely empty "
"chunks, that soon will be released unless claimed for new allocations. "
"Memory here is mutually exclusive with memory reported under "
@ -1708,21 +1704,21 @@ ReportJSRuntimeStats(const JS::IterateData &data, const nsACString &pathPrefix,
ReportGCHeapBytes(pathPrefix +
NS_LITERAL_CSTRING("gc-heap-decommitted"),
&gcTotal,
data.gcHeapChunkCleanDecommitted + data.gcHeapChunkDirtyDecommitted,
rtStats.gcHeapChunkCleanDecommitted + rtStats.gcHeapChunkDirtyDecommitted,
"Memory in the address space of the garbage-collected JavaScript heap that "
"is currently returned to the OS.",
callback, closure);
ReportGCHeapBytes(pathPrefix +
NS_LITERAL_CSTRING("gc-heap-chunk-admin"),
&gcTotal, data.gcHeapChunkAdmin,
&gcTotal, rtStats.gcHeapChunkAdmin,
"Memory on the garbage-collected JavaScript heap, within chunks, that is "
"used to hold internal book-keeping information.",
callback, closure);
// gcTotal is the sum of everything we've reported for the GC heap. It
// should equal data.gcHeapChunkTotal.
JS_ASSERT(gcTotal == data.gcHeapChunkTotal);
// should equal rtStats.gcHeapChunkTotal.
JS_ASSERT(gcTotal == rtStats.gcHeapChunkTotal);
}
} // namespace memory
@ -1744,12 +1740,12 @@ public:
// the callback. Separating these steps is important because the
// callback may be a JS function, and executing JS while getting these
// stats seems like a bad idea.
JS::IterateData data(xpc::JsMallocSizeOf, xpc::GetCompartmentName,
xpc::DestroyCompartmentName);
if (!JS::CollectCompartmentStatsForRuntime(xpcrt->GetJSRuntime(), &data))
JS::RuntimeStats rtStats(xpc::JsMallocSizeOf, xpc::GetCompartmentName,
xpc::DestroyCompartmentName);
if (!JS::CollectRuntimeStats(xpcrt->GetJSRuntime(), &rtStats))
return NS_ERROR_FAILURE;
uint64_t xpconnect;
size_t xpconnect;
{
xpconnect =
xpcrt->SizeOfIncludingThis(xpc::JsMallocSizeOf) +
@ -1759,37 +1755,37 @@ public:
NS_NAMED_LITERAL_CSTRING(pathPrefix, "explicit/js/");
// This is the second step (see above).
ReportJSRuntimeStats(data, pathPrefix, callback, closure);
ReportJSRuntimeStats(rtStats, pathPrefix, callback, closure);
ReportMemoryBytes(pathPrefix + NS_LITERAL_CSTRING("xpconnect"),
nsIMemoryReporter::KIND_HEAP, xpconnect,
"Memory used by XPConnect." SLOP_BYTES_STRING,
"Memory used by XPConnect.",
callback, closure);
ReportMemoryBytes(NS_LITERAL_CSTRING("js-gc-heap-chunk-dirty-unused"),
nsIMemoryReporter::KIND_OTHER,
data.gcHeapChunkDirtyUnused,
rtStats.gcHeapChunkDirtyUnused,
"The same as 'explicit/js/gc-heap-chunk-dirty-unused'. Shown here for "
"easy comparison with other 'js-gc' reporters.",
callback, closure);
ReportMemoryBytes(NS_LITERAL_CSTRING("js-gc-heap-chunk-clean-unused"),
nsIMemoryReporter::KIND_OTHER,
data.gcHeapChunkCleanUnused,
rtStats.gcHeapChunkCleanUnused,
"The same as 'explicit/js/gc-heap-chunk-clean-unused'. Shown here for "
"easy comparison with other 'js-gc' reporters.",
callback, closure);
ReportMemoryBytes(NS_LITERAL_CSTRING("js-gc-heap-decommitted"),
nsIMemoryReporter::KIND_OTHER,
data.gcHeapChunkCleanDecommitted + data.gcHeapChunkDirtyDecommitted,
rtStats.gcHeapChunkCleanDecommitted + rtStats.gcHeapChunkDirtyDecommitted,
"The same as 'explicit/js/gc-heap-decommitted'. Shown here for "
"easy comparison with other 'js-gc' reporters.",
callback, closure);
ReportMemoryBytes(NS_LITERAL_CSTRING("js-gc-heap-arena-unused"),
nsIMemoryReporter::KIND_OTHER,
data.gcHeapArenaUnused,
rtStats.gcHeapArenaUnused,
"Memory on the garbage-collected JavaScript heap, within arenas, that "
"could be holding useful data but currently isn't. This is the sum of "
"all compartments' 'gc-heap/arena-unused' numbers.",
@ -1797,7 +1793,7 @@ public:
ReportMemoryPercentage(NS_LITERAL_CSTRING("js-gc-heap-unused-fraction"),
nsIMemoryReporter::KIND_OTHER,
data.gcHeapUnusedPercentage,
rtStats.gcHeapUnusedPercentage,
"Fraction of the garbage-collected JavaScript heap that is unused. "
"Computed as ('js-gc-heap-chunk-clean-unused' + "
"'js-gc-heap-chunk-dirty-unused' + 'js-gc-heap-decommitted' + "
@ -1805,14 +1801,14 @@ public:
callback, closure);
ReportMemoryBytes(NS_LITERAL_CSTRING("js-total-objects"),
nsIMemoryReporter::KIND_OTHER, data.totalObjects,
nsIMemoryReporter::KIND_OTHER, rtStats.totalObjects,
"Memory used for all object-related data. This is the sum of all "
"compartments' 'gc-heap/objects-non-function', "
"'gc-heap/objects-function' and 'object-slots' numbers.",
callback, closure);
ReportMemoryBytes(NS_LITERAL_CSTRING("js-total-shapes"),
nsIMemoryReporter::KIND_OTHER, data.totalShapes,
nsIMemoryReporter::KIND_OTHER, rtStats.totalShapes,
"Memory used for all shape-related data. This is the sum of all "
"compartments' 'gc-heap/shapes/tree', 'gc-heap/shapes/dict', "
"'gc-heap/shapes/base', "
@ -1821,32 +1817,32 @@ public:
callback, closure);
ReportMemoryBytes(NS_LITERAL_CSTRING("js-total-scripts"),
nsIMemoryReporter::KIND_OTHER, data.totalScripts,
nsIMemoryReporter::KIND_OTHER, rtStats.totalScripts,
"Memory used for all script-related data. This is the sum of all "
"compartments' 'gc-heap/scripts' and 'script-data' numbers.",
callback, closure);
ReportMemoryBytes(NS_LITERAL_CSTRING("js-total-strings"),
nsIMemoryReporter::KIND_OTHER, data.totalStrings,
nsIMemoryReporter::KIND_OTHER, rtStats.totalStrings,
"Memory used for all string-related data. This is the sum of all "
"compartments' 'gc-heap/strings' and 'string-chars' numbers.",
callback, closure);
#ifdef JS_METHODJIT
ReportMemoryBytes(NS_LITERAL_CSTRING("js-total-mjit"),
nsIMemoryReporter::KIND_OTHER, data.totalMjit,
nsIMemoryReporter::KIND_OTHER, rtStats.totalMjit,
"Memory used by the method JIT. This is the sum of all compartments' "
"'mjit-code', and 'mjit-data' numbers.",
callback, closure);
#endif
ReportMemoryBytes(NS_LITERAL_CSTRING("js-total-type-inference"),
nsIMemoryReporter::KIND_OTHER, data.totalTypeInference,
nsIMemoryReporter::KIND_OTHER, rtStats.totalTypeInference,
"Non-transient memory used by type inference. This is the sum of all "
"compartments' 'gc-heap/type-objects', 'type-inference/script-main', "
"'type-inference/object-main' and 'type-inference/tables' numbers.",
callback, closure);
ReportMemoryBytes(NS_LITERAL_CSTRING("js-total-analysis-temporary"),
nsIMemoryReporter::KIND_OTHER, data.totalAnalysisTemp,
nsIMemoryReporter::KIND_OTHER, rtStats.totalAnalysisTemp,
"Memory used transiently during type inference and compilation. "
"This is the sum of all compartments' 'analysis-temporary' numbers.",
callback, closure);

View File

@ -230,7 +230,7 @@ namespace xpconnect {
namespace memory {
void
ReportJSRuntimeStats(const JS::IterateData &data, const nsACString &pathPrefix,
ReportJSRuntimeStats(const JS::RuntimeStats &rtStats, const nsACString &pathPrefix,
nsIMemoryMultiReporterCallback *callback,
nsISupports *closure);

View File

@ -4804,7 +4804,18 @@ nsLayoutUtils::FontSizeInflationFor(const nsIFrame *aFrame,
/* static */ bool
nsLayoutUtils::FontSizeInflationEnabled(nsPresContext *aPresContext)
{
return (sFontSizeInflationEmPerLine != 0 ||
sFontSizeInflationMinTwips != 0) &&
!aPresContext->IsChrome();
if ((sFontSizeInflationEmPerLine == 0 &&
sFontSizeInflationMinTwips == 0) ||
aPresContext->IsChrome()) {
return false;
}
ViewportInfo vInf =
nsContentUtils::GetViewportInfo(aPresContext->PresShell()->GetDocument());
if (vInf.defaultZoom >= 1.0 || vInf.autoSize) {
return false;
}
return true;
}

View File

@ -0,0 +1,20 @@
<!--
Without the patch for bug 706198, this website should not show up as inflated. That means
that with a 450px container, the minimum font size with 15em per line should be 30px.
So, we map 0px-45px into 30px-45px, and thus 12px gets mapped to 34px.
With the patch, the text should be uninflated, which means that 12px should still be
12px.
-->
<!DOCTYPE html>
<html>
<head>
<meta content='True' name='HandheldFriendly' />
<style>
p { font-size: 12px; line-height: 1.0;}
</style>
<body>
<p>Some uninflated text.</p>
</body>
</head>
</html>

View File

@ -0,0 +1,20 @@
<!--
Without the patch for bug 706198, this website should not show up as inflated. That means
that with a 450px container, the minimum font size with 15em per line should be 30px.
So, we map 0px-45px into 30px-45px, and thus 12px gets mapped to 34px.
With the patch, the text should be uninflated, which means that 12px should still be
12px.
-->
<!DOCTYPE html>
<html>
<head>
<meta content='width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0' name='viewport' />
<style>
p { font-size: 12px; line-height: 1.0;}
</style>
<body>
<p>Some uninflated text.</p>
</body>
</head>
</html>

View File

@ -0,0 +1,20 @@
<!--
Without the patch for bug 706198, this website should not show up as inflated. That means
that with a 450px container, the minimum font size with 15em per line should be 30px.
So, we map 0px-45px into 30px-45px, and thus 12px gets mapped to 34px.
With the patch, the text should be uninflated, which means that 12px should still be
12px.
-->
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=320"/>
<style>
p { font-size: 12px; line-height: 1.0;}
</style>
<body>
<p>Some uninflated text.</p>
</body>
</head>
</html>

View File

@ -0,0 +1,19 @@
<!--
Without the patch for bug 706198, this website should not show up as inflated. That means
that with a 450px container, the minimum font size with 15em per line should be 30px.
So, we map 0px-45px into 30px-45px, and thus 12px gets mapped to 34px.
With the patch, the text should be uninflated, which means that 12px should still be
12px.
-->
<!DOCTYPE html>
<html>
<head>
<style>
p { font-size: 12px; line-height: 1.0;}
</style>
<body>
<p>Some uninflated text.</p>
</body>
</head>
</html>

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.0//EN" "http://www.wapforum.org/DTD/xhtml-mobile10.dtd">
<!--
Without the patch for bug 706198, this website should not show up as inflated. That means
that with a 450px container, the minimum font size with 15em per line should be 30px.
So, we map 0px-45px into 30px-45px, and thus 12px gets mapped to 34px.
With the patch, the text should be uninflated, which means that 12px should still be
12px.
-->
<html>
<head>
<style>
p { font-size: 12px; line-height: 1.0;}
</style>
<body>
<p>Some uninflated text.</p>
</body>
</head>
</html>

View File

@ -61,6 +61,10 @@ var gTests = [
"!= select-combobox-2.html select-combobox-2.html",
"!= input-checkbox.html input-checkbox.html",
"!= input-radio.html input-radio.html",
"== disable-fontinfl-on-mobile.html disable-fontinfl-on-mobile-ref.html",
"== disable-fontinfl-on-mobile-2.html disable-fontinfl-on-mobile-ref.html",
"== disable-fontinfl-on-mobile-3.html disable-fontinfl-on-mobile-ref.html",
"== disable-fontinfl-on-mobile-4.html disable-fontinfl-on-mobile-ref.html",
];
// Maintain a reference count of how many things we're waiting for until

View File

@ -1012,7 +1012,7 @@ nsBlockFrame::Reflow(nsPresContext* aPresContext,
// ALWAYS drain overflow. We never want to leave the previnflow's
// overflow lines hanging around; block reflow depends on the
// overflow line lists being cleared out between reflow passes.
DrainOverflowLines(state);
DrainOverflowLines();
// Handle paginated overflow (see nsContainerFrame.h)
nsOverflowAreas ocBounds;
@ -4439,7 +4439,7 @@ nsBlockFrame::PushLines(nsBlockReflowState& aState,
// the invariant that the property is never set if the list is empty.
bool
nsBlockFrame::DrainOverflowLines(nsBlockReflowState& aState)
nsBlockFrame::DrainOverflowLines()
{
#ifdef DEBUG
VerifyOverflowSituation();

View File

@ -452,7 +452,7 @@ protected:
* part of this block's mLines list.
* @return true if any lines were drained.
*/
bool DrainOverflowLines(nsBlockReflowState& aState);
bool DrainOverflowLines();
/** grab pushed floats from this block's prevInFlow, and splice
* them into this block's mFloats list.

View File

@ -1639,9 +1639,9 @@ skip-if(Android) == 632781-verybig.html 632781-ref.html
== 633344-1.html 633344-1-ref.html
fails-if(Android) == 634232-1.html 634232-1-ref.html
fails-if(Android) == 635302-1.html 635302-1-ref.html
== 635373-1.html 635373-1-ref.html
== 635373-2.html 635373-2-ref.html
== 635373-3.html 635373-3-ref.html
random-if(d2d) == 635373-1.html 635373-1-ref.html
random-if(d2d) == 635373-2.html 635373-2-ref.html
random-if(d2d) == 635373-3.html 635373-3-ref.html
HTTP(..) == 635639-1.html 635639-1-ref.html
HTTP(..) == 635639-2.html 635639-2-ref.html
random == 637597-1.html 637597-1-ref.html # bug 637597 was never really fixed!

View File

@ -218,8 +218,10 @@ pref("extensions.logging.enabled", false);
pref("extensions.hideInstallButton", true);
pref("extensions.showMismatchUI", false);
pref("extensions.hideUpdateButton", false);
pref("extensions.strictCompatibility", false);
pref("extensions.minCompatibleAppVersion", "11.0");
pref("extensions.update.url", "https://versioncheck.addons.mozilla.org/update/VersionCheck.php?reqVersion=%REQ_VERSION%&id=%ITEM_ID%&version=%ITEM_VERSION%&maxAppVersion=%ITEM_MAXAPPVERSION%&status=%ITEM_STATUS%&appID=%APP_ID%&appVersion=%APP_VERSION%&appOS=%APP_OS%&appABI=%APP_ABI%&locale=%APP_LOCALE%&currentAppVersion=%CURRENT_APP_VERSION%&updateType=%UPDATE_TYPE%");
pref("extensions.update.url", "https://versioncheck.addons.mozilla.org/update/VersionCheck.php?reqVersion=%REQ_VERSION%&id=%ITEM_ID%&version=%ITEM_VERSION%&maxAppVersion=%ITEM_MAXAPPVERSION%&status=%ITEM_STATUS%&appID=%APP_ID%&appVersion=%APP_VERSION%&appOS=%APP_OS%&appABI=%APP_ABI%&locale=%APP_LOCALE%&currentAppVersion=%CURRENT_APP_VERSION%&updateType=%UPDATE_TYPE%&compatMode=%COMPATIBILITY_MODE%");
/* preferences for the Get Add-ons pane */
pref("extensions.getAddons.cache.enabled", true);
@ -227,7 +229,7 @@ pref("extensions.getAddons.maxResults", 15);
pref("extensions.getAddons.recommended.browseURL", "https://addons.mozilla.org/%LOCALE%/mobile/recommended/");
pref("extensions.getAddons.recommended.url", "https://services.addons.mozilla.org/%LOCALE%/mobile/api/%API_VERSION%/list/featured/all/%MAX_RESULTS%/%OS%/%VERSION%");
pref("extensions.getAddons.search.browseURL", "https://addons.mozilla.org/%LOCALE%/mobile/search?q=%TERMS%");
pref("extensions.getAddons.search.url", "https://services.addons.mozilla.org/%LOCALE%/mobile/api/%API_VERSION%/search/%TERMS%/all/%MAX_RESULTS%/%OS%/%VERSION%");
pref("extensions.getAddons.search.url", "https://services.addons.mozilla.org/%LOCALE%/mobile/api/%API_VERSION%/search/%TERMS%/all/%MAX_RESULTS%/%OS%/%VERSION%/%COMPATIBILITY_MODE%");
pref("extensions.getAddons.browseAddons", "https://addons.mozilla.org/%LOCALE%/mobile/");
pref("extensions.getAddons.get.url", "https://services.addons.mozilla.org/%LOCALE%/mobile/api/%API_VERSION%/search/guid:%IDS%?src=mobile&appOS=%OS%&appVersion=%VERSION%&tMain=%TIME_MAIN%&tFirstPaint=%TIME_FIRST_PAINT%&tSessionRestored=%TIME_SESSION_RESTORED%");

View File

@ -317,4 +317,16 @@ public class BrowserToolbar extends LinearLayout {
else
mSiteSecurity.setImageLevel(0);
}
public void refresh() {
Tab tab = Tabs.getInstance().getSelectedTab();
if (tab != null) {
setTitle(tab.getDisplayTitle());
setFavicon(tab.getFavicon());
setSecurityMode(tab.getSecurityMode());
setProgressVisibility(tab.isLoading());
setShadowVisibility(!(tab.getURL().startsWith("about:")));
updateTabs(Tabs.getInstance().getCount());
}
}
}

View File

@ -583,12 +583,12 @@ abstract public class GeckoApp
mLastViewport = viewportMetrics.toJSON();
mLastTitle = lastHistoryEntry.mTitle;
getAndProcessThumbnailForTab(tab);
getAndProcessThumbnailForTab(tab, true);
}
}
}
void getAndProcessThumbnailForTab(final Tab tab) {
void getAndProcessThumbnailForTab(final Tab tab, boolean forceBigSceenshot) {
boolean isSelectedTab = Tabs.getInstance().isSelectedTab(tab);
final Bitmap bitmap = isSelectedTab ?
mSoftwareLayerClient.getBitmap() : null;
@ -599,10 +599,10 @@ abstract public class GeckoApp
processThumbnail(tab, bitmap, bos.toByteArray());
} else {
mLastScreen = null;
int sw = isSelectedTab ? mSoftwareLayerClient.getWidth() : tab.getMinScreenshotWidth();
int sh = isSelectedTab ? mSoftwareLayerClient.getHeight(): tab.getMinScreenshotHeight();
int dw = isSelectedTab ? sw : tab.getThumbnailWidth();
int dh = isSelectedTab ? sh : tab.getThumbnailHeight();
int sw = forceBigSceenshot ? mSoftwareLayerClient.getWidth() : tab.getMinScreenshotWidth();
int sh = forceBigSceenshot ? mSoftwareLayerClient.getHeight(): tab.getMinScreenshotHeight();
int dw = forceBigSceenshot ? sw : tab.getThumbnailWidth();
int dh = forceBigSceenshot ? sh : tab.getThumbnailHeight();
try {
JSONObject message = new JSONObject();
message.put("tabID", tab.getId());
@ -1071,6 +1071,17 @@ abstract public class GeckoApp
}
} else if (event.equals("Update:Restart")) {
doRestart("org.mozilla.gecko.restart_update");
} else if (event.equals("Tab:HasTouchListener")) {
int tabId = message.getInt("tabID");
Tab tab = Tabs.getInstance().getTab(tabId);
tab.setHasTouchListeners(true);
if (Tabs.getInstance().isSelectedTab(tab)) {
mMainHandler.post(new Runnable() {
public void run() {
mLayerController.setWaitForTouchListeners(true);
}
});
}
}
} catch (Exception e) {
Log.e(LOGTAG, "Exception handling message \"" + event + "\":", e);
@ -1446,6 +1457,20 @@ abstract public class GeckoApp
});
}
// The ActionBar needs to be refreshed on rotation as different orientation uses different resources
public void refreshActionBar() {
if (Build.VERSION.SDK_INT >= 11) {
mBrowserToolbar = (BrowserToolbar) getLayoutInflater().inflate(R.layout.browser_toolbar, null);
mBrowserToolbar.refresh();
GeckoActionBar.setBackgroundDrawable(this, getResources().getDrawable(R.drawable.gecko_actionbar_bg));
GeckoActionBar.setDisplayOptions(this, ActionBar.DISPLAY_SHOW_CUSTOM, ActionBar.DISPLAY_SHOW_CUSTOM |
ActionBar.DISPLAY_SHOW_HOME |
ActionBar.DISPLAY_SHOW_TITLE |
ActionBar.DISPLAY_USE_LOGO);
GeckoActionBar.setCustomView(this, mBrowserToolbar);
}
}
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
@ -1531,14 +1556,7 @@ abstract public class GeckoApp
mOrientation = getResources().getConfiguration().orientation;
if (Build.VERSION.SDK_INT >= 11) {
mBrowserToolbar = (BrowserToolbar) getLayoutInflater().inflate(R.layout.browser_toolbar, null);
GeckoActionBar.setBackgroundDrawable(this, getResources().getDrawable(R.drawable.gecko_actionbar_bg));
GeckoActionBar.setDisplayOptions(this, ActionBar.DISPLAY_SHOW_CUSTOM, ActionBar.DISPLAY_SHOW_CUSTOM |
ActionBar.DISPLAY_SHOW_HOME |
ActionBar.DISPLAY_SHOW_TITLE |
ActionBar.DISPLAY_USE_LOGO);
GeckoActionBar.setCustomView(this, mBrowserToolbar);
refreshActionBar();
} else {
mBrowserToolbar = (BrowserToolbar) findViewById(R.id.browser_toolbar);
}
@ -1639,6 +1657,7 @@ abstract public class GeckoApp
GeckoAppShell.registerGeckoEventListener("CharEncoding:Data", GeckoApp.mAppContext);
GeckoAppShell.registerGeckoEventListener("CharEncoding:State", GeckoApp.mAppContext);
GeckoAppShell.registerGeckoEventListener("Update:Restart", GeckoApp.mAppContext);
GeckoAppShell.registerGeckoEventListener("Tab:HasTouchListener", GeckoApp.mAppContext);
mConnectivityFilter = new IntentFilter();
mConnectivityFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
@ -1899,6 +1918,13 @@ abstract public class GeckoApp
// Undo whatever we did in onPause.
super.onResume();
int newOrientation = getResources().getConfiguration().orientation;
if (mOrientation != newOrientation) {
mOrientation = newOrientation;
refreshActionBar();
}
// Just in case. Normally we start in onNewIntent
if (checkLaunchState(LaunchState.Launching))
onNewIntent(getIntent());
@ -1978,6 +2004,7 @@ abstract public class GeckoApp
GeckoAppShell.unregisterGeckoEventListener("Downloads:Done", GeckoApp.mAppContext);
GeckoAppShell.unregisterGeckoEventListener("CharEncoding:Data", GeckoApp.mAppContext);
GeckoAppShell.unregisterGeckoEventListener("CharEncoding:State", GeckoApp.mAppContext);
GeckoAppShell.unregisterGeckoEventListener("Tab:HasTouchListener", GeckoApp.mAppContext);
mFavicons.close();
@ -2012,23 +2039,7 @@ abstract public class GeckoApp
if (mOrientation != newConfig.orientation) {
mOrientation = newConfig.orientation;
mAutoCompletePopup.hide();
if (Build.VERSION.SDK_INT >= 11) {
mBrowserToolbar = (BrowserToolbar) getLayoutInflater().inflate(R.layout.browser_toolbar, null);
Tab tab = Tabs.getInstance().getSelectedTab();
if (tab != null) {
mBrowserToolbar.setTitle(tab.getDisplayTitle());
mBrowserToolbar.setFavicon(tab.getFavicon());
mBrowserToolbar.setSecurityMode(tab.getSecurityMode());
mBrowserToolbar.setProgressVisibility(tab.isLoading());
mBrowserToolbar.setShadowVisibility(!(tab.getURL().startsWith("about:")));
mBrowserToolbar.updateTabs(Tabs.getInstance().getCount());
}
GeckoActionBar.setBackgroundDrawable(this, getResources().getDrawable(R.drawable.gecko_actionbar_bg));
GeckoActionBar.setCustomView(mAppContext, mBrowserToolbar);
}
refreshActionBar();
}
}

View File

@ -1147,12 +1147,17 @@ public class GeckoAppShell
}
public static void setSelectedLocale(String localeCode) {
/* We're not using this, not need to save it (see bug 635342)
SharedPreferences settings =
/* Bug 713464: This method is still called from Gecko side.
Earlier we had an option to run Firefox in a language other than system's language.
However, this is not supported as of now.
Gecko resets the locale to en-US by calling this function with an empty string.
This affects GeckoPreferences activity in multi-locale builds.
//We're not using this, not need to save it (see bug 635342)
SharedPreferences settings =
GeckoApp.mAppContext.getPreferences(Activity.MODE_PRIVATE);
settings.edit().putString(GeckoApp.mAppContext.getPackageName() + ".locale",
localeCode).commit();
*/
Locale locale;
int index;
if ((index = localeCode.indexOf('-')) != -1 ||
@ -1169,6 +1174,7 @@ public class GeckoAppShell
Configuration config = res.getConfiguration();
config.locale = locale;
res.updateConfiguration(config, res.getDisplayMetrics());
*/
}
public static int[] getSystemColors() {

View File

@ -293,7 +293,7 @@ public class Tabs implements GeckoEventListener {
final Tab tab = iterator.next();
GeckoAppShell.getHandler().post(new Runnable() {
public void run() {
GeckoApp.mAppContext.getAndProcessThumbnailForTab(tab);
GeckoApp.mAppContext.getAndProcessThumbnailForTab(tab, false);
}
});
}

View File

@ -112,6 +112,9 @@ public class GeckoSoftwareLayerClient extends LayerClient implements GeckoEventL
// inside a transaction, so no synchronization is needed.
private boolean mUpdateViewportOnEndDraw;
/* Used by robocop for testing purposes */
private DrawListener mDrawListener;
private static Pattern sColorPattern;
public GeckoSoftwareLayerClient(Context context) {
@ -325,6 +328,11 @@ public class GeckoSoftwareLayerClient extends LayerClient implements GeckoEventL
}
}
Log.i(LOGTAG, "zerdatime " + SystemClock.uptimeMillis() + " - endDrawing");
/* Used by robocop for testing purposes */
if (mDrawListener != null) {
mDrawListener.drawFinished(x, y, width, height);
}
}
public ViewportMetrics getGeckoViewportMetrics() {
@ -536,5 +544,15 @@ public class GeckoSoftwareLayerClient extends LayerClient implements GeckoEventL
int b = Integer.parseInt(matcher.group(3));
return Color.rgb(r, g, b);
}
/** Used by robocop for testing purposes. Not for production use! This is called via reflection by robocop. */
public void setDrawListener(DrawListener listener) {
mDrawListener = listener;
}
/** Used by robocop for testing purposes. Not for production use! This is used via reflection by robocop. */
public interface DrawListener {
public void drawFinished(int x, int y, int width, int height);
}
}

View File

@ -244,7 +244,13 @@ public class LayerController {
// Page size is owned by the LayerClient, so no need to notify it of
// this change.
mView.requestRender();
mView.post(new Runnable() {
public void run() {
mPanZoomController.pageSizeUpdated();
mView.requestRender();
}
});
}
/**

View File

@ -61,7 +61,7 @@ import android.util.Log;
import android.view.WindowManager;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
/**
* The layer renderer implements the rendering logic for a layer view.
@ -95,6 +95,9 @@ public class LayerRenderer implements GLSurfaceView.Renderer {
private int mCurrentFrame, mFrameTimingsSum, mDroppedFrames;
private boolean mShowFrameRate;
/* Used by robocop for testing purposes */
private IntBuffer mPixelBuffer;
public LayerRenderer(LayerView view) {
mView = view;
@ -246,6 +249,31 @@ public class LayerRenderer implements GLSurfaceView.Renderer {
mView.requestRender();
PanningPerfAPI.recordFrameTime();
/* Used by robocop for testing purposes */
IntBuffer pixelBuffer = mPixelBuffer;
if (updated && pixelBuffer != null) {
synchronized (pixelBuffer) {
pixelBuffer.position(0);
gl.glReadPixels(0, 0, (int)screenContext.viewport.width(), (int)screenContext.viewport.height(), GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, pixelBuffer);
pixelBuffer.notify();
}
}
}
/** Used by robocop for testing purposes. Not for production use! */
IntBuffer getPixels() {
IntBuffer pixelBuffer = IntBuffer.allocate(mView.getWidth() * mView.getHeight());
synchronized (pixelBuffer) {
mPixelBuffer = pixelBuffer;
mView.requestRender();
try {
pixelBuffer.wait();
} catch (InterruptedException ie) {
}
mPixelBuffer = null;
}
return pixelBuffer;
}
private RenderContext createScreenContext() {

View File

@ -52,6 +52,7 @@ import android.view.MotionEvent;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
import android.util.Log;
import java.nio.IntBuffer;
import java.util.LinkedList;
import org.json.JSONArray;
@ -237,5 +238,10 @@ public class LayerView extends GLSurfaceView
public int getMaxTextureSize() {
return mRenderer.getMaxTextureSize();
}
/** Used by robocop for testing purposes. Not for production use! This is called via reflection by robocop. */
public IntBuffer getPixels() {
return mRenderer.getPixels();
}
}

View File

@ -4,7 +4,7 @@
<item android:right="34dp">
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
android:src="@drawable/address_bar_texture"
android:tileMode="mirror"
android:tileMode="repeat"
android:dither="false"/>
</item>

View File

@ -0,0 +1,17 @@
<html style="margin: 0; padding: 0">
<title>Browser Box test</title>
<body style="margin: 0; padding: 0">
<script type="text/javascript">
for (var y = 0; y < 2000; y += 100) {
document.write("<div style='width: 2000px; height: 100px; margin: 0; padding: 0; border: none'>\n");
for (var x = 0; x < 2000; x += 100) {
var r = (y + x) % 255;
var g = 255 - (y / 10);
var b = 255 - (x / 10);
document.write("<div style='float: left; width: 100px; height: 100px; margin: 0; padding: 0; border: none; background-color: rgb(" + r + "," + g + "," + b + ")'> </div>\n");
}
document.write("</div>\n");
}
</script>
</body>
</html>

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