зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-c to b2g-inbound
This commit is contained in:
Коммит
98ca2b2c71
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
11
configure.in
11
configure.in
|
@ -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 ©)
|
||||
ProfiledBlocksFunction(ProfiledBlocksFunction &©)
|
||||
: 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);
|
||||
}
|
||||
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче