This commit is contained in:
Wes Kocher 2013-11-21 19:24:36 -08:00
Родитель 18ba86a2b7 07ce8fb494
Коммит 98ca2b2c71
166 изменённых файлов: 7832 добавлений и 2941 удалений

Просмотреть файл

@ -112,6 +112,8 @@ run-if = crashreporter
[browser_aboutSyncProgress.js]
[browser_addKeywordSearch.js]
[browser_alltabslistener.js]
[browser_backButtonFitts.js]
skip-if = os != "win" # The Fitts Law back button is only supported on Windows (bug 571454)
[browser_blob-channelname.js]
[browser_bookmark_titles.js]
skip-if = toolkit == "windows" # Disabled on Windows due to frequent failures (bugs 825739, 841341)

Просмотреть файл

@ -0,0 +1,30 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
function test () {
waitForExplicitFinish();
var firstLocation = "http://example.org/browser/browser/base/content/test/general/dummy_page.html";
gBrowser.selectedTab = gBrowser.addTab(firstLocation);
gBrowser.selectedBrowser.addEventListener("pageshow", function onPageShow1() {
gBrowser.selectedBrowser.removeEventListener("pageshow", onPageShow1);
gBrowser.selectedBrowser.contentWindow.history.pushState("page2", "page2", "page2");
window.maximize();
// Find where the nav-bar is vertically.
var navBar = document.getElementById("nav-bar");
var boundingRect = navBar.getBoundingClientRect();
var yPixel = boundingRect.top + Math.floor(boundingRect.height / 2);
var xPixel = 0; // Use the first pixel of the screen since it is maximized.
gBrowser.selectedBrowser.contentWindow.addEventListener("popstate", function onPopState() {
gBrowser.selectedBrowser.contentWindow.removeEventListener("popstate", onPopState);
is(gBrowser.selectedBrowser.contentDocument.location.href, firstLocation,
"Clicking the first pixel should have navigated back.");
window.restore();
gBrowser.removeCurrentTab();
finish();
});
EventUtils.synthesizeMouseAtPoint(xPixel, yPixel, {}, window);
});
}

Просмотреть файл

@ -40,17 +40,21 @@ function setup() {
}
function onSaveState() {
try {
ss.getWindowValue(newWin, "foobar");
} catch (e) {
// The window is untracked which means that the saveState() call isn't the
// one we're waiting for. It's most likely been triggered by an async
// collection running in the background.
waitForSaveState(onSaveState);
return;
}
// Double check that we have no closed windows
is(ss.getClosedWindowCount(), 0, "no closed windows on first save");
Services.obs.addObserver(observe1, "sessionstore-state-write", false);
try {
ss.getWindowValue(newWin, "foobar");
} catch (e) {
ok(false, "window is untracked!");
}
// Now close the new window, which should trigger another save event
newWin.close();
}

Просмотреть файл

@ -49,7 +49,6 @@ function testParseHTMLAttribute() {
let attrib = "color:red; font-size: 12px; background-image: " +
"url(chrome://branding/content/about-logo.png)";
let frag = parser.parseHTMLAttribute(attrib, {
colorSwatchClass: "test-colorswatch",
urlClass: "theme-link"
});
@ -57,16 +56,32 @@ function testParseHTMLAttribute() {
ok(target, "captain, we have the div");
target.appendChild(frag);
let expected = 'color:<span style="background-color:red" ' +
'class="test-colorswatch"></span>#F00; font-size: 12px; ' +
let expected = 'color:#F00; font-size: 12px; ' +
'background-image: url(\'<a href="chrome://branding/content/about-logo.png" ' +
'class="theme-link" ' +
'target="_blank">chrome://branding/content/about-logo.png</a>\')';
is(target.innerHTML, expected, "HTML Attribute correctly parsed");
target.innerHTML = "";
testParseNonCssHTMLAttribute();
}
function testParseNonCssHTMLAttribute() {
let attrib = "someclass background someotherclass red";
let frag = parser.parseHTMLAttribute(attrib);
let target = doc.querySelector("div");
ok(target, "captain, we have the div");
target.appendChild(frag);
let expected = 'someclass background someotherclass red';
is(target.innerHTML, expected, "Non-CSS HTML Attribute correctly parsed");
target.innerHTML = "";
finishUp();
}
function finishUp() {
Services = Loader = OutputParser = parser = doc = null;
gBrowser.removeCurrentTab();

Просмотреть файл

@ -57,7 +57,7 @@ const CM_IFRAME =
" <style>" +
" html, body { height: 100%; }" +
" body { margin: 0; overflow: hidden; }" +
" .CodeMirror { width: 100%; height: 100% !important; }" +
" .CodeMirror { width: 100%; height: 100% !important; line-height: normal!important}" +
" </style>" +
[ " <link rel='stylesheet' href='" + style + "'>" for (style of CM_STYLES) ].join("\n") +
" </head>" +

Просмотреть файл

@ -49,6 +49,8 @@ const kReferenceDpi = 240; // standard "pixel" size used in some preferences
const kStateActive = 0x00000001; // :active pseudoclass for elements
const kZoomToElementMargin = 16; // in px
/*
* getBoundingContentRect
*
@ -395,36 +397,37 @@ let Content = {
* Zoom utilities
*/
_zoomOut: function() {
let rect = getBoundingContentRect(content.document.documentElement);
let utils = Util.getWindowUtils(content);
let viewId = utils.getViewId(content.document.documentElement);
let presShellId = {};
utils.getPresShellId(presShellId);
let zoomData = [rect.x,
rect.y,
rect.width,
rect.height,
presShellId.value,
viewId].join(",");
Services.obs.notifyObservers(null, "Metro:ZoomToRect", zoomData);
let rect = new Rect(0,0,0,0);
this._zoomToRect(rect);
this._isZoomedIn = false;
},
_zoomToElement: function(aElement) {
let rect = getBoundingContentRect(aElement);
this._inflateRect(rect, kZoomToElementMargin);
this._zoomToRect(rect);
this._isZoomedIn = true;
},
_inflateRect: function(aRect, aMargin) {
aRect.left -= aMargin;
aRect.top -= aMargin;
aRect.bottom += aMargin;
aRect.right += aMargin;
},
_zoomToRect: function (aRect) {
let utils = Util.getWindowUtils(content);
let viewId = utils.getViewId(content.document.documentElement);
let presShellId = {};
utils.getPresShellId(presShellId);
let zoomData = [rect.x,
rect.y,
rect.width,
rect.height,
let zoomData = [aRect.x,
aRect.y,
aRect.width,
aRect.height,
presShellId.value,
viewId].join(",");
Services.obs.notifyObservers(null, "Metro:ZoomToRect", zoomData);
this._isZoomedIn = true;
},
_shouldZoomToElement: function(aElement) {

Просмотреть файл

@ -12,7 +12,7 @@
}
.devtools-monospace {
font-family: monospace;
font-family: Menlo, monospace;
font-size: 108%;
}

Просмотреть файл

@ -10,7 +10,7 @@
}
.devtools-monospace {
font-family: monospace;
font-family: Consolas, monospace;
}
/* Toolbar and Toolbar items */

Просмотреть файл

@ -4,19 +4,15 @@
package org.mozilla.gecko.annotationProcessors;
import java.lang.reflect.Method;
/**
* Object holding method and annotation. Used by GeneratableEntryPointIterator.
* Object holding annotation data. Used by GeneratableElementIterator.
*/
public class MethodWithAnnotationInfo {
public final Method method;
public class AnnotationInfo {
public final String wrapperName;
public final boolean isStatic;
public final boolean isMultithreaded;
public MethodWithAnnotationInfo(Method aMethod, String aWrapperName, boolean aIsStatic, boolean aIsMultithreaded) {
method = aMethod;
public AnnotationInfo(String aWrapperName, boolean aIsStatic, boolean aIsMultithreaded) {
wrapperName = aWrapperName;
isStatic = aIsStatic;
isMultithreaded = aIsMultithreaded;

Просмотреть файл

@ -4,8 +4,10 @@
package org.mozilla.gecko.annotationProcessors;
import org.mozilla.gecko.annotationProcessors.classloader.AnnotatableEntity;
import org.mozilla.gecko.annotationProcessors.classloader.ClassWithOptions;
import org.mozilla.gecko.annotationProcessors.classloader.IterableJarLoadingURLClassLoader;
import org.mozilla.gecko.annotationProcessors.utils.GeneratableEntryPointIterator;
import org.mozilla.gecko.annotationProcessors.utils.GeneratableElementIterator;
import java.io.FileOutputStream;
import java.io.IOException;
@ -16,6 +18,12 @@ public class AnnotationProcessor {
public static final String OUTFILE = "GeneratedJNIWrappers.cpp";
public static final String HEADERFILE = "GeneratedJNIWrappers.h";
public static final String GENERATED_COMMENT =
"// GENERATED CODE\n" +
"// Generated by the Java program at /build/annotationProcessors at compile time from\n" +
"// annotations on Java methods. To update, change the annotations on the corresponding Java\n" +
"// methods and rerun the build. Manually updating this file will cause your build to fail.\n\n";
public static void main(String[] args) {
// We expect a list of jars on the commandline. If missing, whinge about it.
if (args.length <= 1) {
@ -33,44 +41,121 @@ public class AnnotationProcessor {
long s = System.currentTimeMillis();
// Get an iterator over the classes in the jar files given...
Iterator<Class<?>> jarClassIterator = IterableJarLoadingURLClassLoader.getIteratorOverJars(args);
Iterator<ClassWithOptions> jarClassIterator = IterableJarLoadingURLClassLoader.getIteratorOverJars(args);
CodeGenerator generatorInstance = new CodeGenerator();
StringBuilder headerFile = new StringBuilder(GENERATED_COMMENT);
headerFile.append("#ifndef GeneratedJNIWrappers_h__\n" +
"#define GeneratedJNIWrappers_h__\n\n" +
"#include \"nsXPCOMStrings.h\"\n" +
"#include \"AndroidJavaWrappers.h\"\n" +
"\n" +
"namespace mozilla {\n" +
"namespace widget {\n" +
"namespace android {\n" +
"void InitStubs(JNIEnv *jEnv);\n\n");
StringBuilder implementationFile = new StringBuilder(GENERATED_COMMENT);
implementationFile.append("#include \"GeneratedJNIWrappers.h\"\n" +
"#include \"AndroidBridgeUtilities.h\"\n" +
"#include \"nsXPCOMStrings.h\"\n" +
"#include \"AndroidBridge.h\"\n" +
"\n" +
"namespace mozilla {\n" +
"namespace widget {\n" +
"namespace android {\n");
// Used to track the calls to the various class-specific initialisation functions.
StringBuilder stubInitialiser = new StringBuilder();
stubInitialiser.append("void InitStubs(JNIEnv *jEnv) {\n");
while (jarClassIterator.hasNext()) {
Class<?> aClass = jarClassIterator.next();
ClassWithOptions aClassTuple = jarClassIterator.next();
CodeGenerator generatorInstance;
// Get an iterator over the appropriately generated methods of this class
Iterator<MethodWithAnnotationInfo> methodIterator = new GeneratableEntryPointIterator(aClass.getDeclaredMethods());
Iterator<AnnotatableEntity> methodIterator = new GeneratableElementIterator(aClassTuple.wrappedClass);
// Iterate all annotated methods in this class..
if (!methodIterator.hasNext()) {
continue;
}
generatorInstance = new CodeGenerator(aClassTuple.wrappedClass, aClassTuple.generatedName);
stubInitialiser.append(" ").append(aClassTuple.generatedName).append("::InitStubs(jEnv);\n");
// Iterate all annotated members in this class..
while (methodIterator.hasNext()) {
MethodWithAnnotationInfo aMethodTuple = methodIterator.next();
generatorInstance.generateMethod(aMethodTuple, aClass);
AnnotatableEntity aElementTuple = methodIterator.next();
switch (aElementTuple.mEntityType) {
case METHOD:
generatorInstance.generateMethod(aElementTuple);
break;
case FIELD:
generatorInstance.generateField(aElementTuple);
break;
case CONSTRUCTOR:
generatorInstance.generateConstructor(aElementTuple);
break;
}
}
headerFile.append(generatorInstance.getHeaderFileContents());
implementationFile.append(generatorInstance.getWrapperFileContents());
}
writeOutputFiles(generatorInstance);
implementationFile.append('\n');
stubInitialiser.append("}");
implementationFile.append(stubInitialiser);
implementationFile.append("\n} /* android */\n" +
"} /* widget */\n" +
"} /* mozilla */\n");
headerFile.append("\n} /* android */\n" +
"} /* widget */\n" +
"} /* mozilla */\n" +
"#endif\n");
writeOutputFiles(headerFile, implementationFile);
long e = System.currentTimeMillis();
System.out.println("Annotation processing complete in " + (e - s) + "ms");
}
private static void writeOutputFiles(CodeGenerator aGenerator) {
private static void writeOutputFiles(StringBuilder aHeaderFile, StringBuilder aImplementationFile) {
FileOutputStream headerStream = null;
try {
FileOutputStream outStream = new FileOutputStream(OUTFILE);
outStream.write(aGenerator.getWrapperFileContents());
headerStream = new FileOutputStream(OUTFILE);
headerStream.write(aImplementationFile.toString().getBytes());
} catch (IOException e) {
System.err.println("Unable to write " + OUTFILE + ". Perhaps a permissions issue?");
e.printStackTrace(System.err);
} finally {
if (headerStream != null) {
try {
headerStream.close();
} catch (IOException e) {
System.err.println("Unable to close headerStream due to "+e);
e.printStackTrace(System.err);
}
}
}
FileOutputStream outStream = null;
try {
FileOutputStream headerStream = new FileOutputStream(HEADERFILE);
headerStream.write(aGenerator.getHeaderFileContents());
outStream = new FileOutputStream(HEADERFILE);
outStream.write(aHeaderFile.toString().getBytes());
} catch (IOException e) {
System.err.println("Unable to write " + OUTFILE + ". Perhaps a permissions issue?");
System.err.println("Unable to write " + HEADERFILE + ". Perhaps a permissions issue?");
e.printStackTrace(System.err);
} finally {
if (outStream != null) {
try {
outStream.close();
} catch (IOException e) {
System.err.println("Unable to close outStream due to "+e);
e.printStackTrace(System.err);
}
}
}
}
}

Просмотреть файл

@ -4,82 +4,236 @@
package org.mozilla.gecko.annotationProcessors;
import org.mozilla.gecko.annotationProcessors.classloader.AnnotatableEntity;
import org.mozilla.gecko.annotationProcessors.utils.Utils;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.HashSet;
public class CodeGenerator {
private static final Class<?>[] EMPTY_CLASS_ARRAY = new Class<?>[0];
private static final Annotation[][] GETTER_ARGUMENT_ANNOTATIONS = new Annotation[0][0];
private static final Annotation[][] SETTER_ARGUMENT_ANNOTATIONS = new Annotation[1][0];
// Buffers holding the strings to ultimately be written to the output files.
private final StringBuilder zeroingCode = new StringBuilder();
private final StringBuilder wrapperStartupCode = new StringBuilder();
private final StringBuilder wrapperMethodBodies = new StringBuilder();
private final StringBuilder headerFields = new StringBuilder();
private final StringBuilder headerMethods = new StringBuilder();
private final StringBuilder headerPublic = new StringBuilder();
private final StringBuilder headerProtected = new StringBuilder();
private final HashSet<String> seenClasses = new HashSet<String>();
private final String GENERATED_COMMENT = "// GENERATED CODE\n" +
"// Generated by the Java program at /build/annotationProcessors at compile time from\n" +
"// annotations on Java methods. To update, change the annotations on the corresponding Java\n" +
"// methods and rerun the build. Manually updating this file will cause your build to fail.\n\n";
private final String mCClassName;
private final Class<?> mClassToWrap;
private boolean mHasEncounteredDefaultConstructor;
// Used for creating unique names for method ID fields in the face of
private final HashMap<Member, String> mMembersToIds = new HashMap<Member, String>();
private final HashSet<String> mTakenMemberNames = new HashSet<String>();
private int mNameMunger;
public CodeGenerator(Class<?> aClass, String aGeneratedName) {
mClassToWrap = aClass;
mCClassName = aGeneratedName;
public CodeGenerator() {
// Write the file header things. Includes and so forth.
// GeneratedJNIWrappers.cpp is generated as the concatenation of wrapperStartupCode with
// wrapperMethodBodies. Similarly, GeneratedJNIWrappers.h is the concatenation of headerFields
// with headerMethods.
wrapperStartupCode.append(GENERATED_COMMENT);
wrapperStartupCode.append(
"#include \"nsXPCOMStrings.h\"\n" +
"#include \"AndroidBridge.h\"\n" +
"#include \"AndroidBridgeUtilities.h\"\n" +
"\n" +
"#ifdef DEBUG\n" +
"#define ALOG_BRIDGE(args...) ALOG(args)\n" +
"#else\n" +
"#define ALOG_BRIDGE(args...) ((void)0)\n" +
"#endif\n" +
"\n" +
"using namespace mozilla;\n" +
"void AndroidBridge::InitStubs(JNIEnv *jEnv) {\n" +
" initInit();\n");
// Now we write the various GetStaticMethodID calls here...
// wrapperMethodBodies. Similarly, GeneratedJNIWrappers.h is the concatenation of headerPublic
// with headerProtected.
wrapperStartupCode.append("void ").append(mCClassName).append("::InitStubs(JNIEnv *jEnv) {\n" +
" initInit();\n");
headerFields.append("protected:\n\n");
headerMethods.append(GENERATED_COMMENT);
headerMethods.append("public:\n\n");
// Now we write the various GetStaticMethodID calls here...
headerPublic.append("class ").append(mCClassName).append(" : public AutoGlobalWrappedJavaObject {\n" +
"public:\n" +
" static void InitStubs(JNIEnv *jEnv);\n");
headerProtected.append("protected:");
generateWrapperMethod();
}
/**
* Emit a static method which takes an instance of the class being wrapped and returns an instance
* of the C++ wrapper class backed by that object.
*/
private void generateWrapperMethod() {
headerPublic.append(" static ").append(mCClassName).append("* Wrap(jobject obj);\n" +
" ").append(mCClassName).append("(jobject obj, JNIEnv* env) : AutoGlobalWrappedJavaObject(obj, env) {};\n");
wrapperMethodBodies.append("\n").append(mCClassName).append("* ").append(mCClassName).append("::Wrap(jobject obj) {\n" +
" JNIEnv *env = GetJNIForThread();\n\n" +
" if (!env) {\n" +
" ALOG_BRIDGE(\"Aborted: No env - %s\", __PRETTY_FUNCTION__);\n" +
" return NULL;\n" +
" }\n\n" +
" ").append(mCClassName).append("* ret = new ").append(mCClassName).append("(obj, env);\n" +
" env->DeleteLocalRef(obj);\n" +
" return ret;\n" +
"}\n");
}
private void generateMemberCommon(Member theMethod, String aCMethodName, Class<?> aClass) {
ensureClassHeaderAndStartup(aClass);
writeMemberIdField(theMethod, aCMethodName);
writeStartupCode(theMethod);
}
/**
* Append the appropriate generated code to the buffers for the method provided.
*
* @param aMethodTuple The Java method, plus the name for the generated method.
* @param aClass The class to which the Java method belongs.
* @param aMethodTuple The Java method, plus annotation data.
*/
public void generateMethod(MethodWithAnnotationInfo aMethodTuple, Class<?> aClass) {
public void generateMethod(AnnotatableEntity aMethodTuple) {
// Unpack the tuple and extract some useful fields from the Method..
Method aMethod = aMethodTuple.method;
String CMethodName = aMethodTuple.wrapperName;
Method theMethod = aMethodTuple.getMethod();
String javaMethodName = aMethod.getName();
String CMethodName = aMethodTuple.mAnnotationInfo.wrapperName;
ensureClassHeaderAndStartup(aClass);
generateMemberCommon(theMethod, CMethodName, mClassToWrap);
writeHeaderField(CMethodName);
writeStartupCode(CMethodName, javaMethodName, aMethod, aClass);
boolean isFieldStatic = Utils.isMemberStatic(theMethod);
boolean shallGenerateStatic = isFieldStatic || aMethodTuple.mAnnotationInfo.isStatic;
Class<?>[] parameterTypes = theMethod.getParameterTypes();
Class<?> returnType = theMethod.getReturnType();
// Get the C++ method signature for this method.
String implementationSignature = Utils.getCImplementationMethodSignature(aMethod, CMethodName);
String headerSignature = Utils.getCHeaderMethodSignature(aMethod, CMethodName, aMethodTuple.isStatic);
String implementationSignature = Utils.getCImplementationMethodSignature(parameterTypes, returnType, CMethodName, mCClassName);
String headerSignature = Utils.getCHeaderMethodSignature(parameterTypes, theMethod.getParameterAnnotations(), returnType, CMethodName, mCClassName, shallGenerateStatic);
// Add the header signature to the header file.
headerMethods.append(headerSignature);
headerMethods.append(";\n");
writeSignatureToHeader(headerSignature);
// Use the implementation signature to generate the method body...
writeMethodBody(implementationSignature, CMethodName, aMethod, aClass, aMethodTuple.isStatic, aMethodTuple.isMultithreaded);
writeMethodBody(implementationSignature, CMethodName, theMethod, mClassToWrap, aMethodTuple.mAnnotationInfo.isStatic, aMethodTuple.mAnnotationInfo.isMultithreaded);
}
private void generateGetterOrSetterBody(Class<?> aFieldType, String aFieldName, boolean aIsFieldStatic, boolean isSetter) {
StringBuilder argumentContent = null;
if (isSetter) {
Class<?>[] setterArguments = new Class<?>[]{aFieldType};
// Marshall the argument..
argumentContent = getArgumentMarshalling(setterArguments);
}
boolean isObjectReturningMethod = Utils.isObjectType(aFieldType);
wrapperMethodBodies.append(" ");
if (isSetter) {
wrapperMethodBodies.append("env->Set");
} else {
wrapperMethodBodies.append("return ");
if (isObjectReturningMethod) {
wrapperMethodBodies.append("static_cast<").append(Utils.getCReturnType(aFieldType)).append(">(");
}
wrapperMethodBodies.append("env->Get");
}
if (aIsFieldStatic) {
wrapperMethodBodies.append("Static");
}
wrapperMethodBodies.append(Utils.getFieldType(aFieldType))
.append("Field(");
// Static will require the class and the field id. Nonstatic, the object and the field id.
if (aIsFieldStatic) {
wrapperMethodBodies.append(Utils.getClassReferenceName(mClassToWrap));
} else {
wrapperMethodBodies.append("wrapped_obj");
}
wrapperMethodBodies.append(", j")
.append(aFieldName);
if (isSetter) {
wrapperMethodBodies.append(argumentContent);
}
if (!isSetter && isObjectReturningMethod) {
wrapperMethodBodies.append(')');
}
wrapperMethodBodies.append(");\n" +
"}\n");
}
public void generateField(AnnotatableEntity aFieldTuple) {
Field theField = aFieldTuple.getField();
// Handles a peculiar case when dealing with enum types. We don't care about this field.
// It just gets in the way and stops our code from compiling.
if (theField.getName().equals("$VALUES")) {
return;
}
String CFieldName = aFieldTuple.mAnnotationInfo.wrapperName;
Class<?> fieldType = theField.getType();
generateMemberCommon(theField, CFieldName, mClassToWrap);
boolean isFieldStatic = Utils.isMemberStatic(theField);
boolean isFieldFinal = Utils.isMemberFinal(theField);
boolean shallGenerateStatic = isFieldStatic || aFieldTuple.mAnnotationInfo.isStatic;
String getterName = "get" + CFieldName;
String getterSignature = Utils.getCImplementationMethodSignature(EMPTY_CLASS_ARRAY, fieldType, getterName, mCClassName);
String getterHeaderSignature = Utils.getCHeaderMethodSignature(EMPTY_CLASS_ARRAY, GETTER_ARGUMENT_ANNOTATIONS, fieldType, getterName, mCClassName, shallGenerateStatic);
writeSignatureToHeader(getterHeaderSignature);
writeFunctionStartupBoilerPlate(getterSignature, fieldType, isFieldStatic, true);
generateGetterOrSetterBody(fieldType, CFieldName, isFieldStatic, false);
// If field not final, also generate a setter function.
if (!isFieldFinal) {
String setterName = "set" + CFieldName;
Class<?>[] setterArguments = new Class<?>[]{fieldType};
String setterSignature = Utils.getCImplementationMethodSignature(setterArguments, Void.class, setterName, mCClassName);
String setterHeaderSignature = Utils.getCHeaderMethodSignature(setterArguments, SETTER_ARGUMENT_ANNOTATIONS, Void.class, setterName, mCClassName, shallGenerateStatic);
writeSignatureToHeader(setterHeaderSignature);
writeFunctionStartupBoilerPlate(setterSignature, Void.class, isFieldStatic, true);
generateGetterOrSetterBody(fieldType, CFieldName, isFieldStatic, true);
}
}
public void generateConstructor(AnnotatableEntity aCtorTuple) {
// Unpack the tuple and extract some useful fields from the Method..
Constructor theCtor = aCtorTuple.getConstructor();
String CMethodName = mCClassName;
generateMemberCommon(theCtor, mCClassName, mClassToWrap);
String implementationSignature = Utils.getCImplementationMethodSignature(theCtor.getParameterTypes(), Void.class, CMethodName, mCClassName);
String headerSignature = Utils.getCHeaderMethodSignature(theCtor.getParameterTypes(), theCtor.getParameterAnnotations(), Void.class, CMethodName, mCClassName, false);
// Slice off the "void " from the start of the constructor declaration.
headerSignature = headerSignature.substring(5);
implementationSignature = implementationSignature.substring(5);
// Add the header signatures to the header file.
writeSignatureToHeader(headerSignature);
// Use the implementation signature to generate the method body...
writeCtorBody(implementationSignature, theCtor, aCtorTuple.mAnnotationInfo.isMultithreaded);
if (theCtor.getParameterTypes().length == 0) {
mHasEncounteredDefaultConstructor = true;
}
}
/**
@ -94,18 +248,169 @@ public class CodeGenerator {
return;
}
zeroingCode.append("jclass ")
.append(mCClassName)
.append("::")
.append(Utils.getClassReferenceName(aClass))
.append(" = 0;\n");
// Add a field to hold the reference...
headerFields.append("\njclass ");
headerFields.append(Utils.getClassReferenceName(aClass));
headerFields.append(";\n");
headerProtected.append("\n static jclass ")
.append(Utils.getClassReferenceName(aClass))
.append(";\n");
// Add startup code to populate it..
wrapperStartupCode.append('\n');
wrapperStartupCode.append(Utils.getStartupLineForClass(aClass));
wrapperStartupCode.append('\n')
.append(Utils.getStartupLineForClass(aClass));
seenClasses.add(className);
}
/**
* Write out the function startup boilerplate for the method described. Check for environment
* existence,
* @param methodSignature
* @param returnType
* @param aIsStatic
* @param aIsThreaded
*/
private void writeFunctionStartupBoilerPlate(String methodSignature, Class<?> returnType, boolean aIsStatic, boolean aIsThreaded) {
// The start-of-function boilerplate. Does the bridge exist? Does the env exist? etc.
wrapperMethodBodies.append('\n')
.append(methodSignature)
.append(" {\n");
wrapperMethodBodies.append(" JNIEnv *env = ");
if (!aIsThreaded) {
wrapperMethodBodies.append("AndroidBridge::GetJNIEnv();\n");
} else {
wrapperMethodBodies.append("GetJNIForThread();\n");
}
wrapperMethodBodies.append(" if (!env) {\n" +
" ALOG_BRIDGE(\"Aborted: No env - %s\", __PRETTY_FUNCTION__);\n" +
" return").append(Utils.getFailureReturnForType(returnType)).append(";\n" +
" }\n\n");
}
/**
* Write out the appropriate JNI frame pushing boilerplate for a call to the member provided (
* which must be a constructor or method).
*
* @param aMethod A constructor/method being wrapped.
* @param aIsObjectReturningMethod Does the method being wrapped return an object?
*/
private void writeFramePushBoilerplate(Member aMethod, boolean aIsObjectReturningMethod) {
if (aMethod instanceof Field) {
throw new IllegalArgumentException("Tried to push frame for a FIELD?!");
}
Method m;
Constructor c;
Class<?> returnType;
int localReferencesNeeded;
if (aMethod instanceof Method) {
m = (Method) aMethod;
returnType = m.getReturnType();
localReferencesNeeded = Utils.enumerateReferenceArguments(m.getParameterTypes());
} else {
c = (Constructor) aMethod;
returnType = Void.class;
localReferencesNeeded = Utils.enumerateReferenceArguments(c.getParameterTypes());
}
// Determine the number of local refs required for our local frame..
// AutoLocalJNIFrame is not applicable here due to it's inability to handle return values.
if (aIsObjectReturningMethod) {
localReferencesNeeded++;
}
wrapperMethodBodies.append(" if (env->PushLocalFrame(").append(localReferencesNeeded).append(") != 0) {\n" +
" ALOG_BRIDGE(\"Exceptional exit of: %s\", __PRETTY_FUNCTION__);\n" +
" env->ExceptionDescribe();\n"+
" env->ExceptionClear();\n" +
" return").append(Utils.getFailureReturnForType(returnType)).append(";\n" +
" }\n\n");
}
private StringBuilder getArgumentMarshalling(Class<?>[] argumentTypes) {
StringBuilder argumentContent = new StringBuilder();
// If we have >2 arguments, use the jvalue[] calling approach.
argumentContent.append(", ");
if (argumentTypes.length > 2) {
wrapperMethodBodies.append(" jvalue args[").append(argumentTypes.length).append("];\n");
for (int aT = 0; aT < argumentTypes.length; aT++) {
wrapperMethodBodies.append(" args[").append(aT).append("].")
.append(Utils.getArrayArgumentMashallingLine(argumentTypes[aT], "a" + aT));
}
// The only argument is the array of arguments.
argumentContent.append("args");
wrapperMethodBodies.append('\n');
} else {
// Otherwise, use the vanilla calling approach.
boolean needsNewline = false;
for (int aT = 0; aT < argumentTypes.length; aT++) {
// If the argument is a string-esque type, create a jstring from it, otherwise
// it can be passed directly.
if (Utils.isCharSequence(argumentTypes[aT])) {
wrapperMethodBodies.append(" jstring j").append(aT).append(" = AndroidBridge::NewJavaString(env, a").append(aT).append(");\n");
needsNewline = true;
// Ensure we refer to the newly constructed Java string - not to the original
// parameter to the wrapper function.
argumentContent.append('j').append(aT);
} else {
argumentContent.append('a').append(aT);
}
if (aT != argumentTypes.length - 1) {
argumentContent.append(", ");
}
}
if (needsNewline) {
wrapperMethodBodies.append('\n');
}
}
return argumentContent;
}
private void writeCtorBody(String implementationSignature, Constructor theCtor, boolean aIsThreaded) {
Class<?>[] argumentTypes = theCtor.getParameterTypes();
writeFunctionStartupBoilerPlate(implementationSignature, Void.class, false, aIsThreaded);
writeFramePushBoilerplate(theCtor, false);
// Marshall arguments for this constructor, if any...
boolean hasArguments = argumentTypes.length != 0;
StringBuilder argumentContent = new StringBuilder();
if (hasArguments) {
argumentContent = getArgumentMarshalling(argumentTypes);
}
// The call into Java
wrapperMethodBodies.append(" Init(env->NewObject");
if (argumentTypes.length > 2) {
wrapperMethodBodies.append('A');
}
wrapperMethodBodies.append('(');
// Call takes class id, method id of constructor method, then arguments.
wrapperMethodBodies.append(Utils.getClassReferenceName(mClassToWrap)).append(", ");
wrapperMethodBodies.append(mMembersToIds.get(theCtor))
// Tack on the arguments, if any..
.append(argumentContent)
.append("), env);\n" +
" env->PopLocalFrame(NULL);\n" +
"}\n");
}
/**
* Generates the method body of the C++ wrapper function for the Java method indicated.
*
@ -119,44 +424,11 @@ public class CodeGenerator {
Class<?>[] argumentTypes = aMethod.getParameterTypes();
Class<?> returnType = aMethod.getReturnType();
// The start-of-function boilerplate. Does the bridge exist? Does the env exist? etc.
wrapperMethodBodies.append('\n');
wrapperMethodBodies.append(methodSignature);
writeFunctionStartupBoilerPlate(methodSignature, returnType, aIsStaticBridgeMethod, aIsMultithreaded);
wrapperMethodBodies.append(" {\n");
boolean isObjectReturningMethod = !returnType.getCanonicalName().equals("void") && Utils.isObjectType(returnType);
// Static stubs check the bridge instance has been created before trying to run.
if (aIsStaticBridgeMethod) {
wrapperMethodBodies.append(" if (!sBridge) {\n" +
" ALOG_BRIDGE(\"Aborted: No sBridge - %s\", __PRETTY_FUNCTION__);\n" +
" return").append(Utils.getFailureReturnForType(returnType)).append(";\n" +
" }\n\n");
}
wrapperMethodBodies.append(" JNIEnv *env = ");
if (!aIsMultithreaded) {
wrapperMethodBodies.append("GetJNIEnv();\n");
} else {
wrapperMethodBodies.append("GetJNIForThread();\n");
}
wrapperMethodBodies.append(" if (!env) {\n" +
" ALOG_BRIDGE(\"Aborted: No env - %s\", __PRETTY_FUNCTION__);\n" +
" return").append(Utils.getFailureReturnForType(returnType)).append(";\n" +
" }\n\n");
boolean isObjectReturningMethod = !returnType.getCanonicalName().equals("void") && Utils.doesReturnObjectType(aMethod);
// Determine the number of local refs required for our local frame..
// AutoLocalJNIFrame is not applicable here due to it's inability to handle return values.
int localReferencesNeeded = Utils.enumerateReferenceArguments(aMethod);
if (isObjectReturningMethod) {
localReferencesNeeded++;
}
wrapperMethodBodies.append(" if (env->PushLocalFrame(").append(localReferencesNeeded).append(") != 0) {\n" +
" ALOG_BRIDGE(\"Exceptional exit of: %s\", __PRETTY_FUNCTION__);\n" +
" env->ExceptionDescribe();\n"+
" env->ExceptionClear();\n" +
" return").append(Utils.getFailureReturnForType(returnType)).append(";\n" +
" }\n\n");
writeFramePushBoilerplate(aMethod, isObjectReturningMethod);
// Marshall arguments, if we have any.
boolean hasArguments = argumentTypes.length != 0;
@ -168,43 +440,10 @@ public class CodeGenerator {
// argumentContent).
StringBuilder argumentContent = new StringBuilder();
if (hasArguments) {
argumentContent.append(", ");
// If we have >2 arguments, use the jvalue[] calling approach.
if (argumentTypes.length > 2) {
wrapperMethodBodies.append(" jvalue args[").append(argumentTypes.length).append("];\n");
for (int aT = 0; aT < argumentTypes.length; aT++) {
wrapperMethodBodies.append(" args[").append(aT).append("].");
wrapperMethodBodies.append(Utils.getArrayArgumentMashallingLine(argumentTypes[aT], "a" + aT));
}
// The only argument is the array of arguments.
argumentContent.append("args");
wrapperMethodBodies.append('\n');
} else {
// Otherwise, use the vanilla calling approach.
boolean needsNewline = false;
for (int aT = 0; aT < argumentTypes.length; aT++) {
// If the argument is a string-esque type, create a jstring from it, otherwise
// it can be passed directly.
if (Utils.isCharSequence(argumentTypes[aT])) {
wrapperMethodBodies.append(" jstring j").append(aT).append(" = NewJavaString(env, a").append(aT).append(");\n");
needsNewline = true;
// Ensure we refer to the newly constructed Java string - not to the original
// parameter to the wrapper function.
argumentContent.append('j').append(aT);
} else {
argumentContent.append('a').append(aT);
}
if (aT != argumentTypes.length - 1) {
argumentContent.append(", ");
}
}
if (needsNewline) {
wrapperMethodBodies.append('\n');
}
}
argumentContent = getArgumentMarshalling(argumentTypes);
}
// Allocate a temporary variable to hold the return type from Java.
wrapperMethodBodies.append(" ");
if (!returnType.getCanonicalName().equals("void")) {
if (isObjectReturningMethod) {
@ -215,11 +454,11 @@ public class CodeGenerator {
wrapperMethodBodies.append(" temp = ");
}
boolean isStaticJavaMethod = Utils.isMethodStatic(aMethod);
boolean isStaticJavaMethod = Utils.isMemberStatic(aMethod);
// The call into Java
wrapperMethodBodies.append("env->");
wrapperMethodBodies.append(Utils.getCallPrefix(returnType, isStaticJavaMethod));
wrapperMethodBodies.append("env->")
.append(Utils.getCallPrefix(returnType, isStaticJavaMethod));
if (argumentTypes.length > 2) {
wrapperMethodBodies.append('A');
}
@ -227,28 +466,18 @@ public class CodeGenerator {
wrapperMethodBodies.append('(');
// If the underlying Java method is nonstatic, we provide the target object to the JNI.
if (!isStaticJavaMethod) {
wrapperMethodBodies.append("aTarget, ");
wrapperMethodBodies.append("wrapped_obj, ");
} else {
// If the stub to be generated is static, we need to use the singleton to access the class
// reference.
if (aIsStaticBridgeMethod) {
wrapperMethodBodies.append("sBridge->");
}
// If this is a static underlyin Java method, we need to use the class reference in our
// If this is a static underlying Java method, we need to use the class reference in our
// call.
wrapperMethodBodies.append(Utils.getClassReferenceName(aClass)).append(", ");
}
// Write the method id out..
if (aIsStaticBridgeMethod) {
wrapperMethodBodies.append("sBridge->");
}
wrapperMethodBodies.append('j');
wrapperMethodBodies.append(aCMethodName);
wrapperMethodBodies.append(mMembersToIds.get(aMethod));
// Tack on the arguments, if any..
wrapperMethodBodies.append(argumentContent);
wrapperMethodBodies.append(");\n\n");
wrapperMethodBodies.append(argumentContent)
.append(");\n\n");
// Check for exception and return the failure value..
wrapperMethodBodies.append(" if (env->ExceptionCheck()) {\n" +
@ -257,14 +486,14 @@ public class CodeGenerator {
" env->ExceptionClear();\n" +
" env->PopLocalFrame(NULL);\n" +
" return").append(Utils.getFailureReturnForType(returnType)).append(";\n" +
" }\n");
" }\n\n");
// If we're returning an object, pop the callee's stack frame extracting our ref as the return
// value.
if (isObjectReturningMethod) {
wrapperMethodBodies.append(" ");
wrapperMethodBodies.append(Utils.getCReturnType(returnType));
wrapperMethodBodies.append(" ret = static_cast<").append(Utils.getCReturnType(returnType)).append(">(env->PopLocalFrame(temp));\n" +
wrapperMethodBodies.append(" ")
.append(Utils.getCReturnType(returnType))
.append(" ret = static_cast<").append(Utils.getCReturnType(returnType)).append(">(env->PopLocalFrame(temp));\n" +
" return ret;\n");
} else if (!returnType.getCanonicalName().equals("void")) {
// If we're a primitive-returning function, just return the directly-obtained primative
@ -279,35 +508,83 @@ public class CodeGenerator {
}
/**
* Generates the code to get the method id of the given method on startup.
* Generates the code to get the id of the given member on startup.
*
* @param aCMethodName The C method name of the method being generated.
* @param aJavaMethodName The name of the Java method being wrapped.
* @param aMethod The Java method being wrapped.
* @param aMember The Java member being wrapped.
*/
private void writeStartupCode(String aCMethodName, String aJavaMethodName, Method aMethod, Class<?> aClass) {
wrapperStartupCode.append(" j");
wrapperStartupCode.append(aCMethodName);
wrapperStartupCode.append(" = get");
if (Utils.isMethodStatic(aMethod)) {
private void writeStartupCode(Member aMember) {
wrapperStartupCode.append(" ")
.append(mMembersToIds.get(aMember))
.append(" = get");
if (Utils.isMemberStatic(aMember)) {
wrapperStartupCode.append("Static");
}
wrapperStartupCode.append("Method(\"");
wrapperStartupCode.append(aJavaMethodName);
wrapperStartupCode.append("\", \"");
wrapperStartupCode.append(Utils.getTypeSignatureString(aMethod));
wrapperStartupCode.append("\");\n");
boolean isField = aMember instanceof Field;
if (isField) {
wrapperStartupCode.append("Field(\"");
} else {
wrapperStartupCode.append("Method(\"");
}
if (aMember instanceof Constructor) {
wrapperStartupCode.append("<init>");
} else {
wrapperStartupCode.append(aMember.getName());
}
wrapperStartupCode.append("\", \"")
.append(Utils.getTypeSignatureStringForMember(aMember))
.append("\");\n");
}
private void writeZeroingFor(Member aMember, final String aMemberName) {
if (aMember instanceof Field) {
zeroingCode.append("jfieldID ");
} else {
zeroingCode.append("jmethodID ");
}
zeroingCode.append(mCClassName)
.append("::")
.append(aMemberName)
.append(" = 0;\n");
}
/**
* Create a method id field in the header file for the C method name provided.
* Write the field declaration for the C++ id field of the given member.
*
* @param aMethodName C method name to generate a method id field for.
* @param aMember Member for which an id field needs to be generated.
*/
private void writeHeaderField(String aMethodName) {
headerFields.append("jmethodID j");
headerFields.append(aMethodName);
headerFields.append(";\n");
private void writeMemberIdField(Member aMember, final String aCMethodName) {
String memberName = 'j'+ aCMethodName;
if (aMember instanceof Field) {
headerProtected.append(" static jfieldID ");
} else {
headerProtected.append(" static jmethodID ");
}
while(mTakenMemberNames.contains(memberName)) {
memberName = 'j' + aCMethodName + mNameMunger;
mNameMunger++;
}
writeZeroingFor(aMember, memberName);
mMembersToIds.put(aMember, memberName);
mTakenMemberNames.add(memberName);
headerProtected.append(memberName)
.append(";\n");
}
/**
* Helper function to add a provided method signature to the public section of the generated header.
*
* @param aSignature The header to add.
*/
private void writeSignatureToHeader(String aSignature) {
headerPublic.append(" ")
.append(aSignature)
.append(";\n");
}
/**
@ -315,11 +592,13 @@ public class CodeGenerator {
*
* @return The bytes to be written to the wrappers file.
*/
public byte[] getWrapperFileContents() {
public String getWrapperFileContents() {
wrapperStartupCode.append("}\n");
wrapperStartupCode.append(wrapperMethodBodies);
zeroingCode.append(wrapperStartupCode)
.append(wrapperMethodBodies);
wrapperMethodBodies.setLength(0);
return wrapperStartupCode.toString().getBytes();
wrapperStartupCode.setLength(0);
return zeroingCode.toString();
}
/**
@ -327,10 +606,13 @@ public class CodeGenerator {
*
* @return The bytes to be written to the header file.
*/
public byte[] getHeaderFileContents() {
headerFields.append('\n');
headerFields.append(headerMethods);
headerMethods.setLength(0);
return headerFields.toString().getBytes();
public String getHeaderFileContents() {
if (!mHasEncounteredDefaultConstructor) {
headerPublic.append(" ").append(mCClassName).append("() : AutoGlobalWrappedJavaObject() {};\n");
}
headerProtected.append("};\n\n");
headerPublic.append(headerProtected);
headerProtected.setLength(0);
return headerPublic.toString();
}
}

Просмотреть файл

@ -0,0 +1,57 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.gecko.annotationProcessors.classloader;
import org.mozilla.gecko.annotationProcessors.AnnotationInfo;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
/**
* Union type to hold either a method, field, or ctor. Allows us to iterate "The generatable stuff", despite
* the fact that such things can be of either flavour.
*/
public class AnnotatableEntity {
public enum ENTITY_TYPE {METHOD, FIELD, CONSTRUCTOR}
private final Member mMember;
public final ENTITY_TYPE mEntityType;
public final AnnotationInfo mAnnotationInfo;
public AnnotatableEntity(Member aObject, AnnotationInfo aAnnotationInfo) {
mMember = aObject;
mAnnotationInfo = aAnnotationInfo;
if (aObject instanceof Method) {
mEntityType = ENTITY_TYPE.METHOD;
} else if (aObject instanceof Field) {
mEntityType = ENTITY_TYPE.FIELD;
} else {
mEntityType = ENTITY_TYPE.CONSTRUCTOR;
}
}
public Method getMethod() {
if (mEntityType != ENTITY_TYPE.METHOD) {
throw new UnsupportedOperationException("Attempt to cast to unsupported member type.");
}
return (Method) mMember;
}
public Field getField() {
if (mEntityType != ENTITY_TYPE.FIELD) {
throw new UnsupportedOperationException("Attempt to cast to unsupported member type.");
}
return (Field) mMember;
}
public Constructor getConstructor() {
if (mEntityType != ENTITY_TYPE.CONSTRUCTOR) {
throw new UnsupportedOperationException("Attempt to cast to unsupported member type.");
}
return (Constructor) mMember;
}
}

Просмотреть файл

@ -0,0 +1,15 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.gecko.annotationProcessors.classloader;
public class ClassWithOptions {
public final Class<?> wrappedClass;
public final String generatedName;
public ClassWithOptions(Class<?> someClass, String name) {
wrappedClass = someClass;
generatedName = name;
}
}

Просмотреть файл

@ -21,8 +21,6 @@ import java.util.jar.JarFile;
* classNames is kept sorted to ensure iteration order is consistent across program invocations.
* Otherwise, we'd forever be reporting the outdatedness of the generated code as we permute its
* contents.
* This classloader does not support inner classes. (You probably shouldn't be putting JNI entry
* points in inner classes anyway)
*/
public class IterableJarLoadingURLClassLoader extends URLClassLoader {
LinkedList<String> classNames = new LinkedList<String>();
@ -35,7 +33,7 @@ public class IterableJarLoadingURLClassLoader extends URLClassLoader {
* @param args A list of jar file names an iterator over the classes of which is desired.
* @return An iterator over the top level classes in the jar files provided, in arbitrary order.
*/
public static Iterator<Class<?>> getIteratorOverJars(String[] args) {
public static Iterator<ClassWithOptions> getIteratorOverJars(String[] args) {
URL[] urlArray = new URL[args.length];
LinkedList<String> aClassNames = new LinkedList<String>();
@ -51,10 +49,7 @@ public class IterableJarLoadingURLClassLoader extends URLClassLoader {
continue;
}
final String className = fName.substring(0, fName.length() - 6).replace('/', '.');
// Inner classes are not supported.
if (className.contains("$")) {
continue;
}
aClassNames.add(className);
}
} catch (IOException e) {

Просмотреть файл

@ -4,12 +4,15 @@
package org.mozilla.gecko.annotationProcessors.classloader;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Iterator;
/**
* Class for iterating over an IterableJarLoadingURLClassLoader's classes.
*/
public class JarClassIterator implements Iterator<Class<?>> {
public class JarClassIterator implements Iterator<ClassWithOptions> {
private IterableJarLoadingURLClassLoader mTarget;
private Iterator<String> mTargetClassListIterator;
@ -24,10 +27,44 @@ public class JarClassIterator implements Iterator<Class<?>> {
}
@Override
public Class<?> next() {
public ClassWithOptions next() {
String className = mTargetClassListIterator.next();
try {
return mTarget.loadClass(className);
Class<?> ret = mTarget.loadClass(className);
if (ret.getCanonicalName() == null || "null".equals(ret.getCanonicalName())) {
// Anonymous inner class - unsupported.
return next();
} else {
String generateName = null;
for (Annotation annotation : ret.getAnnotations()) {
Class<?> annotationType = annotation.annotationType();
if (annotationType.getCanonicalName().equals("org.mozilla.gecko.mozglue.generatorannotations.GeneratorOptions")) {
try {
// Determine the explicitly-given name of the stub to generate, if any.
final Method generateNameMethod = annotationType.getDeclaredMethod("generatedClassName");
generateNameMethod.setAccessible(true);
generateName = (String) generateNameMethod.invoke(annotation);
break;
} catch (NoSuchMethodException e) {
System.err.println("Unable to find expected field on GeneratorOptions annotation. Did the signature change?");
e.printStackTrace(System.err);
System.exit(3);
} catch (IllegalAccessException e) {
System.err.println("IllegalAccessException reading fields on GeneratorOptions annotation. Seems the semantics of Reflection have changed...");
e.printStackTrace(System.err);
System.exit(4);
} catch (InvocationTargetException e) {
System.err.println("InvocationTargetException reading fields on GeneratorOptions annotation. This really shouldn't happen.");
e.printStackTrace(System.err);
System.exit(5);
}
}
}
if (generateName == null) {
generateName = ret.getSimpleName();
}
return new ClassWithOptions(ret, generateName);
}
} catch (ClassNotFoundException e) {
System.err.println("Unable to enumerate class: " + className + ". Corrupted jar file?");
e.printStackTrace();

Просмотреть файл

@ -6,12 +6,14 @@
jar = add_java_jar('annotationProcessors')
jar.sources += [
'AnnotationInfo.java',
'AnnotationProcessor.java',
'classloader/AnnotatableEntity.java',
'classloader/ClassWithOptions.java',
'classloader/IterableJarLoadingURLClassLoader.java',
'classloader/JarClassIterator.java',
'CodeGenerator.java',
'MethodWithAnnotationInfo.java',
'utils/AlphabeticMethodComparator.java',
'utils/GeneratableEntryPointIterator.java',
'utils/AlphabeticAnnotatableEntityComparator.java',
'utils/GeneratableElementIterator.java',
'utils/Utils.java',
]

Просмотреть файл

@ -0,0 +1,81 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.gecko.annotationProcessors.utils;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.util.Comparator;
public class AlphabeticAnnotatableEntityComparator<T extends Member> implements Comparator<T> {
@Override
public int compare(T aLhs, T aRhs) {
// Constructors, Methods, Fields.
boolean lIsConstructor = aLhs instanceof Constructor;
boolean rIsConstructor = aRhs instanceof Constructor;
boolean lIsMethod = aLhs instanceof Method;
boolean rIsField = aRhs instanceof Field;
if (lIsConstructor) {
if (!rIsConstructor) {
return -1;
}
} else if (lIsMethod) {
if (rIsConstructor) {
return 1;
} else if (rIsField) {
return -1;
}
} else {
if (!rIsField) {
return 1;
}
}
// Verify these objects are the same type and cast them.
if (aLhs instanceof Method) {
return compare((Method) aLhs, (Method) aRhs);
} else if (aLhs instanceof Field) {
return compare((Field) aLhs, (Field) aRhs);
} else {
return compare((Constructor) aLhs, (Constructor) aRhs);
}
}
// Alas, the type system fails us.
private static int compare(Method aLhs, Method aRhs) {
// Initially, attempt to differentiate the methods be name alone..
String lName = aLhs.getName();
String rName = aRhs.getName();
int ret = lName.compareTo(rName);
if (ret != 0) {
return ret;
}
// The names were the same, so we need to compare signatures to find their uniqueness..
lName = Utils.getTypeSignatureStringForMethod(aLhs);
rName = Utils.getTypeSignatureStringForMethod(aRhs);
return lName.compareTo(rName);
}
private static int compare(Constructor aLhs, Constructor aRhs) {
// The names will be the same, so we need to compare signatures to find their uniqueness..
String lName = Utils.getTypeSignatureString(aLhs);
String rName = Utils.getTypeSignatureString(aRhs);
return lName.compareTo(rName);
}
private static int compare(Field aLhs, Field aRhs) {
// Compare field names..
String lName = aLhs.getName();
String rName = aRhs.getName();
return lName.compareTo(rName);
}
}

Просмотреть файл

@ -1,28 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.gecko.annotationProcessors.utils;
import java.lang.reflect.Method;
import java.util.Comparator;
public class AlphabeticMethodComparator implements Comparator<Method> {
@Override
public int compare(Method lhs, Method rhs) {
// Initially, attempt to differentiate the methods be name alone..
String lName = lhs.getName();
String rName = rhs.getName();
int ret = lName.compareTo(rName);
if (ret != 0) {
return ret;
}
// The names were the same, so we need to compare signatures to find their uniqueness..
lName = Utils.getTypeSignatureString(lhs);
rName = Utils.getTypeSignatureString(rhs);
return lName.compareTo(rName);
}
}

Просмотреть файл

@ -4,31 +4,57 @@
package org.mozilla.gecko.annotationProcessors.utils;
import org.mozilla.gecko.annotationProcessors.MethodWithAnnotationInfo;
import org.mozilla.gecko.annotationProcessors.AnnotationInfo;
import org.mozilla.gecko.annotationProcessors.classloader.AnnotatableEntity;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
/**
* Iterator over the methods in a given method list which have the GeneratableAndroidBridgeTarget
* Iterator over the methods in a given method list which have the WrappedJNIMethod
* annotation. Returns an object containing both the annotation (Which may contain interesting
* parameters) and the argument.
*/
public class GeneratableEntryPointIterator implements Iterator<MethodWithAnnotationInfo> {
private final Method[] mMethods;
private MethodWithAnnotationInfo mNextReturnValue;
private int mMethodIndex;
public class GeneratableElementIterator implements Iterator<AnnotatableEntity> {
private final Member[] mObjects;
private AnnotatableEntity mNextReturnValue;
private int mElementIndex;
public GeneratableEntryPointIterator(Method[] aMethods) {
// Sort the methods into alphabetical order by name, to ensure we always iterate methods
// in the same order..
Arrays.sort(aMethods, new AlphabeticMethodComparator());
mMethods = aMethods;
private boolean mIterateEveryEntry;
public GeneratableElementIterator(Class<?> aClass) {
// Get all the elements of this class as AccessibleObjects.
Member[] aMethods = aClass.getDeclaredMethods();
Member[] aFields = aClass.getDeclaredFields();
Member[] aCtors = aClass.getConstructors();
// Shove them all into one buffer.
Member[] objs = new Member[aMethods.length + aFields.length + aCtors.length];
int offset = 0;
System.arraycopy(aMethods, 0, objs, 0, aMethods.length);
offset += aMethods.length;
System.arraycopy(aFields, 0, objs, offset, aFields.length);
offset += aFields.length;
System.arraycopy(aCtors, 0, objs, offset, aCtors.length);
// Sort the elements to ensure determinism.
Arrays.sort(objs, new AlphabeticAnnotatableEntityComparator());
mObjects = objs;
// Check for "Wrap ALL the things" flag.
for (Annotation annotation : aClass.getDeclaredAnnotations()) {
final String annotationTypeName = annotation.annotationType().getName();
if (annotationTypeName.equals("org.mozilla.gecko.mozglue.generatorannotations.WrapEntireClassForJNI")) {
mIterateEveryEntry = true;
break;
}
}
findNextValue();
}
@ -38,15 +64,14 @@ public class GeneratableEntryPointIterator implements Iterator<MethodWithAnnotat
* one exists. Otherwise cache null, so hasNext returns false.
*/
private void findNextValue() {
while (mMethodIndex < mMethods.length) {
Method candidateMethod = mMethods[mMethodIndex];
mMethodIndex++;
for (Annotation annotation : candidateMethod.getDeclaredAnnotations()) {
// GeneratableAndroidBridgeTarget has a parameter. Use Reflection to obtain it.
while (mElementIndex < mObjects.length) {
Member candidateElement = mObjects[mElementIndex];
mElementIndex++;
for (Annotation annotation : ((AnnotatedElement) candidateElement).getDeclaredAnnotations()) {
// WrappedJNIMethod has parameters. Use Reflection to obtain them.
Class<? extends Annotation> annotationType = annotation.annotationType();
final String annotationTypeName = annotationType.getName();
if (annotationTypeName.equals("org.mozilla.gecko.mozglue.GeneratableAndroidBridgeTarget")) {
if (annotationTypeName.equals("org.mozilla.gecko.mozglue.generatorannotations.WrapElementForJNI")) {
String stubName = null;
boolean isStaticStub = false;
boolean isMultithreadedStub = false;
@ -66,28 +91,38 @@ public class GeneratableEntryPointIterator implements Iterator<MethodWithAnnotat
multithreadedStubMethod.setAccessible(true);
isMultithreadedStub = (Boolean) multithreadedStubMethod.invoke(annotation);
} catch (NoSuchMethodException e) {
System.err.println("Unable to find expected field on GeneratableAndroidBridgeTarget annotation. Did the signature change?");
System.err.println("Unable to find expected field on WrapElementForJNI annotation. Did the signature change?");
e.printStackTrace(System.err);
System.exit(3);
} catch (IllegalAccessException e) {
System.err.println("IllegalAccessException reading fields on GeneratableAndroidBridgeTarget annotation. Seems the semantics of Reflection have changed...");
System.err.println("IllegalAccessException reading fields on WrapElementForJNI annotation. Seems the semantics of Reflection have changed...");
e.printStackTrace(System.err);
System.exit(4);
} catch (InvocationTargetException e) {
System.err.println("InvocationTargetException reading fields on GeneratableAndroidBridgeTarget annotation. This really shouldn't happen.");
System.err.println("InvocationTargetException reading fields on WrapElementForJNI annotation. This really shouldn't happen.");
e.printStackTrace(System.err);
System.exit(5);
}
// If the method name was not explicitly given in the annotation generate one...
if (stubName.isEmpty()) {
String aMethodName = candidateMethod.getName();
String aMethodName = candidateElement.getName();
stubName = aMethodName.substring(0, 1).toUpperCase() + aMethodName.substring(1);
}
mNextReturnValue = new MethodWithAnnotationInfo(candidateMethod, stubName, isStaticStub, isMultithreadedStub);
AnnotationInfo annotationInfo = new AnnotationInfo(stubName, isStaticStub, isMultithreadedStub);
mNextReturnValue = new AnnotatableEntity(candidateElement, annotationInfo);
return;
}
}
// If no annotation found, we might be expected to generate anyway using default arguments,
// thanks to the "Generate everything" annotation.
if (mIterateEveryEntry) {
AnnotationInfo annotationInfo = new AnnotationInfo(candidateElement.getName(), false, false);
mNextReturnValue = new AnnotatableEntity(candidateElement, annotationInfo);
return;
}
}
mNextReturnValue = null;
}
@ -98,14 +133,14 @@ public class GeneratableEntryPointIterator implements Iterator<MethodWithAnnotat
}
@Override
public MethodWithAnnotationInfo next() {
MethodWithAnnotationInfo ret = mNextReturnValue;
public AnnotatableEntity next() {
AnnotatableEntity ret = mNextReturnValue;
findNextValue();
return ret;
}
@Override
public void remove() {
throw new UnsupportedOperationException("Removal of methods from GeneratableEntryPointIterator not supported.");
throw new UnsupportedOperationException("Removal of methods from GeneratableElementIterator not supported.");
}
}

Просмотреть файл

@ -5,6 +5,9 @@
package org.mozilla.gecko.annotationProcessors.utils;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
@ -70,9 +73,23 @@ public class Utils {
sInstanceCallTypes.put("short", "CallShortMethod");
}
private static final HashMap<String, String> sFieldTypes = new HashMap<String, String>();
static {
sFieldTypes.put("int", "Int");
sFieldTypes.put("boolean", "Boolean");
sFieldTypes.put("long", "Long");
sFieldTypes.put("double", "Double");
sFieldTypes.put("float", "Float");
sFieldTypes.put("char", "Char");
sFieldTypes.put("byte", "Byte");
sFieldTypes.put("short", "Short");
}
private static final HashMap<String, String> sFailureReturns = new HashMap<String, String>();
static {
sFailureReturns.put("java.lang.Void", "");
sFailureReturns.put("void", "");
sFailureReturns.put("int", " 0");
sFailureReturns.put("boolean", " false");
@ -87,6 +104,7 @@ public class Utils {
private static final HashMap<String, String> sCanonicalSignatureParts = new HashMap<String, String>();
static {
sCanonicalSignatureParts.put("java/lang/Void", "V");
sCanonicalSignatureParts.put("void", "V");
sCanonicalSignatureParts.put("int", "I");
sCanonicalSignatureParts.put("boolean", "Z");
@ -164,7 +182,9 @@ public class Utils {
* @return A string representation of the C++ return type.
*/
public static String getCReturnType(Class<?> type) {
// Since there's only one thing we want to do differently...
if (type.getCanonicalName().equals("java.lang.Void")) {
return "void";
}
String cParameterType = getCParameterType(type);
if (cParameterType.equals("const nsAString&")) {
return "jstring";
@ -173,6 +193,21 @@ public class Utils {
}
}
/**
* Gets the type-specific part of the JNI function to use to get or set a field of a given type.
*
* @param aFieldType The Java type of the field.
* @return A string representation of the JNI call function substring to use.
*/
public static String getFieldType(Class<?> aFieldType) {
String name = aFieldType.getCanonicalName();
if (sFieldTypes.containsKey(name)) {
return sFieldTypes.get(name);
}
return "Object";
}
/**
* Gets the appropriate JNI call function to use to invoke a Java method with the given return
* type. This, plus a call postfix (Such as "A") forms a complete JNI call function name.
@ -212,29 +247,91 @@ public class Utils {
}
/**
* Get the canonical JNI type signature for a method.
* Helper method to get the type signature for methods, given argument and return type.
* Allows for the near-identical logic needed for constructors and methods to be shared.
* (Alas, constructor does not extend method)
*
* @param aMethod The method to generate a signature for.
* @return The canonical JNI type signature for this method.
* @param arguments Argument types of the underlying method.
* @param returnType Return type of the underlying method.
* @return The canonical Java type string for the method. eg. (IIIIFZ)Lorg/mozilla/gecko/gfx/ViewTransform;
*/
public static String getTypeSignatureString(Method aMethod) {
Class<?>[] arguments = aMethod.getParameterTypes();
Class<?> returnType = aMethod.getReturnType();
private static String getTypeSignatureInternal(Class<?>[] arguments, Class<?> returnType) {
StringBuilder sb = new StringBuilder();
sb.append('(');
// For each argument, write its signature component to the buffer..
for (int i = 0; i < arguments.length; i++) {
writeTypeSignature(sb, arguments[i]);
}
sb.append(')');
// Write the return value's signature..
writeTypeSignature(sb, returnType);
return sb.toString();
}
/**
* Helper method used by getTypeSignatureString to build the signature. Write the subsignature
* Get the canonical JNI type signature for a Field.
*
* @param aField The field to generate a signature for.
* @return The canonical JNI type signature for this method.
*/
protected static String getTypeSignatureStringForField(Field aField) {
StringBuilder sb = new StringBuilder();
writeTypeSignature(sb, aField.getType());
return sb.toString();
}
/**
* Get the canonical JNI type signature for a method.
*
* @param aMethod The method to generate a signature for.
* @return The canonical JNI type signature for this method.
*/
protected static String getTypeSignatureStringForMethod(Method aMethod) {
Class<?>[] arguments = aMethod.getParameterTypes();
Class<?> returnType = aMethod.getReturnType();
return getTypeSignatureInternal(arguments, returnType);
}
/**
* Get the canonical JNI type signature for a Constructor.
*
* @param aConstructor The Constructor to generate a signature for.
* @return The canonical JNI type signature for this method.
*/
protected static String getTypeSignatureStringForConstructor(Constructor aConstructor) {
Class<?>[] arguments = aConstructor.getParameterTypes();
return getTypeSignatureInternal(arguments, Void.class);
}
public static String getTypeSignatureStringForMember(Member aMember) {
if (aMember instanceof Method) {
return getTypeSignatureStringForMethod((Method) aMember);
} else if (aMember instanceof Field) {
return getTypeSignatureStringForField((Field) aMember);
} else {
return getTypeSignatureStringForConstructor((Constructor) aMember);
}
}
public static String getTypeSignatureString(Constructor aConstructor) {
Class<?>[] arguments = aConstructor.getParameterTypes();
StringBuilder sb = new StringBuilder();
sb.append('(');
// For each argument, write its signature component to the buffer..
for (int i = 0; i < arguments.length; i++) {
writeTypeSignature(sb, arguments[i]);
}
// Constructors always return Void.
sb.append(")V");
return sb.toString();
}
/**
* Helper method used by getTypeSignatureStringForMethod to build the signature. Write the subsignature
* of a given type into the buffer.
*
* @param sb The buffer to write into.
@ -242,6 +339,7 @@ public class Utils {
*/
private static void writeTypeSignature(StringBuilder sb, Class<?> c) {
String name = c.getCanonicalName().replaceAll("\\.", "/");
// Determine if this is an array type and, if so, peel away the array operators..
int len = name.length();
while (name.endsWith("[]")) {
@ -250,6 +348,17 @@ public class Utils {
len = len - 2;
}
if (c.isArray()) {
c = c.getComponentType();
}
Class<?> containerClass = c.getDeclaringClass();
if (containerClass != null) {
// Is an inner class. Add the $ symbol.
final int lastSlash = name.lastIndexOf('/');
name = name.substring(0, lastSlash) + '$' + name.substring(lastSlash+1);
}
// Look in the hashmap for the remainder...
if (sCanonicalSignatureParts.containsKey(name)) {
// It was a primitive type, so lookup was a success.
@ -266,38 +375,31 @@ public class Utils {
* Produces a C method signature, sans semicolon, for the given Java Method. Useful for both
* generating header files and method bodies.
*
* @param aMethod The Java method to generate the corresponding wrapper signature for.
* @param aCMethodName The name of the generated method this is to be the signatgure for.
* @return The generated method signature.
* @param aArgumentTypes Argument types of the Java method being wrapped.
* @param aReturnType Return type of the Java method being wrapped.
* @param aCMethodName Name of the method to generate in the C++ class.
* @param aCClassName Name of the C++ class into which the method is declared.
* @return The C++ method implementation signature for the method described.
*/
public static String getCImplementationMethodSignature(Method aMethod, String aCMethodName) {
Class<?>[] argumentTypes = aMethod.getParameterTypes();
Class<?> returnType = aMethod.getReturnType();
public static String getCImplementationMethodSignature(Class<?>[] aArgumentTypes, Class<?> aReturnType, String aCMethodName, String aCClassName) {
StringBuilder retBuffer = new StringBuilder();
// Write return type..
retBuffer.append(getCReturnType(returnType));
retBuffer.append(" AndroidBridge::");
retBuffer.append(getCReturnType(aReturnType));
retBuffer.append(' ');
retBuffer.append(aCClassName);
retBuffer.append("::");
retBuffer.append(aCMethodName);
retBuffer.append('(');
// For an instance method, the first argument is the target object.
if (!isMethodStatic(aMethod)) {
retBuffer.append("jobject aTarget");
if (argumentTypes.length > 0) {
retBuffer.append(", ");
}
}
// Write argument types...
for (int aT = 0; aT < argumentTypes.length; aT++) {
retBuffer.append(getCParameterType(argumentTypes[aT]));
for (int aT = 0; aT < aArgumentTypes.length; aT++) {
retBuffer.append(getCParameterType(aArgumentTypes[aT]));
retBuffer.append(" a");
// We, imaginatively, call our arguments a1, a2, a3...
// The only way to preserve the names from Java would be to parse the
// Java source, which would be computationally hard.
retBuffer.append(aT);
if (aT != argumentTypes.length - 1) {
if (aT != aArgumentTypes.length - 1) {
retBuffer.append(", ");
}
}
@ -309,18 +411,16 @@ public class Utils {
* Produces a C method signature, sans semicolon, for the given Java Method. Useful for both
* generating header files and method bodies.
*
* @param aMethod The Java method to generate the corresponding wrapper signature for.
* @param aCMethodName The name of the generated method this is to be the signatgure for.
* @return The generated method signature.
* @param aArgumentTypes Argument types of the Java method being wrapped.
* @param aArgumentAnnotations The annotations on the Java method arguments. Used to specify
* default values etc.
* @param aReturnType Return type of the Java method being wrapped.
* @param aCMethodName Name of the method to generate in the C++ class.
* @param aCClassName Name of the C++ class into which the method is declared.e
* @param aIsStaticStub true if the generated C++ method should be static, false otherwise.
* @return The generated C++ header method signature for the method described.
*/
public static String getCHeaderMethodSignature(Method aMethod, String aCMethodName, boolean aIsStaticStub) {
Class<?>[] argumentTypes = aMethod.getParameterTypes();
// The annotations on the parameters of this method, in declaration order.
// Importantly - the same order as those in argumentTypes.
Annotation[][] argumentAnnotations = aMethod.getParameterAnnotations();
Class<?> returnType = aMethod.getReturnType();
public static String getCHeaderMethodSignature(Class<?>[] aArgumentTypes, Annotation[][] aArgumentAnnotations, Class<?> aReturnType, String aCMethodName, String aCClassName, boolean aIsStaticStub) {
StringBuilder retBuffer = new StringBuilder();
// Add the static keyword, if applicable.
@ -329,22 +429,14 @@ public class Utils {
}
// Write return type..
retBuffer.append(getCReturnType(returnType));
retBuffer.append(getCReturnType(aReturnType));
retBuffer.append(' ');
retBuffer.append(aCMethodName);
retBuffer.append('(');
// For an instance method, the first argument is the target object.
if (!isMethodStatic(aMethod)) {
retBuffer.append("jobject aTarget");
if (argumentTypes.length > 0) {
retBuffer.append(", ");
}
}
// Write argument types...
for (int aT = 0; aT < argumentTypes.length; aT++) {
retBuffer.append(getCParameterType(argumentTypes[aT]));
for (int aT = 0; aT < aArgumentTypes.length; aT++) {
retBuffer.append(getCParameterType(aArgumentTypes[aT]));
retBuffer.append(" a");
// We, imaginatively, call our arguments a1, a2, a3...
// The only way to preserve the names from Java would be to parse the
@ -352,9 +444,9 @@ public class Utils {
retBuffer.append(aT);
// Append the default value, if there is one..
retBuffer.append(getDefaultValueString(argumentTypes[aT], argumentAnnotations[aT]));
retBuffer.append(getDefaultValueString(aArgumentTypes[aT], aArgumentAnnotations[aT]));
if (aT != argumentTypes.length - 1) {
if (aT != aArgumentTypes.length - 1) {
retBuffer.append(", ");
}
}
@ -376,7 +468,7 @@ public class Utils {
for (int i = 0; i < aArgumentAnnotations.length; i++) {
Class<? extends Annotation> annotationType = aArgumentAnnotations[i].annotationType();
final String annotationTypeName = annotationType.getName();
if (annotationTypeName.equals("org.mozilla.gecko.mozglue.OptionalGeneratedParameter")) {
if (annotationTypeName.equals("org.mozilla.gecko.mozglue.generatorannotations.OptionalGeneratedParameter")) {
return " = " + getDefaultParameterValueForType(aArgumentType);
}
}
@ -406,14 +498,13 @@ public class Utils {
/**
* Helper method that returns the number of reference types in the arguments of m.
*
* @param m The method to consider.
* @param aArgs The method arguments to consider.
* @return How many of the arguments of m are nonprimitive.
*/
public static int enumerateReferenceArguments(Method m) {
public static int enumerateReferenceArguments(Class<?>[] aArgs) {
int ret = 0;
Class<?>[] args = m.getParameterTypes();
for (int i = 0; i < args.length; i++) {
String name = args[i].getCanonicalName();
for (int i = 0; i < aArgs.length; i++) {
String name = aArgs[i].getCanonicalName();
if (!sBasicCTypes.containsKey(name)) {
ret++;
}
@ -453,7 +544,7 @@ public class Utils {
sb.append(" = ").append(argName).append(";\n");
} else {
if (isCharSequence(type)) {
sb.append("l = NewJavaString(env, ").append(argName).append(");\n");
sb.append("l = AndroidBridge::NewJavaString(env, ").append(argName).append(");\n");
} else {
sb.append("l = ").append(argName).append(";\n");
}
@ -463,15 +554,13 @@ public class Utils {
}
/**
* Returns true if the method provided returns an object type. Returns false if it returns a
* primitive type.
* Returns true if the type provided is an object type. Returns false otherwise
*
* @param aMethod The method to consider.
* @return true if the method provided returns an object type, false otherwise.
* @param aType The type to consider.
* @return true if the method provided is an object type, false otherwise.
*/
public static boolean doesReturnObjectType(Method aMethod) {
Class<?> returnType = aMethod.getReturnType();
return !sBasicCTypes.containsKey(returnType.getCanonicalName());
public static boolean isObjectType(Class<?> aType) {
return !sBasicCTypes.containsKey(aType.getCanonicalName());
}
/**
@ -496,7 +585,16 @@ public class Utils {
sb.append(" ");
sb.append(getClassReferenceName(aClass));
sb.append(" = getClassGlobalRef(\"");
sb.append(aClass.getCanonicalName().replaceAll("\\.", "/"));
String name = aClass.getCanonicalName().replaceAll("\\.", "/");
Class<?> containerClass = aClass.getDeclaringClass();
if (containerClass != null) {
// Is an inner class. Add the $ symbol.
final int lastSlash = name.lastIndexOf('/');
name = name.substring(0, lastSlash) + '$' + name.substring(lastSlash+1);
}
sb.append(name);
sb.append("\");\n");
return sb.toString();
}
@ -521,11 +619,21 @@ public class Utils {
/**
* Helper method to read the modifier bits of the given method to determine if it is static.
* @param aMethod The Method to check.
* @param aMember The Member to check.
* @return true of the method is declared static, false otherwise.
*/
public static boolean isMethodStatic(Method aMethod) {
int aMethodModifiers = aMethod.getModifiers();
public static boolean isMemberStatic(Member aMember) {
int aMethodModifiers = aMember.getModifiers();
return Modifier.isStatic(aMethodModifiers);
}
/**
* Helper method to read the modifier bits of the given method to determine if it is static.
* @param aMember The Member to check.
* @return true of the method is declared static, false otherwise.
*/
public static boolean isMemberFinal(Member aMember) {
int aMethodModifiers = aMember.getModifiers();
return Modifier.isFinal(aMethodModifiers);
}
}

Просмотреть файл

@ -368,6 +368,17 @@ if test -n "$GNU_CC" -a -z "$CLANG_CC" ; then
fi
fi
dnl ========================================================
dnl Disable compiling sources in unified mode.
dnl ========================================================
MOZ_ARG_DISABLE_BOOL(unified-compilation,
[ --disable-unified-compilation
Disable unified compilation of some C/C++ sources],
MOZ_DISABLE_UNIFIED_COMPILATION=1,
MOZ_DISABLE_UNIFIED_COMPILATION=)
AC_SUBST(MOZ_DISABLE_UNIFIED_COMPILATION)
dnl ========================================================
dnl Special win32 checks
dnl ========================================================

Просмотреть файл

@ -1792,8 +1792,8 @@ ContentParent::RecvGetShowPasswordSetting(bool* showPassword)
*showPassword = true;
#ifdef MOZ_WIDGET_ANDROID
NS_ASSERTION(AndroidBridge::Bridge() != nullptr, "AndroidBridge is not available");
if (AndroidBridge::Bridge() != nullptr)
*showPassword = AndroidBridge::Bridge()->GetShowPasswordSetting();
*showPassword = GeckoAppShell::GetShowPasswordSetting();
#endif
return true;
}

Просмотреть файл

@ -2262,11 +2262,7 @@ _getvalue(NPP npp, NPNVariable variable, void *result)
}
case kJavaContext_ANPGetValue: {
AndroidBridge *bridge = AndroidBridge::Bridge();
if (!bridge)
return NPERR_GENERIC_ERROR;
jobject ret = bridge->GetContext();
jobject ret = GeckoAppShell::GetContext();
if (!ret)
return NPERR_GENERIC_ERROR;

Просмотреть файл

@ -868,7 +868,7 @@ void nsNPAPIPluginInstance::NotifyFullScreen(bool aFullScreen)
SendLifecycleEvent(this, mFullScreen ? kEnterFullScreen_ANPLifecycleAction : kExitFullScreen_ANPLifecycleAction);
if (mFullScreen && mFullScreenOrientation != dom::eScreenOrientation_None) {
AndroidBridge::Bridge()->LockScreenOrientation(mFullScreenOrientation);
GeckoAppShell::LockScreenOrientation(mFullScreenOrientation);
}
}
@ -925,11 +925,11 @@ void nsNPAPIPluginInstance::SetFullScreenOrientation(uint32_t orientation)
// We're already fullscreen so immediately apply the orientation change
if (mFullScreenOrientation != dom::eScreenOrientation_None) {
AndroidBridge::Bridge()->LockScreenOrientation(mFullScreenOrientation);
GeckoAppShell::LockScreenOrientation(mFullScreenOrientation);
} else if (oldOrientation != dom::eScreenOrientation_None) {
// We applied an orientation when we entered fullscreen, but
// we don't want it anymore
AndroidBridge::Bridge()->UnlockScreenOrientation();
GeckoAppShell::UnlockScreenOrientation();
}
}
}

Просмотреть файл

@ -1672,9 +1672,7 @@ void nsPluginInstanceOwner::RemovePluginView()
if (!mInstance || !mJavaView)
return;
if (AndroidBridge::Bridge())
AndroidBridge::Bridge()->RemovePluginView((jobject)mJavaView, mFullScreen);
GeckoAppShell::RemovePluginView((jobject)mJavaView, mFullScreen);
AndroidBridge::GetJNIEnv()->DeleteGlobalRef((jobject)mJavaView);
mJavaView = nullptr;

Просмотреть файл

@ -26,9 +26,7 @@ AndroidLocationProvider::~AndroidLocationProvider()
NS_IMETHODIMP
AndroidLocationProvider::Startup()
{
if (!AndroidBridge::Bridge())
return NS_ERROR_NOT_IMPLEMENTED;
AndroidBridge::Bridge()->EnableLocation(true);
GeckoAppShell::EnableLocation(true);
return NS_OK;
}
@ -44,17 +42,13 @@ AndroidLocationProvider::Watch(nsIGeolocationUpdate* aCallback)
NS_IMETHODIMP
AndroidLocationProvider::Shutdown()
{
if (!AndroidBridge::Bridge())
return NS_ERROR_NOT_IMPLEMENTED;
AndroidBridge::Bridge()->EnableLocation(false);
GeckoAppShell::EnableLocation(false);
return NS_OK;
}
NS_IMETHODIMP
AndroidLocationProvider::SetHighAccuracy(bool enable)
{
if (!AndroidBridge::Bridge())
return NS_ERROR_NOT_IMPLEMENTED;
AndroidBridge::Bridge()->EnableLocationHighAccuracy(enable);
GeckoAppShell::EnableLocationHighAccuracy(enable);
return NS_OK;
}

Просмотреть файл

@ -14,10 +14,6 @@ NS_IMPL_ISUPPORTS1(nsHapticFeedback, nsIHapticFeedback)
NS_IMETHODIMP
nsHapticFeedback::PerformSimpleAction(int32_t aType)
{
AndroidBridge* bridge = AndroidBridge::Bridge();
if (bridge) {
bridge->PerformHapticFeedback(aType == LongPress);
return NS_OK;
}
return NS_ERROR_FAILURE;
GeckoAppShell::PerformHapticFeedback(aType == LongPress);
return NS_OK;
}

Просмотреть файл

@ -2515,7 +2515,7 @@ public:
#endif
virtual already_AddRefed<TextureImage>
CreateDirectTextureImage(android::GraphicBuffer* aBuffer, GLenum aWrapMode)
CreateDirectTextureImage(::android::GraphicBuffer* aBuffer, GLenum aWrapMode)
{ return nullptr; }
// Before reads from offscreen texture

Просмотреть файл

@ -15,6 +15,7 @@
#include "mozilla/layers/CompositorTypes.h" // for DiagnosticTypes, etc
#include "mozilla/layers/LayersTypes.h" // for LayersBackend
#include "nsTraceRefcnt.h" // for MOZ_COUNT_CTOR, etc
#include "nsRegion.h"
/**
* Different elements of a web pages are rendered into separate "layers" before
@ -291,16 +292,24 @@ public:
/**
* Start a new frame.
*
* aInvalidRect is the invalid region of the screen; it can be ignored for
* compositors where the performance for compositing the entire window is
* sufficient.
*
* aClipRectIn is the clip rect for the window in window space (optional).
* aTransform is the transform from user space to window space.
* aRenderBounds bounding rect for rendering, in user space.
*
* If aClipRectIn is null, this method sets *aClipRectOut to the clip rect
* actually used for rendering (if aClipRectIn is non-null, we will use that
* for the clip rect).
*
* If aRenderBoundsOut is non-null, it will be set to the render bounds
* actually used by the compositor in window space.
*/
virtual void BeginFrame(const gfx::Rect* aClipRectIn,
virtual void BeginFrame(const nsIntRegion& aInvalidRegion,
const gfx::Rect* aClipRectIn,
const gfxMatrix& aTransform,
const gfx::Rect& aRenderBounds,
gfx::Rect* aClipRectOut = nullptr,

Просмотреть файл

@ -110,6 +110,7 @@ struct LayerPropertiesBase : public LayerProperties
: mLayer(aLayer)
, mMaskLayer(nullptr)
, mVisibleRegion(aLayer->GetVisibleRegion())
, mInvalidRegion(aLayer->GetInvalidRegion())
, mTransform(aLayer->GetTransform())
, mOpacity(aLayer->GetOpacity())
, mUseClipRect(!!aLayer->GetClipRect())
@ -201,6 +202,7 @@ struct LayerPropertiesBase : public LayerProperties
nsRefPtr<Layer> mLayer;
nsAutoPtr<LayerPropertiesBase> mMaskLayer;
nsIntRegion mVisibleRegion;
nsIntRegion mInvalidRegion;
gfx3DMatrix mTransform;
float mOpacity;
nsIntRect mClipRect;
@ -320,7 +322,6 @@ struct ImageLayerProperties : public LayerPropertiesBase
{
ImageLayerProperties(ImageLayer* aImage)
: LayerPropertiesBase(aImage)
, mVisibleRegion(aImage->GetVisibleRegion())
, mContainer(aImage->GetContainer())
, mFilter(aImage->GetFilter())
, mScaleToSize(aImage->GetScaleToSize())
@ -348,7 +349,6 @@ struct ImageLayerProperties : public LayerPropertiesBase
return nsIntRect();
}
nsIntRegion mVisibleRegion;
nsRefPtr<ImageContainer> mContainer;
GraphicsFilter mFilter;
gfxIntSize mScaleToSize;

Просмотреть файл

@ -1223,6 +1223,7 @@ public:
* marked as needed to be recomposited.
*/
const nsIntRegion& GetInvalidRegion() { return mInvalidRegion; }
const void SetInvalidRegion(const nsIntRegion& aRect) { mInvalidRegion = aRect; }
/**
* Mark the entirety of the layer's visible region as being invalid.

Просмотреть файл

@ -418,9 +418,7 @@ BasicCompositor::DrawQuad(const gfx::Rect& aRect,
gfx::Float aOpacity,
const gfx::Matrix4x4 &aTransform)
{
RefPtr<DrawTarget> buffer = mRenderTarget
? mRenderTarget->mDrawTarget
: mDrawTarget;
RefPtr<DrawTarget> buffer = mRenderTarget->mDrawTarget;
// For 2D drawing, |dest| and |buffer| are the same surface. For 3D drawing,
// |dest| is a temporary surface.
@ -551,7 +549,8 @@ BasicCompositor::DrawQuad(const gfx::Rect& aRect,
}
void
BasicCompositor::BeginFrame(const gfx::Rect *aClipRectIn,
BasicCompositor::BeginFrame(const nsIntRegion& aInvalidRegion,
const gfx::Rect *aClipRectIn,
const gfxMatrix& aTransform,
const gfx::Rect& aRenderBounds,
gfx::Rect *aClipRectOut /* = nullptr */,
@ -562,6 +561,18 @@ BasicCompositor::BeginFrame(const gfx::Rect *aClipRectIn,
Rect rect = Rect(0, 0, intRect.width, intRect.height);
mWidgetSize = intRect.Size();
nsIntRect invalidRect = aInvalidRegion.GetBounds();
mInvalidRect = IntRect(invalidRect.x, invalidRect.y, invalidRect.width, invalidRect.height);
mInvalidRegion = aInvalidRegion;
if (aRenderBoundsOut) {
*aRenderBoundsOut = Rect();
}
if (mInvalidRect.width <= 0 || mInvalidRect.height <= 0) {
return;
}
if (mCopyTarget) {
// If we have a copy target, then we don't have a widget-provided mDrawTarget (currently). Create a dummy
// placeholder so that CreateRenderTarget() works.
@ -570,17 +581,22 @@ BasicCompositor::BeginFrame(const gfx::Rect *aClipRectIn,
mDrawTarget = mWidget->StartRemoteDrawing();
}
if (!mDrawTarget) {
if (aRenderBoundsOut) {
*aRenderBoundsOut = Rect();
}
return;
}
// Setup an intermediate render target to buffer all compositing. We will
// copy this into mDrawTarget (the widget), and/or mCopyTarget in EndFrame()
RefPtr<CompositingRenderTarget> target = CreateRenderTarget(IntRect(0, 0, intRect.width, intRect.height), INIT_MODE_CLEAR);
RefPtr<CompositingRenderTarget> target = CreateRenderTarget(mInvalidRect, INIT_MODE_CLEAR);
SetRenderTarget(target);
// We only allocate a surface sized to the invalidated region, so we need to
// translate future coordinates.
Matrix transform;
transform.Translate(-invalidRect.x, -invalidRect.y);
mRenderTarget->mDrawTarget->SetTransform(transform);
gfxUtils::ClipToRegion(mRenderTarget->mDrawTarget, aInvalidRegion);
if (aRenderBoundsOut) {
*aRenderBoundsOut = rect;
}
@ -599,20 +615,26 @@ void
BasicCompositor::EndFrame()
{
mRenderTarget->mDrawTarget->PopClip();
mRenderTarget->mDrawTarget->PopClip();
// Note: Most platforms require us to buffer drawing to the widget surface.
// That's why we don't draw to mDrawTarget directly.
RefPtr<SourceSurface> source = mRenderTarget->mDrawTarget->Snapshot();
if (mCopyTarget) {
mCopyTarget->CopySurface(source,
IntRect(0, 0, mWidgetSize.width, mWidgetSize.height),
IntPoint(0, 0));
} else {
// Most platforms require us to buffer drawing to the widget surface.
// That's why we don't draw to mDrawTarget directly.
mDrawTarget->CopySurface(source,
IntRect(0, 0, mWidgetSize.width, mWidgetSize.height),
IntPoint(0, 0));
RefPtr<DrawTarget> dest(mCopyTarget ? mCopyTarget : mDrawTarget);
// The source DrawTarget is clipped to the invalidation region, so we have
// to copy the individual rectangles in the region or else we'll draw blank
// pixels.
nsIntRegionRectIterator iter(mInvalidRegion);
for (const nsIntRect *r = iter.Next(); r; r = iter.Next()) {
dest->CopySurface(source,
IntRect(r->x - mInvalidRect.x, r->y - mInvalidRect.y, r->width, r->height),
IntPoint(r->x, r->y));
}
if (!mCopyTarget) {
mWidget->EndRemoteDrawing();
}
mDrawTarget = nullptr;
mRenderTarget = nullptr;
}
@ -620,6 +642,7 @@ BasicCompositor::EndFrame()
void
BasicCompositor::AbortFrame()
{
mRenderTarget->mDrawTarget->PopClip();
mRenderTarget->mDrawTarget->PopClip();
mDrawTarget = nullptr;
mRenderTarget = nullptr;

Просмотреть файл

@ -84,7 +84,8 @@ public:
gfx::Float aOpacity,
const gfx::Matrix4x4 &aTransform) MOZ_OVERRIDE;
virtual void BeginFrame(const gfx::Rect *aClipRectIn,
virtual void BeginFrame(const nsIntRegion& aInvalidRegion,
const gfx::Rect *aClipRectIn,
const gfxMatrix& aTransform,
const gfx::Rect& aRenderBounds,
gfx::Rect *aClipRectOut = nullptr,
@ -137,6 +138,9 @@ private:
// An optional destination target to copy the results
// to after drawing is completed.
RefPtr<gfx::DrawTarget> mCopyTarget;
gfx::IntRect mInvalidRect;
nsIntRegion mInvalidRegion;
};
} // namespace layers

Просмотреть файл

@ -294,6 +294,16 @@ ClientLayerManager::FlushRendering()
}
}
void
ClientLayerManager::SendInvalidRegion(const nsIntRegion& aRegion)
{
if (mWidget) {
if (CompositorChild* remoteRenderer = mWidget->GetRemoteRenderer()) {
remoteRenderer->SendNotifyRegionInvalidated(aRegion);
}
}
}
void
ClientLayerManager::ForwardTransaction()
{

Просмотреть файл

@ -79,6 +79,7 @@ public:
}
virtual void FlushRendering() MOZ_OVERRIDE;
void SendInvalidRegion(const nsIntRegion& aRegion);
virtual bool NeedsWidgetInvalidation() MOZ_OVERRIDE { return false; }

Просмотреть файл

@ -145,6 +145,9 @@ void
LayerManagerComposite::BeginTransaction()
{
mInTransaction = true;
if (Compositor::GetBackend() == LAYERS_BASIC) {
mClonedLayerTreeProperties = LayerProperties::CloneFrom(GetRoot());
}
}
void
@ -196,6 +199,15 @@ LayerManagerComposite::EndTransaction(DrawThebesLayerCallback aCallback,
return;
}
if (mRoot && mClonedLayerTreeProperties) {
nsIntRegion invalid = mClonedLayerTreeProperties->ComputeDifferences(mRoot, nullptr);
mClonedLayerTreeProperties = nullptr;
mInvalidRegion.Or(mInvalidRegion, invalid);
} else {
mInvalidRegion.Or(mInvalidRegion, mRenderBounds);
}
if (mRoot && !(aFlags & END_NO_IMMEDIATE_REDRAW)) {
if (aFlags & END_NO_COMPOSITE) {
// Apply pending tree updates before recomputing effective
@ -343,13 +355,16 @@ LayerManagerComposite::Render()
clipRect = *mRoot->GetClipRect();
WorldTransformRect(clipRect);
Rect rect(clipRect.x, clipRect.y, clipRect.width, clipRect.height);
mCompositor->BeginFrame(&rect, mWorldMatrix, bounds, nullptr, &actualBounds);
mCompositor->BeginFrame(mInvalidRegion, &rect, mWorldMatrix, bounds, nullptr, &actualBounds);
} else {
gfx::Rect rect;
mCompositor->BeginFrame(nullptr, mWorldMatrix, bounds, &rect, &actualBounds);
mCompositor->BeginFrame(mInvalidRegion, nullptr, mWorldMatrix, bounds, &rect, &actualBounds);
clipRect = nsIntRect(rect.x, rect.y, rect.width, rect.height);
}
// Reset the invalid region now that we've begun compositing.
mInvalidRegion.SetEmpty();
if (actualBounds.IsEmpty()) {
mCompositor->GetWidget()->PostRender(this);
return;

Просмотреть файл

@ -28,6 +28,7 @@
#include "nsRect.h" // for nsIntRect
#include "nsRegion.h" // for nsIntRegion
#include "nscore.h" // for nsAString, etc
#include "LayerTreeInvalidation.h"
class gfxASurface;
class gfxContext;
@ -228,6 +229,11 @@ public:
void SetCompositorID(uint32_t aID);
void AddInvalidRegion(const nsIntRegion& aRegion)
{
mInvalidRegion.Or(mInvalidRegion, aRegion);
}
Compositor* GetCompositor() const
{
return mCompositor;
@ -275,7 +281,10 @@ private:
DrawThebesLayerCallback mThebesLayerCallback;
void *mThebesLayerCallbackData;
gfxMatrix mWorldMatrix;
bool mInTransaction;
nsIntRegion mInvalidRegion;
nsAutoPtr<LayerProperties> mClonedLayerTreeProperties;
};
/**

Просмотреть файл

@ -623,7 +623,8 @@ CompositorD3D11::DrawQuad(const gfx::Rect& aRect,
}
void
CompositorD3D11::BeginFrame(const Rect* aClipRectIn,
CompositorD3D11::BeginFrame(const nsIntRegion& aInvalidRegion,
const Rect* aClipRectIn,
const gfxMatrix& aTransform,
const Rect& aRenderBounds,
Rect* aClipRectOut,

Просмотреть файл

@ -100,7 +100,8 @@ public:
* Start a new frame. If aClipRectIn is null, sets *aClipRectOut to the
* screen dimensions.
*/
virtual void BeginFrame(const gfx::Rect *aClipRectIn,
virtual void BeginFrame(const nsIntRegion& aInvalidRegion,
const gfx::Rect *aClipRectIn,
const gfxMatrix& aTransform,
const gfx::Rect& aRenderBounds,
gfx::Rect *aClipRectOut = nullptr,

Просмотреть файл

@ -439,7 +439,8 @@ CompositorD3D9::SetMask(const EffectChain &aEffectChain, uint32_t aMaskTexture)
}
void
CompositorD3D9::BeginFrame(const Rect *aClipRectIn,
CompositorD3D9::BeginFrame(const nsIntRegion& aInvalidRegion,
const Rect *aClipRectIn,
const gfxMatrix& aTransform,
const Rect& aRenderBounds,
Rect *aClipRectOut,

Просмотреть файл

@ -61,7 +61,8 @@ public:
gfx::Float aOpacity,
const gfx::Matrix4x4 &aTransform) MOZ_OVERRIDE;
virtual void BeginFrame(const gfx::Rect *aClipRectIn,
virtual void BeginFrame(const nsIntRegion& aInvalidRegion,
const gfx::Rect *aClipRectIn,
const gfxMatrix& aTransform,
const gfx::Rect& aRenderBounds,
gfx::Rect *aClipRectOut = nullptr,

Просмотреть файл

@ -322,6 +322,15 @@ CompositorParent::RecvFlushRendering()
return true;
}
bool
CompositorParent::RecvNotifyRegionInvalidated(const nsIntRegion& aRegion)
{
if (mLayerManager) {
mLayerManager->AddInvalidRegion(aRegion);
}
return true;
}
void
CompositorParent::ActorDestroy(ActorDestroyReason why)
{
@ -896,6 +905,7 @@ public:
SurfaceDescriptor* aOutSnapshot)
{ return true; }
virtual bool RecvFlushRendering() MOZ_OVERRIDE { return true; }
virtual bool RecvNotifyRegionInvalidated(const nsIntRegion& aRegion) { return true; }
virtual PLayerTransactionParent*
AllocPLayerTransactionParent(const nsTArray<LayersBackend>& aBackendHints,

Просмотреть файл

@ -88,6 +88,8 @@ public:
SurfaceDescriptor* aOutSnapshot);
virtual bool RecvFlushRendering() MOZ_OVERRIDE;
virtual bool RecvNotifyRegionInvalidated(const nsIntRegion& aRegion) MOZ_OVERRIDE;
virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE;
virtual void ShadowLayersUpdated(LayerTransactionParent* aLayerTree,

Просмотреть файл

@ -284,6 +284,7 @@ LayerTransactionParent::RecvUpdate(const InfallibleTArray<Edit>& cset,
layer->SetMaskLayer(nullptr);
}
layer->SetAnimations(common.animations());
layer->SetInvalidRegion(common.invalidRegion());
typedef SpecificLayerAttributes Specific;
const SpecificLayerAttributes& specific = attrs.specific();

Просмотреть файл

@ -200,7 +200,8 @@ struct CommonLayerAttributes {
nullable PLayer maskLayer;
// Animated colors will only honored for ColorLayers.
Animation[] animations;
};
nsIntRegion invalidRegion;
};
struct ThebesLayerAttributes {
nsIntRegion validRegion;

Просмотреть файл

@ -9,6 +9,7 @@ include LayersSurfaces;
include protocol PGrallocBuffer;
include protocol PLayerTransaction;
include "mozilla/GfxMessageUtils.h";
include "nsRegion.h";
using struct mozilla::null_t from "ipc/IPCMessageUtils.h";
using struct mozilla::layers::TextureFactoryIdentifier from "mozilla/layers/CompositorTypes.h";
@ -64,6 +65,9 @@ parent:
// that hint is ignored.
sync PLayerTransaction(LayersBackend[] layersBackendHints, uint64_t id)
returns (TextureFactoryIdentifier textureFactoryIdentifier, bool success);
// Notify the compositor that a region of the screen has been invalidated.
async NotifyRegionInvalidated(nsIntRegion region);
};
} // layers

Просмотреть файл

@ -536,6 +536,7 @@ ShadowLayerForwarder::EndTransaction(InfallibleTArray<EditReply>* aReplies, bool
}
common.maskLayerParent() = nullptr;
common.animations() = mutant->GetAnimations();
common.invalidRegion() = mutant->GetInvalidRegion();
attrs.specific() = null_t();
mutant->FillSpecificAttributes(attrs.specific());

Просмотреть файл

@ -755,8 +755,11 @@ CalculatePOTSize(const IntSize& aSize, GLContext* gl)
}
void
CompositorOGL::BeginFrame(const Rect *aClipRectIn, const gfxMatrix& aTransform,
const Rect& aRenderBounds, Rect *aClipRectOut,
CompositorOGL::BeginFrame(const nsIntRegion& aInvalidRegion,
const Rect *aClipRectIn,
const gfxMatrix& aTransform,
const Rect& aRenderBounds,
Rect *aClipRectOut,
Rect *aRenderBoundsOut)
{
PROFILER_LABEL("CompositorOGL", "BeginFrame");

Просмотреть файл

@ -243,7 +243,8 @@ private:
/* Start a new frame. If aClipRectIn is null and aClipRectOut is non-null,
* sets *aClipRectOut to the screen dimensions.
*/
virtual void BeginFrame(const gfx::Rect *aClipRectIn,
virtual void BeginFrame(const nsIntRegion& aInvalidRegion,
const gfx::Rect *aClipRectIn,
const gfxMatrix& aTransform,
const gfx::Rect& aRenderBounds,
gfx::Rect *aClipRectOut = nullptr,

Просмотреть файл

@ -210,7 +210,7 @@ nsSurfaceTexture::~nsSurfaceTexture()
return;
if (mSurfaceTexture && env) {
AndroidBridge::Bridge()->UnregisterSurfaceTextureFrameListener(mSurfaceTexture);
GeckoAppShell::UnregisterSurfaceTextureFrameListener(mSurfaceTexture);
env->DeleteGlobalRef(mSurfaceTexture);
mSurfaceTexture = nullptr;
@ -239,9 +239,9 @@ void
nsSurfaceTexture::SetFrameAvailableCallback(nsIRunnable* aRunnable)
{
if (aRunnable)
AndroidBridge::Bridge()->RegisterSurfaceTextureFrameListener(mSurfaceTexture, mID);
GeckoAppShell::RegisterSurfaceTextureFrameListener(mSurfaceTexture, mID);
else
AndroidBridge::Bridge()->UnregisterSurfaceTextureFrameListener(mSurfaceTexture);
GeckoAppShell::UnregisterSurfaceTextureFrameListener(mSurfaceTexture);
mFrameAvailableCallback = aRunnable;
}

Просмотреть файл

@ -14,6 +14,7 @@
using namespace mozilla::dom;
using namespace mozilla::hal;
using namespace mozilla::widget::android;
namespace mozilla {
namespace hal_impl {
@ -54,97 +55,55 @@ CancelVibrate(const WindowIdentifier &)
{
// Ignore WindowIdentifier parameter.
AndroidBridge* b = AndroidBridge::Bridge();
if (b)
b->CancelVibrate();
GeckoAppShell::CancelVibrate();
}
void
EnableBatteryNotifications()
{
AndroidBridge* bridge = AndroidBridge::Bridge();
if (!bridge) {
return;
}
bridge->EnableBatteryNotifications();
GeckoAppShell::EnableBatteryNotifications();
}
void
DisableBatteryNotifications()
{
AndroidBridge* bridge = AndroidBridge::Bridge();
if (!bridge) {
return;
}
bridge->DisableBatteryNotifications();
GeckoAppShell::DisableBatteryNotifications();
}
void
GetCurrentBatteryInformation(hal::BatteryInformation* aBatteryInfo)
{
AndroidBridge* bridge = AndroidBridge::Bridge();
if (!bridge) {
return;
}
bridge->GetCurrentBatteryInformation(aBatteryInfo);
AndroidBridge::Bridge()->GetCurrentBatteryInformation(aBatteryInfo);
}
void
EnableNetworkNotifications()
{
AndroidBridge* bridge = AndroidBridge::Bridge();
if (!bridge) {
return;
}
bridge->EnableNetworkNotifications();
GeckoAppShell::EnableNetworkNotifications();
}
void
DisableNetworkNotifications()
{
AndroidBridge* bridge = AndroidBridge::Bridge();
if (!bridge) {
return;
}
bridge->DisableNetworkNotifications();
GeckoAppShell::DisableNetworkNotifications();
}
void
GetCurrentNetworkInformation(hal::NetworkInformation* aNetworkInfo)
{
AndroidBridge* bridge = AndroidBridge::Bridge();
if (!bridge) {
return;
}
bridge->GetCurrentNetworkInformation(aNetworkInfo);
AndroidBridge::Bridge()->GetCurrentNetworkInformation(aNetworkInfo);
}
void
EnableScreenConfigurationNotifications()
{
AndroidBridge* bridge = AndroidBridge::Bridge();
if (!bridge) {
return;
}
bridge->EnableScreenOrientationNotifications();
GeckoAppShell::EnableScreenOrientationNotifications();
}
void
DisableScreenConfigurationNotifications()
{
AndroidBridge* bridge = AndroidBridge::Bridge();
if (!bridge) {
return;
}
bridge->DisableScreenOrientationNotifications();
GeckoAppShell::DisableScreenOrientationNotifications();
}
void
@ -181,11 +140,6 @@ GetCurrentScreenConfiguration(ScreenConfiguration* aScreenConfiguration)
bool
LockScreenOrientation(const ScreenOrientation& aOrientation)
{
AndroidBridge* bridge = AndroidBridge::Bridge();
if (!bridge) {
return false;
}
switch (aOrientation) {
// The Android backend only supports these orientations.
case eScreenOrientation_PortraitPrimary:
@ -195,7 +149,7 @@ LockScreenOrientation(const ScreenOrientation& aOrientation)
case eScreenOrientation_LandscapeSecondary:
case eScreenOrientation_LandscapePrimary | eScreenOrientation_LandscapeSecondary:
case eScreenOrientation_Default:
bridge->LockScreenOrientation(aOrientation);
GeckoAppShell::LockScreenOrientation(aOrientation);
return true;
default:
return false;
@ -205,12 +159,7 @@ LockScreenOrientation(const ScreenOrientation& aOrientation)
void
UnlockScreenOrientation()
{
AndroidBridge* bridge = AndroidBridge::Bridge();
if (!bridge) {
return;
}
bridge->UnlockScreenOrientation();
GeckoAppShell::UnlockScreenOrientation();
}
} // hal_impl

Просмотреть файл

@ -13,12 +13,12 @@ namespace hal_impl {
void
EnableSensorNotifications(SensorType aSensor) {
AndroidBridge::Bridge()->EnableSensor(aSensor);
GeckoAppShell::EnableSensor(aSensor);
}
void
DisableSensorNotifications(SensorType aSensor) {
AndroidBridge::Bridge()->DisableSensor(aSensor);
GeckoAppShell::DisableSensor(aSensor);
}
} // hal_impl

Просмотреть файл

@ -95,7 +95,7 @@ MessagePump::Run(MessagePump::Delegate* aDelegate)
// This processes messages in the Android Looper. Note that we only
// get here if the normal Gecko event loop has been awoken above.
// Bug 750713
did_work |= AndroidBridge::Bridge()->PumpMessageLoop();
did_work |= GeckoAppShell::PumpMessageLoop();
#endif
did_work |= aDelegate->DoDelayedWork(&delayed_work_time_);

Просмотреть файл

@ -162,6 +162,7 @@ var ignoreFunctions = {
// Bug 940765 - fetching preferences should not GC
"PrefHashEntry* pref_HashTableLookup(void*)": true,
"uint8 mozilla::Preferences::InitStaticMembers()": true, // Temporary, see bug 940765
// These are a little overzealous -- these destructors *can* GC if they end
// up wrapping a pending exception. See bug 898815 for the heavyweight fix.

Просмотреть файл

@ -355,9 +355,7 @@ frontend::CompileScript(ExclusiveContext *cx, LifoAlloc *alloc, HandleObject sco
if (!FoldConstants(cx, &pn, &parser))
return nullptr;
// Inferring names for functions in compiled scripts is currently only
// supported while on the main thread. See bug 895395.
if (cx->isJSContext() && !NameFunctions(cx->asJSContext(), pn))
if (!NameFunctions(cx, pn))
return nullptr;
if (!EmitTree(cx, &bce, pn))

Просмотреть файл

@ -23,7 +23,7 @@ class NameResolver
{
static const size_t MaxParents = 100;
JSContext *cx;
ExclusiveContext *cx;
size_t nparents; /* number of parents in the parents array */
ParseNode *parents[MaxParents]; /* history of ParseNodes we've been looking at */
StringBuffer *buf; /* when resolving, buffer to append to */
@ -262,7 +262,7 @@ class NameResolver
}
public:
explicit NameResolver(JSContext *cx) : cx(cx), nparents(0), buf(nullptr) {}
explicit NameResolver(ExclusiveContext *cx) : cx(cx), nparents(0), buf(nullptr) {}
/*
* Resolve all names for anonymous functions recursively within the
@ -331,7 +331,7 @@ class NameResolver
} /* anonymous namespace */
bool
frontend::NameFunctions(JSContext *cx, ParseNode *pn)
frontend::NameFunctions(ExclusiveContext *cx, ParseNode *pn)
{
NameResolver nr(cx);
nr.resolve(pn);

Просмотреть файл

@ -10,12 +10,15 @@
#include "js/TypeDecls.h"
namespace js {
class ExclusiveContext;
namespace frontend {
class ParseNode;
bool
NameFunctions(JSContext *cx, ParseNode *pn);
NameFunctions(ExclusiveContext *cx, ParseNode *pn);
} /* namespace frontend */
} /* namespace js */

Просмотреть файл

@ -0,0 +1,5 @@
setJitCompilerOption("baseline.usecount.trigger", 0);
var arr = new Uint8ClampedArray(1);
for (var i = 0; i < 2; ++i)
arr[0] = 4294967296;
assertEq(arr[0], 255);

Просмотреть файл

@ -346,7 +346,7 @@ class AsmJSModule
JS_ASSERT(name->isTenured());
}
ProfiledBlocksFunction(const ProfiledBlocksFunction &copy)
ProfiledBlocksFunction(ProfiledBlocksFunction &&copy)
: ProfiledFunction(copy.name, copy.startCodeOffset, copy.endCodeOffset),
endInlineCodeOffset(copy.endInlineCodeOffset), blocks(mozilla::Move(copy.blocks))
{ }
@ -566,7 +566,7 @@ class AsmJSModule
bool trackPerfProfiledBlocks(JSAtom *name, unsigned startCodeOffset, unsigned endInlineCodeOffset,
unsigned endCodeOffset, jit::BasicBlocksVector &basicBlocks) {
ProfiledBlocksFunction func(name, startCodeOffset, endInlineCodeOffset, endCodeOffset, basicBlocks);
return perfProfiledBlocksFunctions_.append(func);
return perfProfiledBlocksFunctions_.append(mozilla::Move(func));
}
unsigned numPerfBlocksFunctions() const {
return perfProfiledBlocksFunctions_.length();

Просмотреть файл

@ -1637,6 +1637,13 @@ IonCompile(JSContext *cx, JSScript *script,
BaselineInspector inspector(script);
BaselineFrameInspector *baselineFrameInspector = nullptr;
if (baselineFrame) {
baselineFrameInspector = NewBaselineFrameInspector(temp, baselineFrame);
if (!baselineFrameInspector)
return AbortReason_Alloc;
}
AutoFlushCache afc("IonCompile", cx->runtime()->jitRuntime());
AutoTempAllocatorRooter root(cx, temp);
@ -1647,7 +1654,7 @@ IonCompile(JSContext *cx, JSScript *script,
IonBuilder *builder = alloc->new_<IonBuilder>((JSContext *) nullptr,
CompileCompartment::get(cx->compartment()),
temp, graph, constraints,
&inspector, info, baselineFrame);
&inspector, info, baselineFrameInspector);
if (!builder)
return AbortReason_Alloc;

Просмотреть файл

@ -37,9 +37,73 @@ using namespace js::jit;
using mozilla::DebugOnly;
using mozilla::Maybe;
class jit::BaselineFrameInspector
{
public:
types::Type thisType;
JSObject *singletonScopeChain;
Vector<types::Type, 4, IonAllocPolicy> argTypes;
Vector<types::Type, 4, IonAllocPolicy> varTypes;
BaselineFrameInspector(TempAllocator *temp)
: thisType(types::Type::UndefinedType()),
singletonScopeChain(nullptr),
argTypes(*temp),
varTypes(*temp)
{}
};
BaselineFrameInspector *
jit::NewBaselineFrameInspector(TempAllocator *temp, BaselineFrame *frame)
{
JS_ASSERT(frame);
BaselineFrameInspector *inspector = temp->lifoAlloc()->new_<BaselineFrameInspector>(temp);
if (!inspector)
return nullptr;
// Note: copying the actual values into a temporary structure for use
// during compilation could capture nursery pointers, so the values' types
// are recorded instead.
inspector->thisType = types::GetValueType(frame->thisValue());
if (frame->scopeChain()->hasSingletonType())
inspector->singletonScopeChain = frame->scopeChain();
JSScript *script = frame->script();
if (script->function()) {
if (!inspector->argTypes.reserve(frame->numFormalArgs()))
return nullptr;
for (size_t i = 0; i < frame->numFormalArgs(); i++) {
if (script->formalIsAliased(i))
inspector->argTypes.infallibleAppend(types::Type::UndefinedType());
else if (!script->argsObjAliasesFormals())
inspector->argTypes.infallibleAppend(types::GetValueType(frame->unaliasedFormal(i)));
else if (frame->hasArgsObj())
inspector->argTypes.infallibleAppend(types::GetValueType(frame->argsObj().arg(i)));
else
inspector->argTypes.infallibleAppend(types::Type::UndefinedType());
}
}
if (!inspector->varTypes.reserve(frame->script()->nfixed))
return nullptr;
for (size_t i = 0; i < frame->script()->nfixed; i++) {
if (script->varIsAliased(i))
inspector->varTypes.infallibleAppend(types::Type::UndefinedType());
else
inspector->varTypes.infallibleAppend(types::GetValueType(frame->unaliasedVar(i)));
}
return inspector;
}
IonBuilder::IonBuilder(JSContext *analysisContext, CompileCompartment *comp, TempAllocator *temp, MIRGraph *graph,
types::CompilerConstraintList *constraints,
BaselineInspector *inspector, CompileInfo *info, BaselineFrame *baselineFrame,
BaselineInspector *inspector, CompileInfo *info, BaselineFrameInspector *baselineFrame,
size_t inliningDepth, uint32_t loopDepth)
: MIRGenerator(comp, temp, graph, info),
backgroundCodegen_(nullptr),
@ -859,7 +923,7 @@ IonBuilder::initParameters()
// frame to determine possible initial types for 'this' and parameters.
if (thisTypes->empty() && baselineFrame_) {
if (!thisTypes->addType(types::GetValueType(baselineFrame_->thisValue()), alloc_->lifoAlloc()))
if (!thisTypes->addType(baselineFrame_->thisType, alloc_->lifoAlloc()))
return false;
}
@ -872,7 +936,7 @@ IonBuilder::initParameters()
if (types->empty() && baselineFrame_ &&
!script_->baselineScript()->modifiesArguments())
{
if (!types->addType(types::GetValueType(baselineFrame_->argv()[i]), alloc_->lifoAlloc()))
if (!types->addType(baselineFrame_->argTypes[i], alloc_->lifoAlloc()))
return false;
}
@ -5814,30 +5878,23 @@ IonBuilder::newPendingLoopHeader(MBasicBlock *predecessor, jsbytecode *pc, bool
MPhi *phi = block->getSlot(i)->toPhi();
// Get the value from the baseline frame.
Value existingValue;
// Get the type from the baseline frame.
types::Type existingType = types::Type::UndefinedType();
uint32_t arg = i - info().firstArgSlot();
uint32_t var = i - info().firstLocalSlot();
if (info().fun() && i == info().thisSlot()) {
existingValue = baselineFrame_->thisValue();
} else if (arg < info().nargs()) {
if (info().needsArgsObj())
existingValue = baselineFrame_->argsObj().arg(arg);
else
existingValue = baselineFrame_->unaliasedFormal(arg);
} else {
existingValue = baselineFrame_->unaliasedVar(var);
}
if (info().fun() && i == info().thisSlot())
existingType = baselineFrame_->thisType;
else if (arg < info().nargs())
existingType = baselineFrame_->argTypes[arg];
else
existingType = baselineFrame_->varTypes[var];
// Extract typeset from value.
MIRType type = existingValue.isDouble()
? MIRType_Double
: MIRTypeFromValueType(existingValue.extractNonDoubleType());
types::Type ntype = types::GetValueType(existingValue);
types::TemporaryTypeSet *typeSet =
alloc_->lifoAlloc()->new_<types::TemporaryTypeSet>(ntype);
alloc_->lifoAlloc()->new_<types::TemporaryTypeSet>(existingType);
if (!typeSet)
return nullptr;
MIRType type = MIRTypeFromValueType(typeSet->getKnownTypeTag());
phi->addBackedgeType(type, typeSet);
}
}
@ -9110,7 +9167,7 @@ IonBuilder::jsop_this()
}
if (thisTypes->getKnownTypeTag() == JSVAL_TYPE_OBJECT ||
(thisTypes->empty() && baselineFrame_ && baselineFrame_->thisValue().isObject()))
(thisTypes->empty() && baselineFrame_ && baselineFrame_->thisType.isSomeObject()))
{
// This is safe, because if the entry type of |this| is an object, it
// will necessarily be an object throughout the entire function. OSR
@ -9294,12 +9351,13 @@ IonBuilder::hasStaticScopeObject(ScopeCoordinate sc, JSObject **pcall)
// entering the Ion code a different call object will be created.
if (script() == outerScript && baselineFrame_ && info().osrPc()) {
JSObject *scope = baselineFrame_->scopeChain();
if (scope->is<CallObject>() &&
scope->as<CallObject>().callee().nonLazyScript() == outerScript)
JSObject *singletonScope = baselineFrame_->singletonScopeChain;
if (singletonScope &&
singletonScope->is<CallObject>() &&
singletonScope->as<CallObject>().callee().nonLazyScript() == outerScript)
{
JS_ASSERT(scope->hasSingletonType());
*pcall = scope;
JS_ASSERT(singletonScope->hasSingletonType());
*pcall = singletonScope;
return true;
}
}

Просмотреть файл

@ -24,6 +24,12 @@ namespace jit {
class CodeGenerator;
class CallInfo;
class BaselineInspector;
class BaselineFrameInspector;
// Records information about a baseline frame for compilation that is stable
// when later used off thread.
BaselineFrameInspector *
NewBaselineFrameInspector(TempAllocator *temp, BaselineFrame *frame);
class IonBuilder : public MIRGenerator
{
@ -207,7 +213,7 @@ class IonBuilder : public MIRGenerator
public:
IonBuilder(JSContext *analysisContext, CompileCompartment *comp, TempAllocator *temp, MIRGraph *graph,
types::CompilerConstraintList *constraints,
BaselineInspector *inspector, CompileInfo *info, BaselineFrame *baselineFrame,
BaselineInspector *inspector, CompileInfo *info, BaselineFrameInspector *baselineFrame,
size_t inliningDepth = 0, uint32_t loopDepth = 0);
bool build();
@ -745,7 +751,7 @@ class IonBuilder : public MIRGenerator
bool init();
JSContext *analysisContext;
BaselineFrame *baselineFrame_;
BaselineFrameInspector *baselineFrame_;
AbortReason abortReason_;
TypeRepresentationSetHash *reprSetHash_;

Просмотреть файл

@ -605,7 +605,11 @@ MacroAssembler::clampDoubleToUint8(FloatRegister input, Register output)
addDouble(ScratchFloatReg, input);
Label outOfRange;
branchTruncateDouble(input, output, &outOfRange);
// Truncate to int32 and ensure the result <= 255. This relies on the
// processor setting output to a value > 255 for doubles outside the int32
// range (for instance 0x80000000).
cvttsd2si(input, output);
branch32(Assembler::Above, output, Imm32(255), &outOfRange);
{
// Check if we had a tie.

Просмотреть файл

@ -5364,9 +5364,13 @@ JS::GetGCNumber()
}
JS::AutoAssertNoGC::AutoAssertNoGC()
: runtime(js::TlsPerThreadData.get()->runtimeFromMainThread())
: runtime(nullptr)
{
gcNumber = runtime->gcNumber;
js::PerThreadData *data = js::TlsPerThreadData.get();
if (data) {
runtime = data->runtimeFromMainThread();
gcNumber = runtime->gcNumber;
}
}
JS::AutoAssertNoGC::AutoAssertNoGC(JSRuntime *rt)
@ -5376,6 +5380,9 @@ JS::AutoAssertNoGC::AutoAssertNoGC(JSRuntime *rt)
JS::AutoAssertNoGC::~AutoAssertNoGC()
{
MOZ_ASSERT(gcNumber == runtime->gcNumber, "GC ran inside an AutoAssertNoGC scope.");
if (runtime)
MOZ_ASSERT(gcNumber == runtime->gcNumber, "GC ran inside an AutoAssertNoGC scope.");
else
MOZ_ASSERT(!js::TlsPerThreadData.get(), "Runtime created within AutoAssertNoGC scope?");
}
#endif

Просмотреть файл

@ -209,6 +209,10 @@ class Type
return (JSValueType) data;
}
bool isSomeObject() const {
return data == JSVAL_TYPE_OBJECT || data > JSVAL_TYPE_UNKNOWN;
}
bool isAnyObject() const {
return data == JSVAL_TYPE_OBJECT;
}

Просмотреть файл

@ -346,7 +346,7 @@ js::ObjectImpl::numFixedSlotsForCompilation() const
#ifdef JSGC_GENERATIONAL
// The compiler does not have access to nursery things, so if this object
// is in the nursery we can fall back to numFixedSlots().
if (!isTenured())
if (IsInsideNursery(GetGCThingRuntime(this), this))
return numFixedSlots();
#endif
gc::AllocKind kind = tenuredGetAllocKind();

Просмотреть файл

@ -8111,6 +8111,9 @@ nsCSSFrameConstructor::CreateContinuingFrame(nsPresContext* aPresContext,
} else if (nsGkAtoms::legendFrame == frameType) {
newFrame = NS_NewLegendFrame(shell, styleContext);
newFrame->Init(content, aParentFrame, aFrame);
} else if (nsGkAtoms::flexContainerFrame == frameType) {
newFrame = NS_NewFlexContainerFrame(shell, styleContext);
newFrame->Init(content, aParentFrame, aFrame);
} else {
NS_RUNTIMEABORT("unexpected frame type");
}

Просмотреть файл

@ -515,6 +515,21 @@ protected:
// in our constructor).
};
// Helper function to calculate the sum of our flex items'
// margin-box main sizes.
static nscoord
SumFlexItemMarginBoxMainSizes(const FlexboxAxisTracker& aAxisTracker,
const nsTArray<FlexItem>& aItems)
{
nscoord sum = 0;
for (uint32_t i = 0; i < aItems.Length(); ++i) {
const FlexItem& item = aItems[i];
sum += item.GetMainSize() +
item.GetMarginBorderPaddingSizeInAxis(aAxisTracker.GetMainAxis());
}
return sum;
}
// Helper-function to find the first non-anonymous-box descendent of aFrame.
static nsIFrame*
GetFirstNonAnonBoxDescendant(nsIFrame* aFrame)
@ -1987,7 +2002,9 @@ nscoord
nsFlexContainerFrame::ComputeFlexContainerMainSize(
const nsHTMLReflowState& aReflowState,
const FlexboxAxisTracker& aAxisTracker,
const nsTArray<FlexItem>& aItems)
const nsTArray<FlexItem>& aItems,
nscoord aAvailableHeightForContent,
nsReflowStatus& aStatus)
{
if (IsAxisHorizontal(aAxisTracker.GetMainAxis())) {
// Horizontal case is easy -- our main size is our computed width
@ -1995,23 +2012,96 @@ nsFlexContainerFrame::ComputeFlexContainerMainSize(
return aReflowState.ComputedWidth();
}
// Vertical case, with non-auto-height:
if (aReflowState.ComputedHeight() != NS_AUTOHEIGHT) {
return aReflowState.ComputedHeight();
nscoord effectiveComputedHeight = GetEffectiveComputedHeight(aReflowState);
if (effectiveComputedHeight != NS_INTRINSICSIZE) {
// Vertical case, with fixed height:
if (aAvailableHeightForContent == NS_UNCONSTRAINEDSIZE ||
effectiveComputedHeight < aAvailableHeightForContent) {
// Not in a fragmenting context, OR no need to fragment because we have
// more available height than we need. Either way, just use our fixed
// height. (Note that the reflow state has already done the appropriate
// min/max-height clamping.)
return effectiveComputedHeight;
}
// Fragmenting *and* our fixed height is too tall for available height:
// Mark incomplete so we get a next-in-flow, and take up all of the
// available height (or the amount of height required by our children, if
// that's larger; but of course not more than our own computed height).
// XXXdholbert For now, we don't support pushing children to our next
// continuation or splitting children, so "amount of height required by
// our children" is just the sum of our children's heights.
NS_FRAME_SET_INCOMPLETE(aStatus);
nscoord sumOfChildHeights =
SumFlexItemMarginBoxMainSizes(aAxisTracker, aItems);
if (sumOfChildHeights <= aAvailableHeightForContent) {
return aAvailableHeightForContent;
}
return std::min(effectiveComputedHeight, sumOfChildHeights);
}
// Vertical case, with auto-height:
// Resolve auto-height to the sum of our items' hypothetical outer main
// sizes (their outer heights), clamped to our computed min/max main-size
// properties (min-height & max-height).
nscoord sumOfChildHeights = 0;
for (uint32_t i = 0; i < aItems.Length(); ++i) {
sumOfChildHeights +=
aItems[i].GetMainSize() +
aItems[i].GetMarginBorderPaddingSizeInAxis(aAxisTracker.GetMainAxis());
// XXXdholbert Handle constrained-aAvailableHeightForContent case here.
nscoord sumOfChildHeights =
SumFlexItemMarginBoxMainSizes(aAxisTracker, aItems);
return NS_CSS_MINMAX(sumOfChildHeights,
aReflowState.mComputedMinHeight,
aReflowState.mComputedMaxHeight);
}
nscoord
nsFlexContainerFrame::ComputeFlexContainerCrossSize(
const nsHTMLReflowState& aReflowState,
const FlexboxAxisTracker& aAxisTracker,
nscoord aLineCrossSize,
nscoord aAvailableHeightForContent,
bool* aIsDefinite,
nsReflowStatus& aStatus)
{
MOZ_ASSERT(aIsDefinite, "outparam pointer must be non-null");
if (IsAxisHorizontal(aAxisTracker.GetCrossAxis())) {
// Cross axis is horizontal: our cross size is our computed width
// (which is already resolved).
*aIsDefinite = true;
return aReflowState.ComputedWidth();
}
return NS_CSS_MINMAX(sumOfChildHeights,
nscoord effectiveComputedHeight = GetEffectiveComputedHeight(aReflowState);
if (effectiveComputedHeight != NS_INTRINSICSIZE) {
// Cross-axis is vertical, and we have a fixed height:
*aIsDefinite = true;
if (aAvailableHeightForContent == NS_UNCONSTRAINEDSIZE ||
effectiveComputedHeight < aAvailableHeightForContent) {
// Not in a fragmenting context, OR no need to fragment because we have
// more available height than we need. Either way, just use our fixed
// height. (Note that the reflow state has already done the appropriate
// min/max-height clamping.)
return effectiveComputedHeight;
}
// Fragmenting *and* our fixed height is too tall for available height:
// Mark incomplete so we get a next-in-flow, and take up all of the
// available height (or the amount of height required by our children, if
// that's larger; but of course not more than our own computed height).
// XXXdholbert For now, we don't support pushing children to our next
// continuation or splitting children, so "amount of height required by
// our children" is just our line-height.
NS_FRAME_SET_INCOMPLETE(aStatus);
if (aLineCrossSize <= aAvailableHeightForContent) {
return aAvailableHeightForContent;
}
return std::min(effectiveComputedHeight, aLineCrossSize);
}
// Cross axis is vertical and we have auto-height: shrink-wrap our line(s),
// subject to our min-size / max-size constraints in that (vertical) axis.
// XXXdholbert Handle constrained-aAvailableHeightForContent case here.
*aIsDefinite = false;
return NS_CSS_MINMAX(aLineCrossSize,
aReflowState.mComputedMinHeight,
aReflowState.mComputedMaxHeight);
}
@ -2229,8 +2319,21 @@ nsFlexContainerFrame::Reflow(nsPresContext* aPresContext,
axisTracker, items);
NS_ENSURE_SUCCESS(rv, rv);
// If we're being fragmented into a constrained height, subtract off
// borderpadding-top from it, to get the available height for our
// content box. (Don't subtract if we're skipping top border/padding,
// though.)
nscoord availableHeightForContent = aReflowState.availableHeight;
if (availableHeightForContent != NS_UNCONSTRAINEDSIZE &&
!(GetSkipSides() & (1 << NS_SIDE_TOP))) {
availableHeightForContent -= aReflowState.mComputedBorderPadding.top;
// (Don't let that push availableHeightForContent below zero, though):
availableHeightForContent = std::max(availableHeightForContent, 0);
}
const nscoord contentBoxMainSize =
ComputeFlexContainerMainSize(aReflowState, axisTracker, items);
ComputeFlexContainerMainSize(aReflowState, axisTracker, items,
availableHeightForContent, aStatus);
ResolveFlexibleLengths(axisTracker, contentBoxMainSize, items);
@ -2277,34 +2380,20 @@ nsFlexContainerFrame::Reflow(nsPresContext* aPresContext,
// 'align-content' is 'stretch' -- if it is, we need to give each line an
// additional share of our flex container's desired cross-size. (if it's
// not NS_AUTOHEIGHT and there's any cross-size left over to distribute)
bool isCrossSizeDefinite;
const nscoord contentBoxCrossSize =
ComputeFlexContainerCrossSize(aReflowState, axisTracker,
lineCrossAxisPosnTracker.GetLineCrossSize(),
availableHeightForContent,
&isCrossSizeDefinite, aStatus);
// Calculate the content-box cross size of our flex container:
nscoord contentBoxCrossSize =
GET_CROSS_COMPONENT(axisTracker,
aReflowState.ComputedWidth(),
aReflowState.ComputedHeight());
if (contentBoxCrossSize == NS_AUTOHEIGHT) {
// Unconstrained 'auto' cross-size: shrink-wrap our line(s), subject
// to our min-size / max-size constraints in that axis.
nscoord minCrossSize = GET_CROSS_COMPONENT(axisTracker,
aReflowState.mComputedMinWidth,
aReflowState.mComputedMinHeight);
nscoord maxCrossSize = GET_CROSS_COMPONENT(axisTracker,
aReflowState.mComputedMaxWidth,
aReflowState.mComputedMaxHeight);
contentBoxCrossSize =
NS_CSS_MINMAX(lineCrossAxisPosnTracker.GetLineCrossSize(),
minCrossSize, maxCrossSize);
}
if (lineCrossAxisPosnTracker.GetLineCrossSize() !=
contentBoxCrossSize) {
if (isCrossSizeDefinite) {
// XXXdholbert When we support multi-line flex containers, we should
// distribute any extra space among or between our lines here according
// to 'align-content'. For now, we do the single-line special behavior:
// "If the flex container has only a single line (even if it's a
// multi-line flex container), the cross size of the flex line is the
// flex container's inner cross size."
// "If the flex container has only a single line (even if it's a multi-line
// flex container) and has a definite cross size, the cross size of the
// flex line is the flex container's inner cross size."
lineCrossAxisPosnTracker.SetLineCrossSize(contentBoxCrossSize);
}
@ -2461,8 +2550,9 @@ nsFlexContainerFrame::Reflow(nsPresContext* aPresContext,
aDesiredSize.width = desiredContentBoxSize.width +
containerBorderPadding.LeftRight();
// Does *NOT* include bottom border/padding yet (we add that a bit lower down)
aDesiredSize.height = desiredContentBoxSize.height +
containerBorderPadding.TopBottom();
containerBorderPadding.top;
if (flexContainerAscent == nscoord_MIN) {
// Still don't have our baseline set -- this happens if we have no
@ -2473,12 +2563,36 @@ nsFlexContainerFrame::Reflow(nsPresContext* aPresContext,
"Have flex items but didn't get an ascent - that's odd "
"(or there are just gigantic sizes involved)");
// Per spec, just use the bottom of content-box.
flexContainerAscent = aDesiredSize.height -
aReflowState.mComputedBorderPadding.bottom;
flexContainerAscent = aDesiredSize.height;
}
aDesiredSize.ascent = flexContainerAscent;
// Now: If we're complete, add bottom border/padding to desired height
// (unless that pushes us over available height, in which case we become
// incomplete (unless we already weren't asking for any height, in which case
// we stay complete to avoid looping forever)).
// NOTE: If we're auto-height, we allow our bottom border/padding to push us
// over the available height without requesting a continuation, for
// consistency with the behavior of "display:block" elements.
if (NS_FRAME_IS_COMPLETE(aStatus)) {
// NOTE: We can't use containerBorderPadding.bottom for this, because if
// we're auto-height, ApplySkipSides will have zeroed it (because it
// assumed we might get a continuation). We have the correct value in
// aReflowState.mComputedBorderPadding.bottom, though, so we use that.
nscoord desiredHeightWithBottomBP =
aDesiredSize.height + aReflowState.mComputedBorderPadding.bottom;
if (aDesiredSize.height == 0 ||
desiredHeightWithBottomBP <= aReflowState.availableHeight ||
aReflowState.ComputedHeight() == NS_INTRINSICSIZE) {
// Update desired height to include bottom border/padding
aDesiredSize.height = desiredHeightWithBottomBP;
} else {
// We couldn't fit bottom border/padding, so we'll need a continuation.
NS_FRAME_SET_INCOMPLETE(aStatus);
}
}
// Overflow area = union(my overflow area, kids' overflow areas)
aDesiredSize.SetOverflowAreasToDesiredBounds();
for (nsFrameList::Enumerator e(mFrames); !e.AtEnd(); e.Next()) {

Просмотреть файл

@ -106,7 +106,16 @@ protected:
nscoord ComputeFlexContainerMainSize(const nsHTMLReflowState& aReflowState,
const FlexboxAxisTracker& aAxisTracker,
const nsTArray<FlexItem>& aFlexItems);
const nsTArray<FlexItem>& aFlexItems,
nscoord aAvailableHeightForContent,
nsReflowStatus& aStatus);
nscoord ComputeFlexContainerCrossSize(const nsHTMLReflowState& aReflowState,
const FlexboxAxisTracker& aAxisTracker,
nscoord aLineCrossSize,
nscoord aAvailableHeightForContent,
bool* aIsDefinite,
nsReflowStatus& aStatus);
void PositionItemInMainAxis(MainAxisPositionTracker& aMainAxisPosnTracker,
FlexItem& aItem);

Просмотреть файл

@ -0,0 +1,99 @@
<!DOCTYPE html>
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
<html>
<head>
<style>
.multicol {
height: 10px;
width: 100px;
-moz-column-width: 20px;
-moz-column-fill: auto;
border: 2px solid orange;
}
.flexContainer {
background: teal;
/* border-width is 0 by default; some sub-testcases will increase it. */
border: 0 dashed black;
}
</style>
</head>
<body>
<!-- NO BORDERS/PADDING -->
<!-- ================== -->
<!-- content fits exactly into 1 column: -->
<div class="multicol">
<div class="flexContainer" style="height: 10px"></div>
</div>
<!-- content fits, but margin-top pushes it to overflow: -->
<div class="multicol">
<div class="flexContainer" style="height: 9px;
margin-top: 2px;"></div>
</div>
<!-- content is too tall, by 1px: -->
<div class="multicol">
<div class="flexContainer" style="height: 11px"></div>
</div>
<!-- BORDERS/PADDING ON TOP -->
<!-- ====================== -->
<!-- content fits, but border-top makes us too tall: -->
<div class="multicol">
<div class="flexContainer" style="height: 9px;
border-top-width: 2px"></div>
</div>
<!-- content fits, but padding-top makes us too tall: -->
<div class="multicol">
<div class="flexContainer" style="height: 9px;
padding-top: 2px"></div>
</div>
<!-- content fits, but border/padding-top make us too tall: -->
<div class="multicol">
<div class="flexContainer" style="height: 9px;
border-top-width: 1px;
padding-top: 1px"></div>
</div>
<!-- BORDERS/PADDING ON BOTTOM -->
<!-- ========================= -->
<!-- content fits, but border-bottom-width makes us too tall: -->
<div class="multicol">
<div class="flexContainer" style="height: 9px;
border-bottom-width: 2px"></div>
</div>
<!-- content fits, but padding-bottom makes us too tall: -->
<div class="multicol">
<div class="flexContainer" style="height: 9px;
padding-bottom: 2px"></div>
</div>
<!-- content fits, but border/padding-bottom make us too tall: -->
<div class="multicol">
<div class="flexContainer" style="height: 9px;
border-bottom-width: 1px;
padding-bottom: 1px"></div>
</div>
<!-- BORDERS/PADDING ON TOP AND BOTTOM -->
<!-- ================================= -->
<!-- content fits, but border-top/bottom combined make us too tall: -->
<div class="multicol">
<div class="flexContainer" style="height: 9px;
border-top-width: 1px;
border-bottom-width: 1px"></div>
</div>
<!-- content fits, but padding-top/bottom combined make us too tall: -->
<div class="multicol">
<div class="flexContainer" style="height: 9px;
padding-top: 1px;
padding-bottom: 1px"></div>
</div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,105 @@
<!DOCTYPE html>
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
<!-- Testcase for how we fragment an empty fixed-height flex container, with
various combinations of margin/border/padding helping it to be too tall,
and with the flex container having "flex-direction: row".
-->
<html>
<head>
<style>
.multicol {
height: 10px;
width: 100px;
-moz-column-width: 20px;
-moz-column-fill: auto;
border: 2px solid orange;
}
.flexContainer {
display: flex;
flex-direction: row;
background: teal;
/* border-width is 0 by default; some sub-testcases will increase it. */
border: 0 dashed black;
}
</style>
</head>
<body>
<!-- NO BORDERS/PADDING -->
<!-- ================== -->
<!-- content fits exactly into 1 column: -->
<div class="multicol">
<div class="flexContainer" style="height: 10px"></div>
</div>
<!-- content fits, but margin-top pushes it to overflow: -->
<div class="multicol">
<div class="flexContainer" style="height: 9px;
margin-top: 2px;"></div>
</div>
<!-- content is too tall, by 1px: -->
<div class="multicol">
<div class="flexContainer" style="height: 11px"></div>
</div>
<!-- BORDERS/PADDING ON TOP -->
<!-- ====================== -->
<!-- content fits, but border-top makes us too tall: -->
<div class="multicol">
<div class="flexContainer" style="height: 9px;
border-top-width: 2px"></div>
</div>
<!-- content fits, but padding-top makes us too tall: -->
<div class="multicol">
<div class="flexContainer" style="height: 9px;
padding-top: 2px"></div>
</div>
<!-- content fits, but border/padding-top make us too tall: -->
<div class="multicol">
<div class="flexContainer" style="height: 9px;
border-top-width: 1px;
padding-top: 1px"></div>
</div>
<!-- BORDERS/PADDING ON BOTTOM -->
<!-- ========================= -->
<!-- content fits, but border-bottom-width makes us too tall: -->
<div class="multicol">
<div class="flexContainer" style="height: 9px;
border-bottom-width: 2px"></div>
</div>
<!-- content fits, but padding-bottom makes us too tall: -->
<div class="multicol">
<div class="flexContainer" style="height: 9px;
padding-bottom: 2px"></div>
</div>
<!-- content fits, but border/padding-bottom make us too tall: -->
<div class="multicol">
<div class="flexContainer" style="height: 9px;
border-bottom-width: 1px;
padding-bottom: 1px"></div>
</div>
<!-- BORDERS/PADDING ON TOP AND BOTTOM -->
<!-- ================================= -->
<!-- content fits, but border-top/bottom combined make us too tall: -->
<div class="multicol">
<div class="flexContainer" style="height: 9px;
border-top-width: 1px;
border-bottom-width: 1px"></div>
</div>
<!-- content fits, but padding-top/bottom combined make us too tall: -->
<div class="multicol">
<div class="flexContainer" style="height: 9px;
padding-top: 1px;
padding-bottom: 1px"></div>
</div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,105 @@
<!DOCTYPE html>
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
<!-- Testcase for how we fragment an empty fixed-height flex container, with
various combinations of margin/border/padding helping it to be too tall,
and with the flex container having "flex-direction: row-reverse".
-->
<html>
<head>
<style>
.multicol {
height: 10px;
width: 100px;
-moz-column-width: 20px;
-moz-column-fill: auto;
border: 2px solid orange;
}
.flexContainer {
display: flex;
flex-direction: row-reverse;
background: teal;
/* border-width is 0 by default; some sub-testcases will increase it. */
border: 0 dashed black;
}
</style>
</head>
<body>
<!-- NO BORDERS/PADDING -->
<!-- ================== -->
<!-- content fits exactly into 1 column: -->
<div class="multicol">
<div class="flexContainer" style="height: 10px"></div>
</div>
<!-- content fits, but margin-top pushes it to overflow: -->
<div class="multicol">
<div class="flexContainer" style="height: 9px;
margin-top: 2px;"></div>
</div>
<!-- content is too tall, by 1px: -->
<div class="multicol">
<div class="flexContainer" style="height: 11px"></div>
</div>
<!-- BORDERS/PADDING ON TOP -->
<!-- ====================== -->
<!-- content fits, but border-top makes us too tall: -->
<div class="multicol">
<div class="flexContainer" style="height: 9px;
border-top-width: 2px"></div>
</div>
<!-- content fits, but padding-top makes us too tall: -->
<div class="multicol">
<div class="flexContainer" style="height: 9px;
padding-top: 2px"></div>
</div>
<!-- content fits, but border/padding-top make us too tall: -->
<div class="multicol">
<div class="flexContainer" style="height: 9px;
border-top-width: 1px;
padding-top: 1px"></div>
</div>
<!-- BORDERS/PADDING ON BOTTOM -->
<!-- ========================= -->
<!-- content fits, but border-bottom-width makes us too tall: -->
<div class="multicol">
<div class="flexContainer" style="height: 9px;
border-bottom-width: 2px"></div>
</div>
<!-- content fits, but padding-bottom makes us too tall: -->
<div class="multicol">
<div class="flexContainer" style="height: 9px;
padding-bottom: 2px"></div>
</div>
<!-- content fits, but border/padding-bottom make us too tall: -->
<div class="multicol">
<div class="flexContainer" style="height: 9px;
border-bottom-width: 1px;
padding-bottom: 1px"></div>
</div>
<!-- BORDERS/PADDING ON TOP AND BOTTOM -->
<!-- ================================= -->
<!-- content fits, but border-top/bottom combined make us too tall: -->
<div class="multicol">
<div class="flexContainer" style="height: 9px;
border-top-width: 1px;
border-bottom-width: 1px"></div>
</div>
<!-- content fits, but padding-top/bottom combined make us too tall: -->
<div class="multicol">
<div class="flexContainer" style="height: 9px;
padding-top: 1px;
padding-bottom: 1px"></div>
</div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,105 @@
<!DOCTYPE html>
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
<!-- Testcase for how we fragment an empty fixed-height flex container, with
various combinations of margin/border/padding helping it to be too tall,
and with the flex container having "flex-direction: column".
-->
<html>
<head>
<style>
.multicol {
height: 10px;
width: 100px;
-moz-column-width: 20px;
-moz-column-fill: auto;
border: 2px solid orange;
}
.flexContainer {
display: flex;
flex-direction: column;
background: teal;
/* border-width is 0 by default; some sub-testcases will increase it. */
border: 0 dashed black;
}
</style>
</head>
<body>
<!-- NO BORDERS/PADDING -->
<!-- ================== -->
<!-- content fits exactly into 1 column: -->
<div class="multicol">
<div class="flexContainer" style="height: 10px"></div>
</div>
<!-- content fits, but margin-top pushes it to overflow: -->
<div class="multicol">
<div class="flexContainer" style="height: 9px;
margin-top: 2px;"></div>
</div>
<!-- content is too tall, by 1px: -->
<div class="multicol">
<div class="flexContainer" style="height: 11px"></div>
</div>
<!-- BORDERS/PADDING ON TOP -->
<!-- ====================== -->
<!-- content fits, but border-top makes us too tall: -->
<div class="multicol">
<div class="flexContainer" style="height: 9px;
border-top-width: 2px"></div>
</div>
<!-- content fits, but padding-top makes us too tall: -->
<div class="multicol">
<div class="flexContainer" style="height: 9px;
padding-top: 2px"></div>
</div>
<!-- content fits, but border/padding-top make us too tall: -->
<div class="multicol">
<div class="flexContainer" style="height: 9px;
border-top-width: 1px;
padding-top: 1px"></div>
</div>
<!-- BORDERS/PADDING ON BOTTOM -->
<!-- ========================= -->
<!-- content fits, but border-bottom-width makes us too tall: -->
<div class="multicol">
<div class="flexContainer" style="height: 9px;
border-bottom-width: 2px"></div>
</div>
<!-- content fits, but padding-bottom makes us too tall: -->
<div class="multicol">
<div class="flexContainer" style="height: 9px;
padding-bottom: 2px"></div>
</div>
<!-- content fits, but border/padding-bottom make us too tall: -->
<div class="multicol">
<div class="flexContainer" style="height: 9px;
border-bottom-width: 1px;
padding-bottom: 1px"></div>
</div>
<!-- BORDERS/PADDING ON TOP AND BOTTOM -->
<!-- ================================= -->
<!-- content fits, but border-top/bottom combined make us too tall: -->
<div class="multicol">
<div class="flexContainer" style="height: 9px;
border-top-width: 1px;
border-bottom-width: 1px"></div>
</div>
<!-- content fits, but padding-top/bottom combined make us too tall: -->
<div class="multicol">
<div class="flexContainer" style="height: 9px;
padding-top: 1px;
padding-bottom: 1px"></div>
</div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,105 @@
<!DOCTYPE html>
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
<!-- Testcase for how we fragment an empty fixed-height flex container, with
various combinations of margin/border/padding helping it to be too tall,
and with the flex container having "flex-direction: column-reverse".
-->
<html>
<head>
<style>
.multicol {
height: 10px;
width: 100px;
-moz-column-width: 20px;
-moz-column-fill: auto;
border: 2px solid orange;
}
.flexContainer {
display: flex;
flex-direction: column-reverse;
background: teal;
/* border-width is 0 by default; some sub-testcases will increase it. */
border: 0 dashed black;
}
</style>
</head>
<body>
<!-- NO BORDERS/PADDING -->
<!-- ================== -->
<!-- content fits exactly into 1 column: -->
<div class="multicol">
<div class="flexContainer" style="height: 10px"></div>
</div>
<!-- content fits, but margin-top pushes it to overflow: -->
<div class="multicol">
<div class="flexContainer" style="height: 9px;
margin-top: 2px;"></div>
</div>
<!-- content is too tall, by 1px: -->
<div class="multicol">
<div class="flexContainer" style="height: 11px"></div>
</div>
<!-- BORDERS/PADDING ON TOP -->
<!-- ====================== -->
<!-- content fits, but border-top makes us too tall: -->
<div class="multicol">
<div class="flexContainer" style="height: 9px;
border-top-width: 2px"></div>
</div>
<!-- content fits, but padding-top makes us too tall: -->
<div class="multicol">
<div class="flexContainer" style="height: 9px;
padding-top: 2px"></div>
</div>
<!-- content fits, but border/padding-top make us too tall: -->
<div class="multicol">
<div class="flexContainer" style="height: 9px;
border-top-width: 1px;
padding-top: 1px"></div>
</div>
<!-- BORDERS/PADDING ON BOTTOM -->
<!-- ========================= -->
<!-- content fits, but border-bottom-width makes us too tall: -->
<div class="multicol">
<div class="flexContainer" style="height: 9px;
border-bottom-width: 2px"></div>
</div>
<!-- content fits, but padding-bottom makes us too tall: -->
<div class="multicol">
<div class="flexContainer" style="height: 9px;
padding-bottom: 2px"></div>
</div>
<!-- content fits, but border/padding-bottom make us too tall: -->
<div class="multicol">
<div class="flexContainer" style="height: 9px;
border-bottom-width: 1px;
padding-bottom: 1px"></div>
</div>
<!-- BORDERS/PADDING ON TOP AND BOTTOM -->
<!-- ================================= -->
<!-- content fits, but border-top/bottom combined make us too tall: -->
<div class="multicol">
<div class="flexContainer" style="height: 9px;
border-top-width: 1px;
border-bottom-width: 1px"></div>
</div>
<!-- content fits, but padding-top/bottom combined make us too tall: -->
<div class="multicol">
<div class="flexContainer" style="height: 9px;
padding-top: 1px;
padding-bottom: 1px"></div>
</div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,109 @@
<!DOCTYPE html>
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
<!-- Testcase for how we fragment an empty fixed-height flex container, with
various combinations of margin/border/padding helping it to be too tall,
with the flex container overflowing its fixed-height-block parent,
and with the flex container having "flex-direction: row".
-->
<html>
<head>
<style>
.multicol {
height: 10px;
width: 100px;
-moz-column-width: 20px;
-moz-column-fill: auto;
border: 2px solid orange;
}
.fixedHeightBlock {
height: 2px;
}
.flexContainer {
display: flex;
flex-direction: row;
background: teal;
/* border-width is 0 by default; some sub-testcases will increase it. */
border: 0 dashed black;
}
</style>
</head>
<body>
<!-- NO BORDERS/PADDING -->
<!-- ================== -->
<!-- content fits exactly into 1 column: -->
<div class="multicol"><div class="fixedHeightBlock">
<div class="flexContainer" style="height: 10px"></div>
</div></div>
<!-- content fits, but margin-top pushes it to overflow: -->
<div class="multicol"><div class="fixedHeightBlock">
<div class="flexContainer" style="height: 9px;
margin-top: 2px;"></div>
</div></div>
<!-- content is too tall, by 1px: -->
<div class="multicol"><div class="fixedHeightBlock">
<div class="flexContainer" style="height: 11px"></div>
</div></div>
<!-- BORDERS/PADDING ON TOP -->
<!-- ====================== -->
<!-- content fits, but border-top makes us too tall: -->
<div class="multicol"><div class="fixedHeightBlock">
<div class="flexContainer" style="height: 9px;
border-top-width: 2px"></div>
</div></div>
<!-- content fits, but padding-top makes us too tall: -->
<div class="multicol"><div class="fixedHeightBlock">
<div class="flexContainer" style="height: 9px;
padding-top: 2px"></div>
</div></div>
<!-- content fits, but border/padding-top make us too tall: -->
<div class="multicol"><div class="fixedHeightBlock">
<div class="flexContainer" style="height: 9px;
border-top-width: 1px;
padding-top: 1px"></div>
</div></div>
<!-- BORDERS/PADDING ON BOTTOM -->
<!-- ========================= -->
<!-- content fits, but border-bottom-width makes us too tall: -->
<div class="multicol"><div class="fixedHeightBlock">
<div class="flexContainer" style="height: 9px;
border-bottom-width: 2px"></div>
</div></div>
<!-- content fits, but padding-bottom makes us too tall: -->
<div class="multicol"><div class="fixedHeightBlock">
<div class="flexContainer" style="height: 9px;
padding-bottom: 2px"></div>
</div></div>
<!-- content fits, but border/padding-bottom make us too tall: -->
<div class="multicol"><div class="fixedHeightBlock">
<div class="flexContainer" style="height: 9px;
border-bottom-width: 1px;
padding-bottom: 1px"></div>
</div></div>
<!-- BORDERS/PADDING ON TOP AND BOTTOM -->
<!-- ================================= -->
<!-- content fits, but border-top/bottom combined make us too tall: -->
<div class="multicol"><div class="fixedHeightBlock">
<div class="flexContainer" style="height: 9px;
border-top-width: 1px;
border-bottom-width: 1px"></div>
</div></div>
<!-- content fits, but padding-top/bottom combined make us too tall: -->
<div class="multicol"><div class="fixedHeightBlock">
<div class="flexContainer" style="height: 9px;
padding-top: 1px;
padding-bottom: 1px"></div>
</div></div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,109 @@
<!DOCTYPE html>
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
<!-- Testcase for how we fragment an empty fixed-height flex container, with
various combinations of margin/border/padding helping it to be too tall,
with the flex container overflowing its fixed-height-block parent,
and with the flex container having "flex-direction: row-reverse".
-->
<html>
<head>
<style>
.multicol {
height: 10px;
width: 100px;
-moz-column-width: 20px;
-moz-column-fill: auto;
border: 2px solid orange;
}
.fixedHeightBlock {
height: 2px;
}
.flexContainer {
display: flex;
flex-direction: row-reverse;
background: teal;
/* border-width is 0 by default; some sub-testcases will increase it. */
border: 0 dashed black;
}
</style>
</head>
<body>
<!-- NO BORDERS/PADDING -->
<!-- ================== -->
<!-- content fits exactly into 1 column: -->
<div class="multicol"><div class="fixedHeightBlock">
<div class="flexContainer" style="height: 10px"></div>
</div></div>
<!-- content fits, but margin-top pushes it to overflow: -->
<div class="multicol"><div class="fixedHeightBlock">
<div class="flexContainer" style="height: 9px;
margin-top: 2px;"></div>
</div></div>
<!-- content is too tall, by 1px: -->
<div class="multicol"><div class="fixedHeightBlock">
<div class="flexContainer" style="height: 11px"></div>
</div></div>
<!-- BORDERS/PADDING ON TOP -->
<!-- ====================== -->
<!-- content fits, but border-top makes us too tall: -->
<div class="multicol"><div class="fixedHeightBlock">
<div class="flexContainer" style="height: 9px;
border-top-width: 2px"></div>
</div></div>
<!-- content fits, but padding-top makes us too tall: -->
<div class="multicol"><div class="fixedHeightBlock">
<div class="flexContainer" style="height: 9px;
padding-top: 2px"></div>
</div></div>
<!-- content fits, but border/padding-top make us too tall: -->
<div class="multicol"><div class="fixedHeightBlock">
<div class="flexContainer" style="height: 9px;
border-top-width: 1px;
padding-top: 1px"></div>
</div></div>
<!-- BORDERS/PADDING ON BOTTOM -->
<!-- ========================= -->
<!-- content fits, but border-bottom-width makes us too tall: -->
<div class="multicol"><div class="fixedHeightBlock">
<div class="flexContainer" style="height: 9px;
border-bottom-width: 2px"></div>
</div></div>
<!-- content fits, but padding-bottom makes us too tall: -->
<div class="multicol"><div class="fixedHeightBlock">
<div class="flexContainer" style="height: 9px;
padding-bottom: 2px"></div>
</div></div>
<!-- content fits, but border/padding-bottom make us too tall: -->
<div class="multicol"><div class="fixedHeightBlock">
<div class="flexContainer" style="height: 9px;
border-bottom-width: 1px;
padding-bottom: 1px"></div>
</div></div>
<!-- BORDERS/PADDING ON TOP AND BOTTOM -->
<!-- ================================= -->
<!-- content fits, but border-top/bottom combined make us too tall: -->
<div class="multicol"><div class="fixedHeightBlock">
<div class="flexContainer" style="height: 9px;
border-top-width: 1px;
border-bottom-width: 1px"></div>
</div></div>
<!-- content fits, but padding-top/bottom combined make us too tall: -->
<div class="multicol"><div class="fixedHeightBlock">
<div class="flexContainer" style="height: 9px;
padding-top: 1px;
padding-bottom: 1px"></div>
</div></div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,109 @@
<!DOCTYPE html>
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
<!-- Testcase for how we fragment an empty fixed-height flex container, with
various combinations of margin/border/padding helping it to be too tall,
with the flex container overflowing its fixed-height-block parent,
and with the flex container having "flex-direction: column".
-->
<html>
<head>
<style>
.multicol {
height: 10px;
width: 100px;
-moz-column-width: 20px;
-moz-column-fill: auto;
border: 2px solid orange;
}
.fixedHeightBlock {
height: 2px;
}
.flexContainer {
display: flex;
flex-direction: column;
background: teal;
/* border-width is 0 by default; some sub-testcases will increase it. */
border: 0 dashed black;
}
</style>
</head>
<body>
<!-- NO BORDERS/PADDING -->
<!-- ================== -->
<!-- content fits exactly into 1 column: -->
<div class="multicol"><div class="fixedHeightBlock">
<div class="flexContainer" style="height: 10px"></div>
</div></div>
<!-- content fits, but margin-top pushes it to overflow: -->
<div class="multicol"><div class="fixedHeightBlock">
<div class="flexContainer" style="height: 9px;
margin-top: 2px;"></div>
</div></div>
<!-- content is too tall, by 1px: -->
<div class="multicol"><div class="fixedHeightBlock">
<div class="flexContainer" style="height: 11px"></div>
</div></div>
<!-- BORDERS/PADDING ON TOP -->
<!-- ====================== -->
<!-- content fits, but border-top makes us too tall: -->
<div class="multicol"><div class="fixedHeightBlock">
<div class="flexContainer" style="height: 9px;
border-top-width: 2px"></div>
</div></div>
<!-- content fits, but padding-top makes us too tall: -->
<div class="multicol"><div class="fixedHeightBlock">
<div class="flexContainer" style="height: 9px;
padding-top: 2px"></div>
</div></div>
<!-- content fits, but border/padding-top make us too tall: -->
<div class="multicol"><div class="fixedHeightBlock">
<div class="flexContainer" style="height: 9px;
border-top-width: 1px;
padding-top: 1px"></div>
</div></div>
<!-- BORDERS/PADDING ON BOTTOM -->
<!-- ========================= -->
<!-- content fits, but border-bottom-width makes us too tall: -->
<div class="multicol"><div class="fixedHeightBlock">
<div class="flexContainer" style="height: 9px;
border-bottom-width: 2px"></div>
</div></div>
<!-- content fits, but padding-bottom makes us too tall: -->
<div class="multicol"><div class="fixedHeightBlock">
<div class="flexContainer" style="height: 9px;
padding-bottom: 2px"></div>
</div></div>
<!-- content fits, but border/padding-bottom make us too tall: -->
<div class="multicol"><div class="fixedHeightBlock">
<div class="flexContainer" style="height: 9px;
border-bottom-width: 1px;
padding-bottom: 1px"></div>
</div></div>
<!-- BORDERS/PADDING ON TOP AND BOTTOM -->
<!-- ================================= -->
<!-- content fits, but border-top/bottom combined make us too tall: -->
<div class="multicol"><div class="fixedHeightBlock">
<div class="flexContainer" style="height: 9px;
border-top-width: 1px;
border-bottom-width: 1px"></div>
</div></div>
<!-- content fits, but padding-top/bottom combined make us too tall: -->
<div class="multicol"><div class="fixedHeightBlock">
<div class="flexContainer" style="height: 9px;
padding-top: 1px;
padding-bottom: 1px"></div>
</div></div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,109 @@
<!DOCTYPE html>
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
<!-- Testcase for how we fragment an empty fixed-height flex container, with
various combinations of margin/border/padding helping it to be too tall,
with the flex container overflowing its fixed-height-block parent,
and with the flex container having "flex-direction: column-reverse".
-->
<html>
<head>
<style>
.multicol {
height: 10px;
width: 100px;
-moz-column-width: 20px;
-moz-column-fill: auto;
border: 2px solid orange;
}
.fixedHeightBlock {
height: 2px;
}
.flexContainer {
display: flex;
flex-direction: column-reverse;
background: teal;
/* border-width is 0 by default; some sub-testcases will increase it. */
border: 0 dashed black;
}
</style>
</head>
<body>
<!-- NO BORDERS/PADDING -->
<!-- ================== -->
<!-- content fits exactly into 1 column: -->
<div class="multicol"><div class="fixedHeightBlock">
<div class="flexContainer" style="height: 10px"></div>
</div></div>
<!-- content fits, but margin-top pushes it to overflow: -->
<div class="multicol"><div class="fixedHeightBlock">
<div class="flexContainer" style="height: 9px;
margin-top: 2px;"></div>
</div></div>
<!-- content is too tall, by 1px: -->
<div class="multicol"><div class="fixedHeightBlock">
<div class="flexContainer" style="height: 11px"></div>
</div></div>
<!-- BORDERS/PADDING ON TOP -->
<!-- ====================== -->
<!-- content fits, but border-top makes us too tall: -->
<div class="multicol"><div class="fixedHeightBlock">
<div class="flexContainer" style="height: 9px;
border-top-width: 2px"></div>
</div></div>
<!-- content fits, but padding-top makes us too tall: -->
<div class="multicol"><div class="fixedHeightBlock">
<div class="flexContainer" style="height: 9px;
padding-top: 2px"></div>
</div></div>
<!-- content fits, but border/padding-top make us too tall: -->
<div class="multicol"><div class="fixedHeightBlock">
<div class="flexContainer" style="height: 9px;
border-top-width: 1px;
padding-top: 1px"></div>
</div></div>
<!-- BORDERS/PADDING ON BOTTOM -->
<!-- ========================= -->
<!-- content fits, but border-bottom-width makes us too tall: -->
<div class="multicol"><div class="fixedHeightBlock">
<div class="flexContainer" style="height: 9px;
border-bottom-width: 2px"></div>
</div></div>
<!-- content fits, but padding-bottom makes us too tall: -->
<div class="multicol"><div class="fixedHeightBlock">
<div class="flexContainer" style="height: 9px;
padding-bottom: 2px"></div>
</div></div>
<!-- content fits, but border/padding-bottom make us too tall: -->
<div class="multicol"><div class="fixedHeightBlock">
<div class="flexContainer" style="height: 9px;
border-bottom-width: 1px;
padding-bottom: 1px"></div>
</div></div>
<!-- BORDERS/PADDING ON TOP AND BOTTOM -->
<!-- ================================= -->
<!-- content fits, but border-top/bottom combined make us too tall: -->
<div class="multicol"><div class="fixedHeightBlock">
<div class="flexContainer" style="height: 9px;
border-top-width: 1px;
border-bottom-width: 1px"></div>
</div></div>
<!-- content fits, but padding-top/bottom combined make us too tall: -->
<div class="multicol"><div class="fixedHeightBlock">
<div class="flexContainer" style="height: 9px;
padding-top: 1px;
padding-bottom: 1px"></div>
</div></div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,136 @@
<!DOCTYPE html>
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
<!-- Testcase for how we fragment an empty fixed-height flex container, with
margin/border/padding that are larger than the available height,
and with the flex container having "flex-direction: row".
-->
<html>
<head>
<style>
.multicol {
height: 10px;
width: 100px;
-moz-column-width: 20px;
-moz-column-fill: auto;
border: 2px solid orange;
margin-bottom: 2px;
}
.flexContainer {
background: teal;
/* border-width is 0 by default; some sub-testcases will increase it. */
border: 0 dashed black;
}
</style>
</head>
<body>
<!-- MARGIN LARGER THAN AVAILABLE HEIGHT -->
<!-- =================================== -->
<!-- margin-top is the available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
margin-top: 10px"></div>
</div>
<!-- margin-top is larger than available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
margin-top: 11px"></div>
</div>
<!-- margin-bottom is exactly the available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
margin-bottom: 10px"></div>
</div>
<!-- margin-bottom is larger than available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
margin-bottom: 11px"></div>
</div>
<!-- BORDER LARGER THAN AVAILABLE HEIGHT -->
<!-- =================================== -->
<!-- border-top-width is the available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
border-top-width: 10px"></div>
</div>
<!-- border-top-width is larger than available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
border-top-width: 11px"></div>
</div>
<!-- border-bottom-width is exactly the available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
border-bottom-width: 10px"></div>
</div>
<!-- border-bottom-width is larger than available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
border-bottom-width: 11px"></div>
</div>
<!-- PADDING LARGER THAN AVAILABLE HEIGHT -->
<!-- ==================================== -->
<!-- padding-top is the available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
padding-top: 10px"></div>
</div>
<!-- padding-top is larger than available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
padding-top: 11px"></div>
</div>
<!-- padding-bottom is exactly the available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
padding-bottom: 10px"></div>
</div>
<!-- padding-bottom is larger than available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
padding-bottom: 11px"></div>
</div>
<!-- BORDER+PADDING LARGER THAN AVAILABLE HEIGHT -->
<!-- =========================================== -->
<!-- border+padding-top is the available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
border-top: 5px;
padding-top: 5px"></div>
</div>
<!-- padding-top is larger than available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
border-top: 6px;
padding-top: 6px"></div>
</div>
<!-- padding-bottom is exactly the available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
border-bottom: 5px;
padding-bottom: 5px"></div>
</div>
<!-- padding-bottom is larger than available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
border-bottom: 6px;
padding-bottom: 6px"></div>
</div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,138 @@
<!DOCTYPE html>
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
<!-- Testcase for how we fragment an empty fixed-height flex container, with
margin/border/padding that are larger than the available height,
and with the flex container having "flex-direction: row".
-->
<html>
<head>
<style>
.multicol {
height: 10px;
width: 100px;
-moz-column-width: 20px;
-moz-column-fill: auto;
border: 2px solid orange;
margin-bottom: 2px;
}
.flexContainer {
display: flex;
flex-direction: row;
background: teal;
/* border-width is 0 by default; some sub-testcases will increase it. */
border: 0 dashed black;
}
</style>
</head>
<body>
<!-- MARGIN LARGER THAN AVAILABLE HEIGHT -->
<!-- =================================== -->
<!-- margin-top is the available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
margin-top: 10px"></div>
</div>
<!-- margin-top is larger than available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
margin-top: 11px"></div>
</div>
<!-- margin-bottom is exactly the available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
margin-bottom: 10px"></div>
</div>
<!-- margin-bottom is larger than available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
margin-bottom: 11px"></div>
</div>
<!-- BORDER LARGER THAN AVAILABLE HEIGHT -->
<!-- =================================== -->
<!-- border-top-width is the available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
border-top-width: 10px"></div>
</div>
<!-- border-top-width is larger than available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
border-top-width: 11px"></div>
</div>
<!-- border-bottom-width is exactly the available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
border-bottom-width: 10px"></div>
</div>
<!-- border-bottom-width is larger than available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
border-bottom-width: 11px"></div>
</div>
<!-- PADDING LARGER THAN AVAILABLE HEIGHT -->
<!-- ==================================== -->
<!-- padding-top is the available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
padding-top: 10px"></div>
</div>
<!-- padding-top is larger than available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
padding-top: 11px"></div>
</div>
<!-- padding-bottom is exactly the available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
padding-bottom: 10px"></div>
</div>
<!-- padding-bottom is larger than available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
padding-bottom: 11px"></div>
</div>
<!-- BORDER+PADDING LARGER THAN AVAILABLE HEIGHT -->
<!-- =========================================== -->
<!-- border+padding-top is the available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
border-top: 5px;
padding-top: 5px"></div>
</div>
<!-- padding-top is larger than available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
border-top: 6px;
padding-top: 6px"></div>
</div>
<!-- padding-bottom is exactly the available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
border-bottom: 5px;
padding-bottom: 5px"></div>
</div>
<!-- padding-bottom is larger than available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
border-bottom: 6px;
padding-bottom: 6px"></div>
</div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,138 @@
<!DOCTYPE html>
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
<!-- Testcase for how we fragment an empty fixed-height flex container, with
margin/border/padding that are larger than the available height,
and with the flex container having "flex-direction: row-reverse".
-->
<html>
<head>
<style>
.multicol {
height: 10px;
width: 100px;
-moz-column-width: 20px;
-moz-column-fill: auto;
border: 2px solid orange;
margin-bottom: 2px;
}
.flexContainer {
display: flex;
flex-direction: row-reverse;
background: teal;
/* border-width is 0 by default; some sub-testcases will increase it. */
border: 0 dashed black;
}
</style>
</head>
<body>
<!-- MARGIN LARGER THAN AVAILABLE HEIGHT -->
<!-- =================================== -->
<!-- margin-top is the available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
margin-top: 10px"></div>
</div>
<!-- margin-top is larger than available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
margin-top: 11px"></div>
</div>
<!-- margin-bottom is exactly the available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
margin-bottom: 10px"></div>
</div>
<!-- margin-bottom is larger than available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
margin-bottom: 11px"></div>
</div>
<!-- BORDER LARGER THAN AVAILABLE HEIGHT -->
<!-- =================================== -->
<!-- border-top-width is the available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
border-top-width: 10px"></div>
</div>
<!-- border-top-width is larger than available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
border-top-width: 11px"></div>
</div>
<!-- border-bottom-width is exactly the available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
border-bottom-width: 10px"></div>
</div>
<!-- border-bottom-width is larger than available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
border-bottom-width: 11px"></div>
</div>
<!-- PADDING LARGER THAN AVAILABLE HEIGHT -->
<!-- ==================================== -->
<!-- padding-top is the available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
padding-top: 10px"></div>
</div>
<!-- padding-top is larger than available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
padding-top: 11px"></div>
</div>
<!-- padding-bottom is exactly the available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
padding-bottom: 10px"></div>
</div>
<!-- padding-bottom is larger than available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
padding-bottom: 11px"></div>
</div>
<!-- BORDER+PADDING LARGER THAN AVAILABLE HEIGHT -->
<!-- =========================================== -->
<!-- border+padding-top is the available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
border-top: 5px;
padding-top: 5px"></div>
</div>
<!-- padding-top is larger than available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
border-top: 6px;
padding-top: 6px"></div>
</div>
<!-- padding-bottom is exactly the available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
border-bottom: 5px;
padding-bottom: 5px"></div>
</div>
<!-- padding-bottom is larger than available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
border-bottom: 6px;
padding-bottom: 6px"></div>
</div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,138 @@
<!DOCTYPE html>
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
<!-- Testcase for how we fragment an empty fixed-height flex container, with
margin/border/padding that are larger than the available height,
and with the flex container having "flex-direction: column".
-->
<html>
<head>
<style>
.multicol {
height: 10px;
width: 100px;
-moz-column-width: 20px;
-moz-column-fill: auto;
border: 2px solid orange;
margin-bottom: 2px;
}
.flexContainer {
display: flex;
flex-direction: column;
background: teal;
/* border-width is 0 by default; some sub-testcases will increase it. */
border: 0 dashed black;
}
</style>
</head>
<body>
<!-- MARGIN LARGER THAN AVAILABLE HEIGHT -->
<!-- =================================== -->
<!-- margin-top is the available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
margin-top: 10px"></div>
</div>
<!-- margin-top is larger than available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
margin-top: 11px"></div>
</div>
<!-- margin-bottom is exactly the available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
margin-bottom: 10px"></div>
</div>
<!-- margin-bottom is larger than available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
margin-bottom: 11px"></div>
</div>
<!-- BORDER LARGER THAN AVAILABLE HEIGHT -->
<!-- =================================== -->
<!-- border-top-width is the available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
border-top-width: 10px"></div>
</div>
<!-- border-top-width is larger than available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
border-top-width: 11px"></div>
</div>
<!-- border-bottom-width is exactly the available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
border-bottom-width: 10px"></div>
</div>
<!-- border-bottom-width is larger than available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
border-bottom-width: 11px"></div>
</div>
<!-- PADDING LARGER THAN AVAILABLE HEIGHT -->
<!-- ==================================== -->
<!-- padding-top is the available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
padding-top: 10px"></div>
</div>
<!-- padding-top is larger than available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
padding-top: 11px"></div>
</div>
<!-- padding-bottom is exactly the available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
padding-bottom: 10px"></div>
</div>
<!-- padding-bottom is larger than available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
padding-bottom: 11px"></div>
</div>
<!-- BORDER+PADDING LARGER THAN AVAILABLE HEIGHT -->
<!-- =========================================== -->
<!-- border+padding-top is the available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
border-top: 5px;
padding-top: 5px"></div>
</div>
<!-- padding-top is larger than available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
border-top: 6px;
padding-top: 6px"></div>
</div>
<!-- padding-bottom is exactly the available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
border-bottom: 5px;
padding-bottom: 5px"></div>
</div>
<!-- padding-bottom is larger than available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
border-bottom: 6px;
padding-bottom: 6px"></div>
</div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,138 @@
<!DOCTYPE html>
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
<!-- Testcase for how we fragment an empty fixed-height flex container, with
margin/border/padding that are larger than the available height,
and with the flex container having "flex-direction: column-reverse".
-->
<html>
<head>
<style>
.multicol {
height: 10px;
width: 100px;
-moz-column-width: 20px;
-moz-column-fill: auto;
border: 2px solid orange;
margin-bottom: 2px;
}
.flexContainer {
display: flex;
flex-direction: column-reverse;
background: teal;
/* border-width is 0 by default; some sub-testcases will increase it. */
border: 0 dashed black;
}
</style>
</head>
<body>
<!-- MARGIN LARGER THAN AVAILABLE HEIGHT -->
<!-- =================================== -->
<!-- margin-top is the available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
margin-top: 10px"></div>
</div>
<!-- margin-top is larger than available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
margin-top: 11px"></div>
</div>
<!-- margin-bottom is exactly the available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
margin-bottom: 10px"></div>
</div>
<!-- margin-bottom is larger than available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
margin-bottom: 11px"></div>
</div>
<!-- BORDER LARGER THAN AVAILABLE HEIGHT -->
<!-- =================================== -->
<!-- border-top-width is the available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
border-top-width: 10px"></div>
</div>
<!-- border-top-width is larger than available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
border-top-width: 11px"></div>
</div>
<!-- border-bottom-width is exactly the available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
border-bottom-width: 10px"></div>
</div>
<!-- border-bottom-width is larger than available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
border-bottom-width: 11px"></div>
</div>
<!-- PADDING LARGER THAN AVAILABLE HEIGHT -->
<!-- ==================================== -->
<!-- padding-top is the available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
padding-top: 10px"></div>
</div>
<!-- padding-top is larger than available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
padding-top: 11px"></div>
</div>
<!-- padding-bottom is exactly the available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
padding-bottom: 10px"></div>
</div>
<!-- padding-bottom is larger than available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
padding-bottom: 11px"></div>
</div>
<!-- BORDER+PADDING LARGER THAN AVAILABLE HEIGHT -->
<!-- =========================================== -->
<!-- border+padding-top is the available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
border-top: 5px;
padding-top: 5px"></div>
</div>
<!-- padding-top is larger than available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
border-top: 6px;
padding-top: 6px"></div>
</div>
<!-- padding-bottom is exactly the available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
border-bottom: 5px;
padding-bottom: 5px"></div>
</div>
<!-- padding-bottom is larger than available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px;
border-bottom: 6px;
padding-bottom: 6px"></div>
</div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,62 @@
<!DOCTYPE html>
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
<html>
<head>
<style>
.multicol {
height: 10px;
width: 100px;
-moz-column-width: 20px;
-moz-column-fill: auto;
border: 2px solid orange;
margin-bottom: 15px; /* (just for spacing between testcases) */
}
.flexContainer {
background: teal;
border: 1px dashed black;
}
.item {
display: block;
width: 100%;
height: 20px;
}
</style>
</head>
<body>
<!-- auto-height container: -->
<div class="multicol">
<div class="flexContainer">
<img src="" class="item">
</div>
</div>
<!-- fixed-height container, smaller than available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px">
<img src="" class="item">
</div>
</div>
<!-- fixed-height container, between available height and child height: -->
<div class="multicol">
<div class="flexContainer" style="height: 15px">
<img src="" class="item">
</div>
</div>
<!-- fixed-height container, same as child height: -->
<div class="multicol">
<div class="flexContainer" style="height: 20px">
<img src="" class="item">
</div>
</div>
<!-- fixed-height container, larger than child height: -->
<div class="multicol">
<div class="flexContainer" style="height: 24px">
<img src="" class="item">
</div>
</div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,66 @@
<!DOCTYPE html>
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
<!-- Testcase for how we fragment a flex container with a single unbreakable
child, with the flex container having "flex-direction: row".
-->
<html>
<head>
<style>
.multicol {
height: 10px;
width: 100px;
-moz-column-width: 20px;
-moz-column-fill: auto;
border: 2px solid orange;
margin-bottom: 15px; /* (just for spacing between testcases) */
}
.flexContainer {
display: flex;
flex-direction: row;
background: teal;
border: 1px dashed black;
}
.item {
width: 100%;
height: 20px;
}
</style>
</head>
<body>
<!-- auto-height container: -->
<div class="multicol">
<div class="flexContainer">
<img src="" class="item">
</div>
</div>
<!-- fixed-height container, smaller than available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px">
<img src="" class="item">
</div>
</div>
<!-- fixed-height container, between available height and child height: -->
<div class="multicol">
<div class="flexContainer" style="height: 15px">
<img src="" class="item">
</div>
</div>
<!-- fixed-height container, same as child height: -->
<div class="multicol">
<div class="flexContainer" style="height: 20px">
<img src="" class="item">
</div>
</div>
<!-- fixed-height container, larger than child height: -->
<div class="multicol">
<div class="flexContainer" style="height: 24px">
<img src="" class="item">
</div>
</div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,66 @@
<!DOCTYPE html>
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
<!-- Testcase for how we fragment a flex container with a single unbreakable
child, with the flex container having "flex-direction: row-reverse".
-->
<html>
<head>
<style>
.multicol {
height: 10px;
width: 100px;
-moz-column-width: 20px;
-moz-column-fill: auto;
border: 2px solid orange;
margin-bottom: 15px; /* (just for spacing between testcases) */
}
.flexContainer {
display: flex;
flex-direction: row-reverse;
background: teal;
border: 1px dashed black;
}
.item {
width: 100%;
height: 20px;
}
</style>
</head>
<body>
<!-- auto-height container: -->
<div class="multicol">
<div class="flexContainer">
<img src="" class="item">
</div>
</div>
<!-- fixed-height container, smaller than available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px">
<img src="" class="item">
</div>
</div>
<!-- fixed-height container, between available height and child height: -->
<div class="multicol">
<div class="flexContainer" style="height: 15px">
<img src="" class="item">
</div>
</div>
<!-- fixed-height container, same as child height: -->
<div class="multicol">
<div class="flexContainer" style="height: 20px">
<img src="" class="item">
</div>
</div>
<!-- fixed-height container, larger than child height: -->
<div class="multicol">
<div class="flexContainer" style="height: 24px">
<img src="" class="item">
</div>
</div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,67 @@
<!DOCTYPE html>
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
<!-- Testcase for how we fragment a flex container with a single unbreakable
child, with the flex container having "flex-direction: column".
-->
<html>
<head>
<style>
.multicol {
height: 10px;
width: 100px;
-moz-column-width: 20px;
-moz-column-fill: auto;
border: 2px solid orange;
margin-bottom: 15px; /* (just for spacing between testcases) */
}
.flexContainer {
display: flex;
flex-direction: column;
background: teal;
border: 1px dashed black;
}
.item {
width: 100%;
height: 20px;
flex: none;
}
</style>
</head>
<body>
<!-- auto-height container: -->
<div class="multicol">
<div class="flexContainer">
<img src="" class="item">
</div>
</div>
<!-- fixed-height container, smaller than available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px">
<img src="" class="item">
</div>
</div>
<!-- fixed-height container, between available height and child height: -->
<div class="multicol">
<div class="flexContainer" style="height: 15px">
<img src="" class="item">
</div>
</div>
<!-- fixed-height container, same as child height: -->
<div class="multicol">
<div class="flexContainer" style="height: 20px">
<img src="" class="item">
</div>
</div>
<!-- fixed-height container, larger than child height: -->
<div class="multicol">
<div class="flexContainer" style="height: 24px">
<img src="" class="item">
</div>
</div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,68 @@
<!DOCTYPE html>
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
<!-- Testcase for how we fragment a flex container with a single unbreakable
child, with the flex container having "flex-direction: column-reverse".
-->
<html>
<head>
<style>
.multicol {
height: 10px;
width: 100px;
-moz-column-width: 20px;
-moz-column-fill: auto;
border: 2px solid orange;
margin-bottom: 15px; /* (just for spacing between testcases) */
}
.flexContainer {
display: flex;
flex-direction: column-reverse;
justify-content: flex-end;
background: teal;
border: 1px dashed black;
}
.item {
width: 100%;
height: 20px;
flex: none;
}
</style>
</head>
<body>
<!-- auto-height container: -->
<div class="multicol">
<div class="flexContainer">
<img src="" class="item">
</div>
</div>
<!-- fixed-height container, smaller than available height: -->
<div class="multicol">
<div class="flexContainer" style="height: 8px">
<img src="" class="item">
</div>
</div>
<!-- fixed-height container, between available height and child height: -->
<div class="multicol">
<div class="flexContainer" style="height: 15px">
<img src="" class="item">
</div>
</div>
<!-- fixed-height container, same as child height: -->
<div class="multicol">
<div class="flexContainer" style="height: 20px">
<img src="" class="item">
</div>
</div>
<!-- fixed-height container, larger than child height: -->
<div class="multicol">
<div class="flexContainer" style="height: 24px">
<img src="" class="item">
</div>
</div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,25 @@
# Tests with an empty flex container being fragmented:
== flexbox-empty-1a.html flexbox-empty-1-ref.html
== flexbox-empty-1b.html flexbox-empty-1-ref.html
== flexbox-empty-1c.html flexbox-empty-1-ref.html
== flexbox-empty-1d.html flexbox-empty-1-ref.html
# Tests with an empty flex container that overflows a short fixed-height block
# being fragmented:
== flexbox-empty-1e.html flexbox-empty-1-ref.html
== flexbox-empty-1f.html flexbox-empty-1-ref.html
== flexbox-empty-1g.html flexbox-empty-1-ref.html
== flexbox-empty-1h.html flexbox-empty-1-ref.html
# Tests with an empty flex container being fragmented, with margin, border,
# and/or padding being taller than the available height:
== flexbox-empty-2a.html flexbox-empty-2-ref.html
== flexbox-empty-2b.html flexbox-empty-2-ref.html
== flexbox-empty-2c.html flexbox-empty-2-ref.html
== flexbox-empty-2d.html flexbox-empty-2-ref.html
# Tests for how we fragment a flex container with one unbreakable child
== flexbox-unbreakable-child-1a.html flexbox-unbreakable-child-1-ref.html
== flexbox-unbreakable-child-1b.html flexbox-unbreakable-child-1-ref.html
== flexbox-unbreakable-child-1c.html flexbox-unbreakable-child-1-ref.html
== flexbox-unbreakable-child-1d.html flexbox-unbreakable-child-1-ref.html

Просмотреть файл

@ -9,6 +9,9 @@
# tests over to the w3c-css directory, so that they can become part of the
# W3C's test suite.
# SUBDIRECTORY: Reftests for paginated flex containers
include pagination/reftest.list
# Tests for cross-axis alignment (align-self / align-items properties)
fails == flexbox-align-self-baseline-horiz-2.xhtml flexbox-align-self-baseline-horiz-2-ref.xhtml # bug 793456, and possibly others
# This one fails on windows R (but not Ru, strangely). On Windows R, the

Просмотреть файл

@ -14,18 +14,18 @@ if CONFIG['MOZ_REPLACE_MALLOC']:
'malloc_decls.h',
'replace_malloc.h',
]
UNIFIED_SOURCES += [
SOURCES += [
'jemalloc_config.c',
'mozmemory_wrap.c',
]
if CONFIG['MOZ_JEMALLOC3']:
UNIFIED_SOURCES += [
SOURCES += [
'mozjemalloc_compat.c',
]
if CONFIG['MOZ_REPLACE_MALLOC']:
UNIFIED_SOURCES += [
SOURCES += [
'replace_malloc.c',
]

Просмотреть файл

@ -4,14 +4,8 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
# These cannot be built unified because they both define static arena_purge
# functions with different types.
SOURCES += [
'src/src/arena.c',
'src/src/ctl.c',
]
UNIFIED_SOURCES += [
'src/src/atomic.c',
'src/src/base.c',
'src/src/bitmap.c',
@ -19,6 +13,7 @@ UNIFIED_SOURCES += [
'src/src/chunk_dss.c',
'src/src/chunk_mmap.c',
'src/src/ckh.c',
'src/src/ctl.c',
'src/src/extent.c',
'src/src/hash.c',
'src/src/huge.c',
@ -37,7 +32,7 @@ UNIFIED_SOURCES += [
# Only OSX needs the zone allocation implementation,
# but only if replace-malloc is not enabled.
if CONFIG['OS_TARGET'] == 'Darwin' and not CONFIG['MOZ_REPLACE_MALLOC']:
UNIFIED_SOURCES += [
SOURCES += [
'src/src/zone.c',
]

Просмотреть файл

@ -32,7 +32,7 @@ if CONFIG['WRAP_STL_INCLUDES']:
'msvc_throw_wrapper.cpp',
]
UNIFIED_SOURCES += [
SOURCES += [
'mozalloc.cpp',
'mozalloc_abort.cpp',
'mozalloc_oom.cpp',

Просмотреть файл

@ -10,10 +10,10 @@ import org.mozilla.gecko.gfx.BitmapUtils;
import org.mozilla.gecko.gfx.GeckoLayerClient;
import org.mozilla.gecko.gfx.LayerView;
import org.mozilla.gecko.gfx.PanZoomController;
import org.mozilla.gecko.mozglue.generatorannotations.OptionalGeneratedParameter;
import org.mozilla.gecko.mozglue.generatorannotations.WrapElementForJNI;
import org.mozilla.gecko.prompts.PromptService;
import org.mozilla.gecko.mozglue.GeckoLoader;
import org.mozilla.gecko.mozglue.GeneratableAndroidBridgeTarget;
import org.mozilla.gecko.mozglue.OptionalGeneratedParameter;
import org.mozilla.gecko.util.EventDispatcher;
import org.mozilla.gecko.util.GeckoEventListener;
import org.mozilla.gecko.util.HardwareUtils;
@ -402,14 +402,14 @@ public class GeckoAppShell
/*
* The Gecko-side API: API methods that Gecko calls
*/
@GeneratableAndroidBridgeTarget(generateStatic = true)
@WrapElementForJNI(generateStatic = true)
public static void notifyIME(int type) {
if (mEditableListener != null) {
mEditableListener.notifyIME(type);
}
}
@GeneratableAndroidBridgeTarget(generateStatic = true)
@WrapElementForJNI(generateStatic = true)
public static void notifyIMEContext(int state, String typeHint,
String modeHint, String actionHint) {
if (mEditableListener != null) {
@ -418,7 +418,7 @@ public class GeckoAppShell
}
}
@GeneratableAndroidBridgeTarget(generateStatic = true)
@WrapElementForJNI(generateStatic = true)
public static void notifyIMEChange(String text, int start, int end, int newEnd) {
if (newEnd < 0) { // Selection change
mEditableListener.onSelectionChange(start, end);
@ -462,7 +462,7 @@ public class GeckoAppShell
}
// Signal the Java thread that it's time to wake up
@GeneratableAndroidBridgeTarget
@WrapElementForJNI
public static void acknowledgeEvent() {
synchronized (sEventAckLock) {
sWaitingForEventAck = false;
@ -501,7 +501,7 @@ public class GeckoAppShell
return lastKnownLocation;
}
@GeneratableAndroidBridgeTarget
@WrapElementForJNI
public static void enableLocation(final boolean enable) {
ThreadUtils.postToUiThread(new Runnable() {
@Override
@ -557,12 +557,12 @@ public class GeckoAppShell
}
}
@GeneratableAndroidBridgeTarget
@WrapElementForJNI
public static void enableLocationHighAccuracy(final boolean enable) {
mLocationHighAccuracy = enable;
}
@GeneratableAndroidBridgeTarget
@WrapElementForJNI
public static void enableSensor(int aSensortype) {
GeckoInterface gi = getGeckoInterface();
if (gi == null)
@ -617,7 +617,7 @@ public class GeckoAppShell
}
}
@GeneratableAndroidBridgeTarget
@WrapElementForJNI
public static void disableSensor(int aSensortype) {
GeckoInterface gi = getGeckoInterface();
if (gi == null)
@ -661,7 +661,7 @@ public class GeckoAppShell
}
}
@GeneratableAndroidBridgeTarget
@WrapElementForJNI
public static void moveTaskToBack() {
if (getGeckoInterface() != null)
getGeckoInterface().getActivity().moveTaskToBack(true);
@ -672,7 +672,7 @@ public class GeckoAppShell
// Native Fennec doesn't care because the Java code already knows the selection indexes.
}
@GeneratableAndroidBridgeTarget(stubName = "NotifyXreExit")
@WrapElementForJNI(stubName = "NotifyXreExit")
static void onXreExit() {
// The launch state can only be Launched or GeckoRunning at this point
GeckoThread.setLaunchState(GeckoThread.LaunchState.GeckoExiting);
@ -688,7 +688,7 @@ public class GeckoAppShell
System.exit(0);
}
@GeneratableAndroidBridgeTarget
@WrapElementForJNI
static void scheduleRestart() {
gRestartScheduled = true;
}
@ -731,7 +731,7 @@ public class GeckoAppShell
// "Installs" an application by creating a shortcut
// This is the entry point from AndroidBridge.h
@GeneratableAndroidBridgeTarget
@WrapElementForJNI
static void createShortcut(String aTitle, String aURI, String aIconData, String aType) {
if ("webapp".equals(aType)) {
Log.w(LOGTAG, "createShortcut with no unique URI should not be used for aType = webapp!");
@ -926,7 +926,7 @@ public class GeckoAppShell
return bitmap;
}
@GeneratableAndroidBridgeTarget(stubName = "GetHandlersForMimeTypeWrapper")
@WrapElementForJNI(stubName = "GetHandlersForMimeTypeWrapper")
static String[] getHandlersForMimeType(String aMimeType, String aAction) {
Intent intent = getIntentForActionString(aAction);
if (aMimeType != null && aMimeType.length() > 0)
@ -934,7 +934,7 @@ public class GeckoAppShell
return getHandlersForIntent(intent);
}
@GeneratableAndroidBridgeTarget(stubName = "GetHandlersForURLWrapper")
@WrapElementForJNI(stubName = "GetHandlersForURLWrapper")
static String[] getHandlersForURL(String aURL, String aAction) {
// aURL may contain the whole URL or just the protocol
Uri uri = aURL.indexOf(':') >= 0 ? Uri.parse(aURL) : new Uri.Builder().scheme(aURL).build();
@ -977,12 +977,12 @@ public class GeckoAppShell
return new Intent(aAction);
}
@GeneratableAndroidBridgeTarget(stubName = "GetExtensionFromMimeTypeWrapper")
@WrapElementForJNI(stubName = "GetExtensionFromMimeTypeWrapper")
static String getExtensionFromMimeType(String aMimeType) {
return MimeTypeMap.getSingleton().getExtensionFromMimeType(aMimeType);
}
@GeneratableAndroidBridgeTarget(stubName = "GetMimeTypeFromExtensionsWrapper")
@WrapElementForJNI(stubName = "GetMimeTypeFromExtensionsWrapper")
static String getMimeTypeFromExtensions(String aFileExt) {
StringTokenizer st = new StringTokenizer(aFileExt, ".,; ");
String type = null;
@ -1115,7 +1115,7 @@ public class GeckoAppShell
* @param title the title to use in <code>ACTION_SEND</code> intents.
* @return true if the activity started successfully; false otherwise.
*/
@GeneratableAndroidBridgeTarget
@WrapElementForJNI
public static boolean openUriExternal(String targetURI,
String mimeType,
@OptionalGeneratedParameter String packageName,
@ -1301,7 +1301,7 @@ public class GeckoAppShell
}
}
@GeneratableAndroidBridgeTarget(stubName = "ShowAlertNotificationWrapper")
@WrapElementForJNI(stubName = "ShowAlertNotificationWrapper")
public static void showAlertNotification(String aImageUrl, String aAlertTitle, String aAlertText,
String aAlertCookie, String aAlertName) {
// The intent to launch when the user clicks the expanded notification
@ -1328,13 +1328,13 @@ public class GeckoAppShell
sNotificationClient.add(notificationID, aImageUrl, aAlertTitle, aAlertText, contentIntent);
}
@GeneratableAndroidBridgeTarget
@WrapElementForJNI
public static void alertsProgressListener_OnProgress(String aAlertName, long aProgress, long aProgressMax, String aAlertText) {
int notificationID = aAlertName.hashCode();
sNotificationClient.update(notificationID, aProgress, aProgressMax, aAlertText);
}
@GeneratableAndroidBridgeTarget
@WrapElementForJNI
public static void closeNotification(String aAlertName) {
String alertCookie = mAlertCookies.get(aAlertName);
if (alertCookie != null) {
@ -1362,7 +1362,7 @@ public class GeckoAppShell
closeNotification(aAlertName);
}
@GeneratableAndroidBridgeTarget(stubName = "GetDpiWrapper")
@WrapElementForJNI(stubName = "GetDpiWrapper")
public static int getDpi() {
if (sDensityDpi == 0) {
sDensityDpi = getContext().getResources().getDisplayMetrics().densityDpi;
@ -1371,7 +1371,7 @@ public class GeckoAppShell
return sDensityDpi;
}
@GeneratableAndroidBridgeTarget()
@WrapElementForJNI
public static float getDensity() {
return getContext().getResources().getDisplayMetrics().density;
}
@ -1406,7 +1406,7 @@ public class GeckoAppShell
* Returns the colour depth of the default screen. This will either be
* 24 or 16.
*/
@GeneratableAndroidBridgeTarget(stubName = "GetScreenDepthWrapper")
@WrapElementForJNI(stubName = "GetScreenDepthWrapper")
public static synchronized int getScreenDepth() {
if (sScreenDepth == 0) {
sScreenDepth = 16;
@ -1429,27 +1429,27 @@ public class GeckoAppShell
sScreenDepth = aScreenDepth;
}
@GeneratableAndroidBridgeTarget
@WrapElementForJNI
public static void setFullScreen(boolean fullscreen) {
if (getGeckoInterface() != null)
getGeckoInterface().setFullScreen(fullscreen);
}
@GeneratableAndroidBridgeTarget(stubName = "ShowFilePickerForExtensionsWrapper")
@WrapElementForJNI(stubName = "ShowFilePickerForExtensionsWrapper")
public static String showFilePickerForExtensions(String aExtensions) {
if (getGeckoInterface() != null)
return sActivityHelper.showFilePicker(getGeckoInterface().getActivity(), getMimeTypeFromExtensions(aExtensions));
return "";
}
@GeneratableAndroidBridgeTarget(stubName = "ShowFilePickerForMimeTypeWrapper")
@WrapElementForJNI(stubName = "ShowFilePickerForMimeTypeWrapper")
public static String showFilePickerForMimeType(String aMimeType) {
if (getGeckoInterface() != null)
return sActivityHelper.showFilePicker(getGeckoInterface().getActivity(), aMimeType);
return "";
}
@GeneratableAndroidBridgeTarget
@WrapElementForJNI
public static void performHapticFeedback(boolean aIsLongPress) {
// Don't perform haptic feedback if a vibration is currently playing,
// because the haptic feedback will nuke the vibration.
@ -1466,14 +1466,14 @@ public class GeckoAppShell
return (Vibrator) layerView.getContext().getSystemService(Context.VIBRATOR_SERVICE);
}
@GeneratableAndroidBridgeTarget(stubName = "Vibrate1")
@WrapElementForJNI(stubName = "Vibrate1")
public static void vibrate(long milliseconds) {
sVibrationEndTime = System.nanoTime() + milliseconds * 1000000;
sVibrationMaybePlaying = true;
vibrator().vibrate(milliseconds);
}
@GeneratableAndroidBridgeTarget(stubName = "VibrateA")
@WrapElementForJNI(stubName = "VibrateA")
public static void vibrate(long[] pattern, int repeat) {
// If pattern.length is even, the last element in the pattern is a
// meaningless delay, so don't include it in vibrationDuration.
@ -1488,21 +1488,21 @@ public class GeckoAppShell
vibrator().vibrate(pattern, repeat);
}
@GeneratableAndroidBridgeTarget
@WrapElementForJNI
public static void cancelVibrate() {
sVibrationMaybePlaying = false;
sVibrationEndTime = 0;
vibrator().cancel();
}
@GeneratableAndroidBridgeTarget
@WrapElementForJNI
public static void showInputMethodPicker() {
InputMethodManager imm = (InputMethodManager)
getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.showInputMethodPicker();
}
@GeneratableAndroidBridgeTarget
@WrapElementForJNI
public static void setKeepScreenOn(final boolean on) {
ThreadUtils.postToUiThread(new Runnable() {
@Override
@ -1512,7 +1512,7 @@ public class GeckoAppShell
});
}
@GeneratableAndroidBridgeTarget
@WrapElementForJNI
public static void notifyDefaultPrevented(final boolean defaultPrevented) {
ThreadUtils.postToUiThread(new Runnable() {
@Override
@ -1526,7 +1526,7 @@ public class GeckoAppShell
});
}
@GeneratableAndroidBridgeTarget
@WrapElementForJNI
public static boolean isNetworkLinkUp() {
ConnectivityManager cm = (ConnectivityManager)
getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
@ -1536,7 +1536,7 @@ public class GeckoAppShell
return true;
}
@GeneratableAndroidBridgeTarget
@WrapElementForJNI
public static boolean isNetworkLinkKnown() {
ConnectivityManager cm = (ConnectivityManager)
getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
@ -1545,7 +1545,7 @@ public class GeckoAppShell
return true;
}
@GeneratableAndroidBridgeTarget
@WrapElementForJNI
public static int networkLinkType() {
ConnectivityManager cm = (ConnectivityManager)
getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
@ -1604,7 +1604,7 @@ public class GeckoAppShell
}
}
@GeneratableAndroidBridgeTarget
@WrapElementForJNI
public static void setSelectedLocale(String localeCode) {
/* 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.
@ -1643,7 +1643,7 @@ public class GeckoAppShell
}
@GeneratableAndroidBridgeTarget(stubName = "GetSystemColoursWrapper")
@WrapElementForJNI(stubName = "GetSystemColoursWrapper")
public static int[] getSystemColors() {
// attrsAppearance[] must correspond to AndroidSystemColors structure in android/AndroidBridge.h
final int[] attrsAppearance = {
@ -1680,7 +1680,7 @@ public class GeckoAppShell
return result;
}
@GeneratableAndroidBridgeTarget
@WrapElementForJNI
public static void killAnyZombies() {
GeckoProcessesVisitor visitor = new GeckoProcessesVisitor() {
@Override
@ -1836,7 +1836,7 @@ public class GeckoAppShell
} catch (Exception e) { }
}
@GeneratableAndroidBridgeTarget
@WrapElementForJNI
public static void scanMedia(String aFile, String aMimeType) {
// If the platform didn't give us a mimetype, try to guess one from the filename
if (TextUtils.isEmpty(aMimeType)) {
@ -1850,7 +1850,7 @@ public class GeckoAppShell
GeckoMediaScannerClient.startScan(context, aFile, aMimeType);
}
@GeneratableAndroidBridgeTarget(stubName = "GetIconForExtensionWrapper")
@WrapElementForJNI(stubName = "GetIconForExtensionWrapper")
public static byte[] getIconForExtension(String aExt, int iconSize) {
try {
if (iconSize <= 0)
@ -1908,7 +1908,7 @@ public class GeckoAppShell
return activityInfo.loadIcon(pm);
}
@GeneratableAndroidBridgeTarget
@WrapElementForJNI
public static boolean getShowPasswordSetting() {
try {
int showPassword =
@ -1921,7 +1921,7 @@ public class GeckoAppShell
}
}
@GeneratableAndroidBridgeTarget(stubName = "AddPluginViewWrapper")
@WrapElementForJNI(stubName = "AddPluginViewWrapper")
public static void addPluginView(View view,
float x, float y,
float w, float h,
@ -1930,7 +1930,7 @@ public class GeckoAppShell
getGeckoInterface().addPluginView(view, new RectF(x, y, x + w, y + h), isFullScreen);
}
@GeneratableAndroidBridgeTarget
@WrapElementForJNI
public static void removePluginView(View view, boolean isFullScreen) {
if (getGeckoInterface() != null)
getGeckoInterface().removePluginView(view, isFullScreen);
@ -2154,7 +2154,7 @@ public class GeckoAppShell
private static ContextGetter sContextGetter;
@GeneratableAndroidBridgeTarget(allowMultithread = true)
@WrapElementForJNI(allowMultithread = true)
public static Context getContext() {
return sContextGetter.getContext();
}
@ -2212,7 +2212,7 @@ public class GeckoAppShell
static byte[] sCameraBuffer = null;
@GeneratableAndroidBridgeTarget(stubName = "InitCameraWrapper")
@WrapElementForJNI(stubName = "InitCameraWrapper")
static int[] initCamera(String aContentType, int aCamera, int aWidth, int aHeight) {
ThreadUtils.postToUiThread(new Runnable() {
@Override
@ -2313,7 +2313,7 @@ public class GeckoAppShell
return result;
}
@GeneratableAndroidBridgeTarget
@WrapElementForJNI
static synchronized void closeCamera() {
ThreadUtils.postToUiThread(new Runnable() {
@Override
@ -2365,32 +2365,32 @@ public class GeckoAppShell
/*
* Battery API related methods.
*/
@GeneratableAndroidBridgeTarget
@WrapElementForJNI
public static void enableBatteryNotifications() {
GeckoBatteryManager.enableNotifications();
}
@GeneratableAndroidBridgeTarget(stubName = "HandleGeckoMessageWrapper")
@WrapElementForJNI(stubName = "HandleGeckoMessageWrapper")
public static String handleGeckoMessage(String message) {
return sEventDispatcher.dispatchEvent(message);
}
@GeneratableAndroidBridgeTarget
@WrapElementForJNI
public static void disableBatteryNotifications() {
GeckoBatteryManager.disableNotifications();
}
@GeneratableAndroidBridgeTarget(stubName = "GetCurrentBatteryInformationWrapper")
@WrapElementForJNI(stubName = "GetCurrentBatteryInformationWrapper")
public static double[] getCurrentBatteryInformation() {
return GeckoBatteryManager.getCurrentInformation();
}
@GeneratableAndroidBridgeTarget(stubName = "CheckURIVisited")
@WrapElementForJNI(stubName = "CheckURIVisited")
static void checkUriVisited(String uri) {
GlobalHistory.getInstance().checkUriVisited(uri);
}
@GeneratableAndroidBridgeTarget(stubName = "MarkURIVisited")
@WrapElementForJNI(stubName = "MarkURIVisited")
static void markUriVisited(final String uri) {
ThreadUtils.postToBackgroundThread(new Runnable() {
@Override
@ -2400,7 +2400,7 @@ public class GeckoAppShell
});
}
@GeneratableAndroidBridgeTarget(stubName = "SetURITitle")
@WrapElementForJNI(stubName = "SetURITitle")
static void setUriTitle(final String uri, final String title) {
ThreadUtils.postToBackgroundThread(new Runnable() {
@Override
@ -2410,7 +2410,7 @@ public class GeckoAppShell
});
}
@GeneratableAndroidBridgeTarget
@WrapElementForJNI
static void hideProgressDialog() {
// unused stub
}
@ -2418,7 +2418,7 @@ public class GeckoAppShell
/*
* WebSMS related methods.
*/
@GeneratableAndroidBridgeTarget(stubName = "SendMessageWrapper")
@WrapElementForJNI(stubName = "SendMessageWrapper")
public static void sendMessage(String aNumber, String aMessage, int aRequestId) {
if (SmsManager.getInstance() == null) {
return;
@ -2427,7 +2427,7 @@ public class GeckoAppShell
SmsManager.getInstance().send(aNumber, aMessage, aRequestId);
}
@GeneratableAndroidBridgeTarget(stubName = "GetMessageWrapper")
@WrapElementForJNI(stubName = "GetMessageWrapper")
public static void getMessage(int aMessageId, int aRequestId) {
if (SmsManager.getInstance() == null) {
return;
@ -2436,7 +2436,7 @@ public class GeckoAppShell
SmsManager.getInstance().getMessage(aMessageId, aRequestId);
}
@GeneratableAndroidBridgeTarget(stubName = "DeleteMessageWrapper")
@WrapElementForJNI(stubName = "DeleteMessageWrapper")
public static void deleteMessage(int aMessageId, int aRequestId) {
if (SmsManager.getInstance() == null) {
return;
@ -2445,7 +2445,7 @@ public class GeckoAppShell
SmsManager.getInstance().deleteMessage(aMessageId, aRequestId);
}
@GeneratableAndroidBridgeTarget(stubName = "CreateMessageListWrapper")
@WrapElementForJNI(stubName = "CreateMessageListWrapper")
public static void createMessageList(long aStartDate, long aEndDate, String[] aNumbers, int aNumbersCount, int aDeliveryState, boolean aReverse, int aRequestId) {
if (SmsManager.getInstance() == null) {
return;
@ -2454,7 +2454,7 @@ public class GeckoAppShell
SmsManager.getInstance().createMessageList(aStartDate, aEndDate, aNumbers, aNumbersCount, aDeliveryState, aReverse, aRequestId);
}
@GeneratableAndroidBridgeTarget(stubName = "GetNextMessageInListWrapper")
@WrapElementForJNI(stubName = "GetNextMessageInListWrapper")
public static void getNextMessageInList(int aListId, int aRequestId) {
if (SmsManager.getInstance() == null) {
return;
@ -2463,7 +2463,7 @@ public class GeckoAppShell
SmsManager.getInstance().getNextMessageInList(aListId, aRequestId);
}
@GeneratableAndroidBridgeTarget
@WrapElementForJNI
public static void clearMessageList(int aListId) {
if (SmsManager.getInstance() == null) {
return;
@ -2473,7 +2473,7 @@ public class GeckoAppShell
}
/* Called by JNI from AndroidBridge, and by reflection from tests/BaseTest.java.in */
@GeneratableAndroidBridgeTarget
@WrapElementForJNI
public static boolean isTablet() {
return HardwareUtils.isTablet();
}
@ -2486,17 +2486,17 @@ public class GeckoAppShell
}
}
@GeneratableAndroidBridgeTarget(stubName = "GetCurrentNetworkInformationWrapper")
@WrapElementForJNI(stubName = "GetCurrentNetworkInformationWrapper")
public static double[] getCurrentNetworkInformation() {
return GeckoNetworkManager.getInstance().getCurrentInformation();
}
@GeneratableAndroidBridgeTarget
@WrapElementForJNI
public static void enableNetworkNotifications() {
GeckoNetworkManager.getInstance().enableNotifications();
}
@GeneratableAndroidBridgeTarget
@WrapElementForJNI
public static void disableNetworkNotifications() {
GeckoNetworkManager.getInstance().disableNotifications();
}
@ -2610,32 +2610,32 @@ public class GeckoAppShell
return decodeBase64(s.getBytes(), flags);
}
@GeneratableAndroidBridgeTarget(stubName = "GetScreenOrientationWrapper")
@WrapElementForJNI(stubName = "GetScreenOrientationWrapper")
public static short getScreenOrientation() {
return GeckoScreenOrientationListener.getInstance().getScreenOrientation();
}
@GeneratableAndroidBridgeTarget
@WrapElementForJNI
public static void enableScreenOrientationNotifications() {
GeckoScreenOrientationListener.getInstance().enableNotifications();
}
@GeneratableAndroidBridgeTarget
@WrapElementForJNI
public static void disableScreenOrientationNotifications() {
GeckoScreenOrientationListener.getInstance().disableNotifications();
}
@GeneratableAndroidBridgeTarget
@WrapElementForJNI
public static void lockScreenOrientation(int aOrientation) {
GeckoScreenOrientationListener.getInstance().lockScreenOrientation(aOrientation);
}
@GeneratableAndroidBridgeTarget
@WrapElementForJNI
public static void unlockScreenOrientation() {
GeckoScreenOrientationListener.getInstance().unlockScreenOrientation();
}
@GeneratableAndroidBridgeTarget
@WrapElementForJNI
public static boolean pumpMessageLoop() {
Handler geckoHandler = ThreadUtils.sGeckoHandler;
Message msg = getNextMessageFromQueue(ThreadUtils.sGeckoQueue);
@ -2657,7 +2657,7 @@ public class GeckoAppShell
static native void notifyFilePickerResult(String filePath, long id);
@GeneratableAndroidBridgeTarget(stubName = "ShowFilePickerAsyncWrapper")
@WrapElementForJNI(stubName = "ShowFilePickerAsyncWrapper")
public static void showFilePickerAsync(String aMimeType, final long id) {
sActivityHelper.showFilePickerAsync(getGeckoInterface().getActivity(), aMimeType, new ActivityHandlerHelper.FileResultHandler() {
public void gotFile(String filename) {
@ -2666,13 +2666,13 @@ public class GeckoAppShell
});
}
@GeneratableAndroidBridgeTarget
@WrapElementForJNI
public static void notifyWakeLockChanged(String topic, String state) {
if (getGeckoInterface() != null)
getGeckoInterface().notifyWakeLockChanged(topic, state);
}
@GeneratableAndroidBridgeTarget
@WrapElementForJNI
public static void registerSurfaceTextureFrameListener(Object surfaceTexture, final int id) {
((SurfaceTexture)surfaceTexture).setOnFrameAvailableListener(new SurfaceTexture.OnFrameAvailableListener() {
@Override
@ -2682,12 +2682,12 @@ public class GeckoAppShell
});
}
@GeneratableAndroidBridgeTarget(allowMultithread = true)
@WrapElementForJNI(allowMultithread = true)
public static void unregisterSurfaceTextureFrameListener(Object surfaceTexture) {
((SurfaceTexture)surfaceTexture).setOnFrameAvailableListener(null);
}
@GeneratableAndroidBridgeTarget
@WrapElementForJNI
public static boolean unlockProfile() {
// Try to kill any zombie Fennec's that might be running
GeckoAppShell.killAnyZombies();
@ -2701,7 +2701,7 @@ public class GeckoAppShell
return false;
}
@GeneratableAndroidBridgeTarget(stubName = "GetProxyForURIWrapper")
@WrapElementForJNI(stubName = "GetProxyForURIWrapper")
public static String getProxyForURI(String spec, String scheme, String host, int port) {
URI uri = null;
try {

Просмотреть файл

@ -7,6 +7,8 @@ package org.mozilla.gecko;
import org.mozilla.gecko.gfx.DisplayPortMetrics;
import org.mozilla.gecko.gfx.ImmutableViewportMetrics;
import org.mozilla.gecko.mozglue.generatorannotations.GeneratorOptions;
import org.mozilla.gecko.mozglue.generatorannotations.WrapEntireClassForJNI;
import android.content.res.Resources;
import android.graphics.Point;
@ -83,6 +85,8 @@ public class GeckoEvent {
* The DomKeyLocation enum encapsulates the DOM KeyboardEvent's constants.
* @see https://developer.mozilla.org/en-US/docs/DOM/KeyboardEvent#Key_location_constants
*/
@GeneratorOptions(generatedClassName = "JavaDomKeyLocation")
@WrapEntireClassForJNI
public enum DomKeyLocation {
DOM_KEY_LOCATION_STANDARD(0),
DOM_KEY_LOCATION_LEFT(1),

Просмотреть файл

@ -8,7 +8,7 @@ package org.mozilla.gecko;
import android.os.SystemClock;
import android.util.Log;
import org.mozilla.gecko.mozglue.GeneratableAndroidBridgeTarget;
import org.mozilla.gecko.mozglue.generatorannotations.WrapElementForJNI;
import java.lang.Thread;
import java.util.HashMap;
@ -126,7 +126,7 @@ public class GeckoJavaSampler {
}
@GeneratableAndroidBridgeTarget(allowMultithread = true, stubName = "GetThreadNameJavaProfilingWrapper")
@WrapElementForJNI(allowMultithread = true, stubName = "GetThreadNameJavaProfilingWrapper")
public synchronized static String getThreadName(int aThreadId) {
if (aThreadId == 0 && sMainThread != null) {
return sMainThread.getName();
@ -138,7 +138,7 @@ public class GeckoJavaSampler {
return sSamplingRunnable.getSample(aThreadId, aSampleId);
}
@GeneratableAndroidBridgeTarget(allowMultithread = true, stubName = "GetSampleTimeJavaProfiling")
@WrapElementForJNI(allowMultithread = true, stubName = "GetSampleTimeJavaProfiling")
public synchronized static double getSampleTime(int aThreadId, int aSampleId) {
Sample sample = getSample(aThreadId, aSampleId);
if (sample != null) {
@ -152,7 +152,7 @@ public class GeckoJavaSampler {
return 0;
}
@GeneratableAndroidBridgeTarget(allowMultithread = true, stubName = "GetFrameNameJavaProfilingWrapper")
@WrapElementForJNI(allowMultithread = true, stubName = "GetFrameNameJavaProfilingWrapper")
public synchronized static String getFrameName(int aThreadId, int aSampleId, int aFrameId) {
Sample sample = getSample(aThreadId, aSampleId);
if (sample != null && aFrameId < sample.mFrames.length) {
@ -165,7 +165,7 @@ public class GeckoJavaSampler {
return null;
}
@GeneratableAndroidBridgeTarget(allowMultithread = true, stubName = "StartJavaProfiling")
@WrapElementForJNI(allowMultithread = true, stubName = "StartJavaProfiling")
public static void start(int aInterval, int aSamples) {
synchronized (GeckoJavaSampler.class) {
if (sSamplingRunnable != null) {
@ -177,21 +177,21 @@ public class GeckoJavaSampler {
}
}
@GeneratableAndroidBridgeTarget(allowMultithread = true, stubName = "PauseJavaProfiling")
@WrapElementForJNI(allowMultithread = true, stubName = "PauseJavaProfiling")
public static void pause() {
synchronized (GeckoJavaSampler.class) {
sSamplingRunnable.mPauseSampler = true;
}
}
@GeneratableAndroidBridgeTarget(allowMultithread = true, stubName = "UnpauseJavaProfiling")
@WrapElementForJNI(allowMultithread = true, stubName = "UnpauseJavaProfiling")
public static void unpause() {
synchronized (GeckoJavaSampler.class) {
sSamplingRunnable.mPauseSampler = false;
}
}
@GeneratableAndroidBridgeTarget(allowMultithread = true, stubName = "StopJavaProfiling")
@WrapElementForJNI(allowMultithread = true, stubName = "StopJavaProfiling")
public static void stop() {
synchronized (GeckoJavaSampler.class) {
if (sSamplingThread == null) {

Просмотреть файл

@ -151,7 +151,7 @@ ANNOTATION_PROCESSOR_JAR_FILES := $(DEPTH)/build/annotationProcessors/annotation
GeneratedJNIWrappers.cpp: $(ANNOTATION_PROCESSOR_JAR_FILES)
GeneratedJNIWrappers.cpp: $(ALL_JARS)
$(JAVA) -classpath $(JAVA_BOOTCLASSPATH):$(ANNOTATION_PROCESSOR_JAR_FILES) org.mozilla.gecko.annotationProcessors.AnnotationProcessor $(ALL_JARS)
$(JAVA) -classpath gecko-mozglue.jar:$(JAVA_BOOTCLASSPATH):$(ANNOTATION_PROCESSOR_JAR_FILES) org.mozilla.gecko.annotationProcessors.AnnotationProcessor $(ALL_JARS)
gecko_package_dir = generated/org/mozilla/gecko
# Like generated/org/mozilla/fennec_$USERID.

Просмотреть файл

@ -4,8 +4,11 @@
package org.mozilla.gecko;
import org.mozilla.gecko.mozglue.generatorannotations.WrapEntireClassForJNI;
import java.nio.ByteBuffer;
@WrapEntireClassForJNI
public class SurfaceBits {
public int width;
public int height;

Просмотреть файл

@ -9,7 +9,7 @@ import org.mozilla.gecko.db.BrowserDB;
import org.mozilla.gecko.gfx.BitmapUtils;
import org.mozilla.gecko.gfx.IntSize;
import org.mozilla.gecko.mozglue.DirectBufferAllocator;
import org.mozilla.gecko.mozglue.GeneratableAndroidBridgeTarget;
import org.mozilla.gecko.mozglue.generatorannotations.WrapElementForJNI;
import android.graphics.Bitmap;
import android.util.Log;
@ -151,7 +151,7 @@ public final class ThumbnailHelper {
}
/* This method is invoked by JNI once the thumbnail data is ready. */
@GeneratableAndroidBridgeTarget(stubName = "SendThumbnail")
@WrapElementForJNI(stubName = "SendThumbnail")
public static void notifyThumbnail(ByteBuffer data, int tabId, boolean success) {
Tab tab = Tabs.getInstance().getTab(tabId);
ThumbnailHelper helper = ThumbnailHelper.getInstance();

Просмотреть файл

@ -402,10 +402,11 @@ public class LocalBrowserDB implements BrowserDB.BrowserDBIface {
c = cr.query(mBookmarksUriWithProfile,
DEFAULT_BOOKMARK_COLUMNS,
Bookmarks.PARENT + " = ? AND " +
"(" + Bookmarks.TYPE + " = ? OR " + Bookmarks.TYPE + " = ?)",
"(" + Bookmarks.TYPE + " = ? OR " +
"(" + Bookmarks.TYPE + " = ? AND " + Bookmarks.URL + " IS NOT NULL))",
new String[] { String.valueOf(folderId),
String.valueOf(Bookmarks.TYPE_BOOKMARK),
String.valueOf(Bookmarks.TYPE_FOLDER) },
String.valueOf(Bookmarks.TYPE_FOLDER),
String.valueOf(Bookmarks.TYPE_BOOKMARK) },
null);
}

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше