Merge "Use WebTextView overlay to render text fields/areas much faster"

This commit is contained in:
Chris Craik
2011-07-27 15:46:44 -07:00
committed by Android (Google) Code Review
4 changed files with 31 additions and 217 deletions

View File

@ -47,7 +47,7 @@ class DebugFlags {
public static final boolean WEB_VIEW_CORE = false;
/*
* Set to true to allow the WebTextView to draw on top of the web page in a
* different color so that you can see how the two line up.
* different color with no background so you can see how the two line up.
*/
public static final boolean DRAW_WEBTEXTVIEW = false;
}

View File

@ -25,7 +25,7 @@ import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
@ -87,7 +87,6 @@ import junit.framework.Assert;
// Keep track of the text before the change so we know whether we actually
// need to send down the DOM events.
private String mPreChange;
private Drawable mBackground;
// Variables for keeping track of the touch down, to send to the WebView
// when a drag starts
private float mDragStartX;
@ -190,6 +189,8 @@ import junit.framework.Assert;
// that other applications that use embedded WebViews will properly
// display the text in password textfields.
setTextColor(DebugFlags.DRAW_WEBTEXTVIEW ? Color.RED : Color.BLACK);
setBackgroundDrawable(DebugFlags.DRAW_WEBTEXTVIEW ? null : new ColorDrawable(Color.WHITE));
// This helps to align the text better with the text in the web page.
setIncludeFontPadding(false);
@ -423,24 +424,6 @@ import junit.framework.Assert;
// makeNewLayout does.
super.makeNewLayout(w, hintWidth, boring, hintBoring, ellipsisWidth,
bringIntoView);
// For fields that do not draw, create a layout which is altered so that
// the text lines up.
if (DebugFlags.DRAW_WEBTEXTVIEW || willNotDraw()) {
float lineHeight = -1;
if (mWebView != null) {
float height = mWebView.nativeFocusCandidateLineHeight();
if (height != -1) {
lineHeight = height * mWebView.getScale();
}
}
CharSequence text = getText();
// Copy from the existing Layout.
mLayout = new WebTextViewLayout(text, text, getPaint(), mLayout.getWidth(),
mLayout.getAlignment(), mLayout.getSpacingMultiplier(),
mLayout.getSpacingAdd(), false, null, ellipsisWidth,
lineHeight);
}
lineUpScroll();
}
@ -491,51 +474,6 @@ import junit.framework.Assert;
return connection;
}
/**
* In general, TextView makes a call to InputMethodManager.updateSelection
* in onDraw. However, in the general case of WebTextView, we do not draw.
* This method is called by WebView.onDraw to take care of the part that
* needs to be called.
*/
/* package */ void onDrawSubstitute() {
if (!willNotDraw()) {
// If the WebTextView is set to draw, such as in the case of a
// password, onDraw calls updateSelection(), so this code path is
// unnecessary.
return;
}
// This code is copied from TextView.onDraw(). That code does not get
// executed, however, because the WebTextView does not draw, allowing
// webkit's drawing to show through.
InputMethodManager imm = InputMethodManager.peekInstance();
if (imm != null && imm.isActive(this)) {
Spannable sp = (Spannable) getText();
int selStart = Selection.getSelectionStart(sp);
int selEnd = Selection.getSelectionEnd(sp);
int candStart = EditableInputConnection.getComposingSpanStart(sp);
int candEnd = EditableInputConnection.getComposingSpanEnd(sp);
imm.updateSelection(this, selStart, selEnd, candStart, candEnd);
}
}
@Override
protected void onDraw(Canvas canvas) {
// onDraw should only be called for password fields. If WebTextView is
// still drawing, but is no longer corresponding to a password field,
// remove it.
if (!DebugFlags.DRAW_WEBTEXTVIEW && (mWebView == null
|| !mWebView.nativeFocusCandidateIsPassword()
|| !isSameTextField(mWebView.nativeFocusCandidatePointer()))) {
// Although calling remove() would seem to make more sense here,
// changing it to not be a password field will make it not draw.
// Other code will make sure that it is removed completely, but this
// way the user will not see it.
setInPassword(false);
} else {
super.onDraw(canvas);
}
}
@Override
public void onEditorAction(int actionCode) {
switch (actionCode) {
@ -928,102 +866,6 @@ import junit.framework.Assert;
if (mWebView != null) mWebView.incrementTextGeneration();
}
/**
* Determine whether to use the system-wide password disguising method,
* or to use none.
* @param inPassword True if the textfield is a password field.
*/
/* package */ void setInPassword(boolean inPassword) {
if (inPassword) {
setInputType(InputType.TYPE_CLASS_TEXT | EditorInfo.
TYPE_TEXT_VARIATION_WEB_PASSWORD);
createBackground();
}
// For password fields, draw the WebTextView. For others, just show
// webkit's drawing.
if (!DebugFlags.DRAW_WEBTEXTVIEW) {
setWillNotDraw(!inPassword);
}
setBackgroundDrawable(inPassword ? mBackground : null);
}
/**
* Private class used for the background of a password textfield.
*/
private static class OutlineDrawable extends Drawable {
private Paint mBackgroundPaint;
private Paint mOutlinePaint;
private float[] mLines;
public OutlineDrawable() {
mBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mBackgroundPaint.setColor(Color.WHITE);
mOutlinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mOutlinePaint.setColor(Color.BLACK);
mOutlinePaint.setStyle(Paint.Style.STROKE);
mLines = new float[16];
}
@Override
public void setBounds(int left, int top, int right, int bottom) {
super.setBounds(left, top, right, bottom);
bottom--;
right -= 2;
// Top line
mLines[0] = left;
mLines[1] = top + 1;
mLines[2] = right;
mLines[3] = top + 1;
// Right line
mLines[4] = right;
mLines[5] = top;
mLines[6] = right;
mLines[7] = bottom;
// Bottom line
mLines[8] = left;
mLines[9] = bottom;
mLines[10] = right;
mLines[11] = bottom;
// Left line
mLines[12] = left + 1;
mLines[13] = top;
mLines[14] = left + 1;
mLines[15] = bottom;
}
@Override
public void draw(Canvas canvas) {
// Draw the background.
canvas.drawRect(getBounds(), mBackgroundPaint);
// Draw the outline.
canvas.drawLines(mLines, mOutlinePaint);
}
// Always want it to be opaque.
@Override
public int getOpacity() {
return PixelFormat.OPAQUE;
}
// These are needed because they are abstract in Drawable.
@Override
public void setAlpha(int alpha) { }
@Override
public void setColorFilter(ColorFilter cf) { }
}
/**
* Create a background for the WebTextView and set up the paint for drawing
* the text. This way, we can see the password transformation of the
* system, which (optionally) shows the actual text before changing to dots.
* The background is necessary to hide the webkit-drawn text beneath.
*/
private void createBackground() {
if (mBackground != null) {
return;
}
mBackground = new OutlineDrawable();
setGravity(Gravity.CENTER_VERTICAL);
}
@Override
public void setInputType(int type) {
mFromSetInputType = true;
@ -1072,7 +914,8 @@ import junit.framework.Assert;
lp.height = height;
}
if (getParent() == null) {
mWebView.addView(this, lp);
// Insert the view so that it's drawn first (at index 0)
mWebView.addView(this, 0, lp);
} else {
setLayoutParams(lp);
}
@ -1145,7 +988,6 @@ import junit.framework.Assert;
/* package */ void setType(int type) {
if (mWebView == null) return;
boolean single = true;
boolean inPassword = false;
int maxLength = -1;
int inputType = InputType.TYPE_CLASS_TEXT
| InputType.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT;
@ -1167,7 +1009,7 @@ import junit.framework.Assert;
imeOptions |= EditorInfo.IME_ACTION_NONE;
break;
case PASSWORD:
inPassword = true;
inputType |= EditorInfo.TYPE_TEXT_VARIATION_WEB_PASSWORD;
imeOptions |= EditorInfo.IME_ACTION_GO;
break;
case SEARCH:
@ -1219,7 +1061,7 @@ import junit.framework.Assert;
setHorizontallyScrolling(single);
setInputType(inputType);
setImeOptions(imeOptions);
setInPassword(inPassword);
setVisibility(VISIBLE);
AutoCompleteAdapter adapter = null;
setAdapterCustom(adapter);
}

View File

@ -4068,9 +4068,6 @@ public class WebView extends AbsoluteLayout
if (AUTO_REDRAW_HACK && mAutoRedraw) {
invalidate();
}
if (inEditingMode()) {
mWebTextView.onDrawSubstitute();
}
mWebViewCore.signalRepaintDone();
if (mOverScrollGlow != null && mOverScrollGlow.drawEdgeGlows(canvas)) {
@ -4287,18 +4284,18 @@ public class WebView extends AbsoluteLayout
private void onZoomAnimationStart() {
// If it is in password mode, turn it off so it does not draw misplaced.
if (inEditingMode() && nativeFocusCandidateIsPassword()) {
mWebTextView.setInPassword(false);
if (inEditingMode()) {
mWebTextView.setVisibility(INVISIBLE);
}
}
private void onZoomAnimationEnd() {
// adjust the edit text view if needed
if (inEditingMode() && didUpdateWebTextViewDimensions(FULLY_ON_SCREEN)
&& nativeFocusCandidateIsPassword()) {
if (inEditingMode()
&& didUpdateWebTextViewDimensions(FULLY_ON_SCREEN)) {
// If it is a password field, start drawing the WebTextView once
// again.
mWebTextView.setInPassword(true);
mWebTextView.setVisibility(VISIBLE);
}
}
@ -4593,37 +4590,23 @@ public class WebView extends AbsoluteLayout
}
String text = nativeFocusCandidateText();
int nodePointer = nativeFocusCandidatePointer();
if (alreadyThere && mWebTextView.isSameTextField(nodePointer)) {
// It is possible that we have the same textfield, but it has moved,
// i.e. In the case of opening/closing the screen.
// In that case, we need to set the dimensions, but not the other
// aspects.
// If the text has been changed by webkit, update it. However, if
// there has been more UI text input, ignore it. We will receive
// another update when that text is recognized.
if (text != null && !text.equals(mWebTextView.getText().toString())
&& nativeTextGeneration() == mTextGeneration) {
mWebTextView.setTextAndKeepSelection(text);
}
} else {
mWebTextView.setGravity(nativeFocusCandidateIsRtlText() ?
Gravity.RIGHT : Gravity.NO_GRAVITY);
// This needs to be called before setType, which may call
// requestFormData, and it needs to have the correct nodePointer.
mWebTextView.setNodePointer(nodePointer);
mWebTextView.setType(nativeFocusCandidateType());
updateWebTextViewPadding();
if (null == text) {
if (DebugFlags.WEB_VIEW) {
Log.v(LOGTAG, "rebuildWebTextView null == text");
}
text = "";
}
mWebTextView.setTextAndKeepSelection(text);
InputMethodManager imm = InputMethodManager.peekInstance();
if (imm != null && imm.isActive(mWebTextView)) {
imm.restartInput(mWebTextView);
mWebTextView.setGravity(nativeFocusCandidateIsRtlText() ?
Gravity.RIGHT : Gravity.NO_GRAVITY);
// This needs to be called before setType, which may call
// requestFormData, and it needs to have the correct nodePointer.
mWebTextView.setNodePointer(nodePointer);
mWebTextView.setType(nativeFocusCandidateType());
updateWebTextViewPadding();
if (null == text) {
if (DebugFlags.WEB_VIEW) {
Log.v(LOGTAG, "rebuildWebTextView null == text");
}
text = "";
}
mWebTextView.setTextAndKeepSelection(text);
InputMethodManager imm = InputMethodManager.peekInstance();
if (imm != null && imm.isActive(mWebTextView)) {
imm.restartInput(mWebTextView);
}
if (isFocused()) {
mWebTextView.requestFocus();
@ -8120,19 +8103,7 @@ public class WebView extends AbsoluteLayout
// and representing the same node as the pointer.
if (inEditingMode() &&
mWebTextView.isSameTextField(msg.arg1)) {
if (msg.getData().getBoolean("password")) {
Spannable text = (Spannable) mWebTextView.getText();
int start = Selection.getSelectionStart(text);
int end = Selection.getSelectionEnd(text);
mWebTextView.setInPassword(true);
// Restore the selection, which may have been
// ruined by setInPassword.
Spannable pword =
(Spannable) mWebTextView.getText();
Selection.setSelection(pword, start, end);
// If the text entry has created more events, ignore
// this one.
} else if (msg.arg2 == mTextGeneration) {
if (msg.arg2 == mTextGeneration) {
String text = (String) msg.obj;
if (null == text) {
text = "";

View File

@ -623,6 +623,7 @@
<item name="android:completionThreshold">2</item>
<item name="android:dropDownSelector">@android:drawable/list_selector_background</item>
<item name="android:popupBackground">@android:drawable/spinner_dropdown_background</item>
<item name="textCursorDrawable">@android:drawable/text_cursor_holo_light</item>
</style>
<style name="Widget.TabWidget">