diff options
| -rw-r--r-- | api/current.txt | 36 | ||||
| -rwxr-xr-x | core/java/android/util/PropertyValueModel.java | 143 | ||||
| -rwxr-xr-x | core/java/android/util/ValueModel.java | 74 | ||||
| -rw-r--r-- | core/java/android/widget/CheckBox.java | 23 | ||||
| -rw-r--r-- | core/java/android/widget/EditText.java | 23 | ||||
| -rw-r--r-- | core/java/android/widget/SeekBar.java | 20 | ||||
| -rwxr-xr-x | core/java/android/widget/ValueEditor.java | 53 | ||||
| -rw-r--r-- | libs/hwui/FontRenderer.cpp | 10 | ||||
| -rw-r--r-- | libs/hwui/FontRenderer.h | 4 | ||||
| -rw-r--r-- | libs/hwui/OpenGLRenderer.cpp | 77 | ||||
| -rw-r--r-- | libs/hwui/OpenGLRenderer.h | 20 | ||||
| -rw-r--r-- | libs/hwui/TextDropShadowCache.cpp | 6 | ||||
| -rw-r--r-- | libs/hwui/TextDropShadowCache.h | 21 | ||||
| -rw-r--r-- | tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Grain.java | 73 | ||||
| -rw-r--r-- | tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java | 6 | ||||
| -rw-r--r-- | tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/grain.rs | 92 |
16 files changed, 625 insertions, 56 deletions
diff --git a/api/current.txt b/api/current.txt index 29e468b39307..fc067747b6c4 100644 --- a/api/current.txt +++ b/api/current.txt @@ -22826,6 +22826,17 @@ package android.util { method public void set(T, V); } + public class PropertyValueModel extends android.util.ValueModel { + method public T get(); + method public H getHost(); + method public android.util.Property<H, T> getProperty(); + method public java.lang.Class<T> getType(); + method public static android.util.PropertyValueModel<H, T> of(H, android.util.Property<H, T>); + method public static android.util.PropertyValueModel<H, T> of(H, java.lang.Class<T>, java.lang.String); + method public static android.util.PropertyValueModel of(java.lang.Object, java.lang.String); + method public void set(T); + } + public class SparseArray implements java.lang.Cloneable { ctor public SparseArray(); ctor public SparseArray(int); @@ -22974,6 +22985,14 @@ package android.util { field public int type; } + public abstract class ValueModel { + ctor protected ValueModel(); + method public abstract T get(); + method public abstract java.lang.Class<T> getType(); + method public abstract void set(T); + field public static final android.util.ValueModel EMPTY; + } + public class Xml { method public static android.util.AttributeSet asAttributeSet(org.xmlpull.v1.XmlPullParser); method public static android.util.Xml.Encoding findEncodingByName(java.lang.String) throws java.io.UnsupportedEncodingException; @@ -27395,10 +27414,12 @@ package android.widget { method public abstract void onSelectedDayChange(android.widget.CalendarView, int, int, int); } - public class CheckBox extends android.widget.CompoundButton { + public class CheckBox extends android.widget.CompoundButton implements android.widget.ValueEditor { ctor public CheckBox(android.content.Context); ctor public CheckBox(android.content.Context, android.util.AttributeSet); ctor public CheckBox(android.content.Context, android.util.AttributeSet, int); + method public android.util.ValueModel<java.lang.Boolean> getValueModel(); + method public void setValueModel(android.util.ValueModel<java.lang.Boolean>); } public abstract interface Checkable { @@ -27571,14 +27592,16 @@ package android.widget { method public void setSize(int, int); } - public class EditText extends android.widget.TextView { + public class EditText extends android.widget.TextView implements android.widget.ValueEditor { ctor public EditText(android.content.Context); ctor public EditText(android.content.Context, android.util.AttributeSet); ctor public EditText(android.content.Context, android.util.AttributeSet, int); method public void extendSelection(int); + method public android.util.ValueModel<java.lang.CharSequence> getValueModel(); method public void selectAll(); method public void setSelection(int, int); method public void setSelection(int); + method public void setValueModel(android.util.ValueModel<java.lang.CharSequence>); } public abstract interface ExpandableListAdapter { @@ -28595,11 +28618,13 @@ package android.widget { method public abstract java.lang.Object[] getSections(); } - public class SeekBar extends android.widget.AbsSeekBar { + public class SeekBar extends android.widget.AbsSeekBar implements android.widget.ValueEditor { ctor public SeekBar(android.content.Context); ctor public SeekBar(android.content.Context, android.util.AttributeSet); ctor public SeekBar(android.content.Context, android.util.AttributeSet, int); + method public android.util.ValueModel<java.lang.Integer> getValueModel(); method public void setOnSeekBarChangeListener(android.widget.SeekBar.OnSeekBarChangeListener); + method public void setValueModel(android.util.ValueModel<java.lang.Integer>); } public static abstract interface SeekBar.OnSeekBarChangeListener { @@ -29171,6 +29196,11 @@ package android.widget { method public android.widget.TextView getText2(); } + public abstract interface ValueEditor { + method public abstract android.util.ValueModel<T> getValueModel(); + method public abstract void setValueModel(android.util.ValueModel<T>); + } + public class VideoView extends android.view.SurfaceView implements android.widget.MediaController.MediaPlayerControl { ctor public VideoView(android.content.Context); ctor public VideoView(android.content.Context, android.util.AttributeSet); diff --git a/core/java/android/util/PropertyValueModel.java b/core/java/android/util/PropertyValueModel.java new file mode 100755 index 000000000000..eb9c47d0c379 --- /dev/null +++ b/core/java/android/util/PropertyValueModel.java @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.util; + +/** + * A value model for a {@link Property property} of a host object. This class can be used for + * both reflective and non-reflective property implementations. + * + * @param <H> the host type, where the host is the object that holds this property + * @param <T> the value type + * + * @see Property + * @see ValueModel + */ +public class PropertyValueModel<H, T> extends ValueModel<T> { + private final H mHost; + private final Property<H, T> mProperty; + + private PropertyValueModel(H host, Property<H, T> property) { + mProperty = property; + mHost = host; + } + + /** + * Returns the host. + * + * @return the host + */ + public H getHost() { + return mHost; + } + + /** + * Returns the property. + * + * @return the property + */ + public Property<H, T> getProperty() { + return mProperty; + } + + @Override + public Class<T> getType() { + return mProperty.getType(); + } + + @Override + public T get() { + return mProperty.get(mHost); + } + + @Override + public void set(T value) { + mProperty.set(mHost, value); + } + + /** + * Return an appropriate PropertyValueModel for this host and property. + * + * @param host the host + * @param property the property + * @return the value model + */ + public static <H, T> PropertyValueModel<H, T> of(H host, Property<H, T> property) { + return new PropertyValueModel<H, T>(host, property); + } + + /** + * Return a PropertyValueModel for this {@code host} and a + * reflective property, constructed from this {@code propertyType} and {@code propertyName}. + * + * @param host + * @param propertyType the property type + * @param propertyName the property name + * @return a value model with this host and a reflective property with this type and name + * + * @see Property#of + */ + public static <H, T> PropertyValueModel<H, T> of(H host, Class<T> propertyType, + String propertyName) { + return of(host, Property.of((Class<H>) host.getClass(), propertyType, propertyName)); + } + + private static Class getNullaryMethodReturnType(Class c, String name) { + try { + return c.getMethod(name).getReturnType(); + } catch (NoSuchMethodException e) { + return null; + } + } + + private static Class getFieldType(Class c, String name) { + try { + return c.getField(name).getType(); + } catch (NoSuchFieldException e) { + return null; + } + } + + private static String capitalize(String name) { + if (name.isEmpty()) { + return name; + } + return Character.toUpperCase(name.charAt(0)) + name.substring(1); + } + + /** + * Return a PropertyValueModel for this {@code host} and and {@code propertyName}. + * + * @param host the host + * @param propertyName the property name + * @return a value model with this host and a reflective property with this name + */ + public static PropertyValueModel of(Object host, String propertyName) { + Class clazz = host.getClass(); + String suffix = capitalize(propertyName); + Class propertyType = getNullaryMethodReturnType(clazz, "get" + suffix); + if (propertyType == null) { + propertyType = getNullaryMethodReturnType(clazz, "is" + suffix); + } + if (propertyType == null) { + propertyType = getFieldType(clazz, propertyName); + } + if (propertyType == null) { + throw new NoSuchPropertyException(propertyName); + } + return of(host, propertyType, propertyName); + } +} diff --git a/core/java/android/util/ValueModel.java b/core/java/android/util/ValueModel.java new file mode 100755 index 000000000000..4789682ea496 --- /dev/null +++ b/core/java/android/util/ValueModel.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.util; + +/** + * A ValueModel is an abstraction for a 'slot' or place in memory in which a value + * may be stored and retrieved. A common implementation of ValueModel is a regular property of + * an object, whose value may be retrieved by calling the appropriate <em>getter</em> + * method and set by calling the corresponding <em>setter</em> method. + * + * @param <T> the value type + * + * @see PropertyValueModel + */ +public abstract class ValueModel<T> { + /** + * The empty model should be used in place of {@code null} to indicate that a + * model has not been set. The empty model has no value and does nothing when it is set. + */ + public static final ValueModel EMPTY = new ValueModel() { + @Override + public Class getType() { + return Object.class; + } + + @Override + public Object get() { + return null; + } + + @Override + public void set(Object value) { + + } + }; + + protected ValueModel() { + } + + /** + * Returns the type of this property. + * + * @return the property type + */ + public abstract Class<T> getType(); + + /** + * Returns the value of this property. + * + * @return the property value + */ + public abstract T get(); + + /** + * Sets the value of this property. + * + * @param value the new value for this property + */ + public abstract void set(T value); +}
\ No newline at end of file diff --git a/core/java/android/widget/CheckBox.java b/core/java/android/widget/CheckBox.java index 858c415d0f08..6d292dcafa83 100644 --- a/core/java/android/widget/CheckBox.java +++ b/core/java/android/widget/CheckBox.java @@ -20,6 +20,7 @@ import android.content.Context; import android.util.AttributeSet; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityNodeInfo; +import android.util.ValueModel; /** @@ -55,7 +56,9 @@ import android.view.accessibility.AccessibilityNodeInfo; * {@link android.R.styleable#View View Attributes} * </p> */ -public class CheckBox extends CompoundButton { +public class CheckBox extends CompoundButton implements ValueEditor<Boolean> { + private ValueModel<Boolean> mValueModel = ValueModel.EMPTY; + public CheckBox(Context context) { this(context, null); } @@ -79,4 +82,22 @@ public class CheckBox extends CompoundButton { super.onInitializeAccessibilityNodeInfo(info); info.setClassName(CheckBox.class.getName()); } + + @Override + public ValueModel<Boolean> getValueModel() { + return mValueModel; + } + + @Override + public void setValueModel(ValueModel<Boolean> valueModel) { + mValueModel = valueModel; + setChecked(mValueModel.get()); + } + + @Override + public boolean performClick() { + boolean handled = super.performClick(); + mValueModel.set(isChecked()); + return handled; + } } diff --git a/core/java/android/widget/EditText.java b/core/java/android/widget/EditText.java index 2fd876822368..8686177c6247 100644 --- a/core/java/android/widget/EditText.java +++ b/core/java/android/widget/EditText.java @@ -17,6 +17,7 @@ package android.widget; import android.content.Context; +import android.graphics.Rect; import android.text.Editable; import android.text.Selection; import android.text.Spannable; @@ -24,6 +25,7 @@ import android.text.TextUtils; import android.text.method.ArrowKeyMovementMethod; import android.text.method.MovementMethod; import android.util.AttributeSet; +import android.util.ValueModel; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityNodeInfo; @@ -47,7 +49,9 @@ import android.view.accessibility.AccessibilityNodeInfo; * {@link android.R.styleable#TextView TextView Attributes}, * {@link android.R.styleable#View View Attributes} */ -public class EditText extends TextView { +public class EditText extends TextView implements ValueEditor<CharSequence> { + private ValueModel<CharSequence> mValueModel = ValueModel.EMPTY; + public EditText(Context context) { this(context, null); } @@ -128,4 +132,21 @@ public class EditText extends TextView { super.onInitializeAccessibilityNodeInfo(info); info.setClassName(EditText.class.getName()); } + + @Override + public ValueModel<CharSequence> getValueModel() { + return mValueModel; + } + + @Override + public void setValueModel(ValueModel<CharSequence> valueModel) { + mValueModel = valueModel; + setText(mValueModel.get()); + } + + @Override + void sendAfterTextChanged(Editable text) { + super.sendAfterTextChanged(text); + mValueModel.set(text); + } } diff --git a/core/java/android/widget/SeekBar.java b/core/java/android/widget/SeekBar.java index 2737f9414c46..a6486a827af5 100644 --- a/core/java/android/widget/SeekBar.java +++ b/core/java/android/widget/SeekBar.java @@ -18,6 +18,7 @@ package android.widget; import android.content.Context; import android.util.AttributeSet; +import android.util.ValueModel; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityNodeInfo; @@ -33,7 +34,7 @@ import android.view.accessibility.AccessibilityNodeInfo; * * @attr ref android.R.styleable#SeekBar_thumb */ -public class SeekBar extends AbsSeekBar { +public class SeekBar extends AbsSeekBar implements ValueEditor<Integer> { /** * A callback that notifies clients when the progress level has been @@ -69,8 +70,9 @@ public class SeekBar extends AbsSeekBar { void onStopTrackingTouch(SeekBar seekBar); } + private ValueModel<Integer> mValueModel = ValueModel.EMPTY; private OnSeekBarChangeListener mOnSeekBarChangeListener; - + public SeekBar(Context context) { this(context, null); } @@ -89,9 +91,23 @@ public class SeekBar extends AbsSeekBar { if (mOnSeekBarChangeListener != null) { mOnSeekBarChangeListener.onProgressChanged(this, getProgress(), fromUser); + if (fromUser) { + mValueModel.set(getProgress()); + } } } + @Override + public ValueModel<Integer> getValueModel() { + return mValueModel; + } + + @Override + public void setValueModel(ValueModel<Integer> valueModel) { + mValueModel = valueModel; + setProgress(mValueModel.get()); + } + /** * Sets a listener to receive notifications of changes to the SeekBar's progress level. Also * provides notifications of when the user starts and stops a touch gesture within the SeekBar. diff --git a/core/java/android/widget/ValueEditor.java b/core/java/android/widget/ValueEditor.java new file mode 100755 index 000000000000..2b91abf9b8ff --- /dev/null +++ b/core/java/android/widget/ValueEditor.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.widget; + +import android.util.ValueModel; + +/** + * An interface for editors of simple values. Classes implementing this interface are normally + * UI controls (subclasses of {@link android.view.View View}) that can provide a suitable + * user interface to display and edit values of the specified type. This interface is + * intended to describe editors for simple types, like {@code boolean}, {@code int} or + * {@code String}, where the values themselves are immutable. + * <p> + * For example, {@link android.widget.CheckBox CheckBox} implements + * this interface for the Boolean type as it is capable of providing an appropriate + * mechanism for displaying and changing the value of a Boolean property. + * + * @param <T> the value type that this editor supports + */ +public interface ValueEditor<T> { + /** + * Return the last value model that was set. If no value model has been set, the editor + * should return the value {@link android.util.ValueModel#EMPTY}. + * + * @return the value model + */ + public ValueModel<T> getValueModel(); + + /** + * Sets the value model for this editor. When the value model is set, the editor should + * retrieve the value from the value model, using {@link android.util.ValueModel#get()}, + * and set its internal state accordingly. Likewise, when the editor's internal state changes + * it should update the value model by calling {@link android.util.ValueModel#set(T)} + * with the appropriate value. + * + * @param valueModel the new value model for this editor. + */ + public void setValueModel(ValueModel<T> valueModel); +} diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp index eeb37cbe08c1..7f0ed7309b62 100644 --- a/libs/hwui/FontRenderer.cpp +++ b/libs/hwui/FontRenderer.cpp @@ -288,13 +288,13 @@ void Font::render(SkPaint* paint, const char *text, uint32_t start, uint32_t len } void Font::measure(SkPaint* paint, const char* text, uint32_t start, uint32_t len, - int numGlyphs, Rect *bounds) { + int numGlyphs, Rect *bounds, const float* positions) { if (bounds == NULL) { ALOGE("No return rectangle provided to measure text"); return; } bounds->set(1e6, -1e6, -1e6, 1e6); - render(paint, text, start, len, numGlyphs, 0, 0, MEASURE, NULL, 0, 0, bounds, NULL); + render(paint, text, start, len, numGlyphs, 0, 0, MEASURE, NULL, 0, 0, bounds, positions); } void Font::render(SkPaint* paint, const char* text, uint32_t start, uint32_t len, @@ -1007,7 +1007,7 @@ void FontRenderer::setFont(SkPaint* paint, uint32_t fontId, float fontSize) { } FontRenderer::DropShadow FontRenderer::renderDropShadow(SkPaint* paint, const char *text, - uint32_t startIndex, uint32_t len, int numGlyphs, uint32_t radius) { + uint32_t startIndex, uint32_t len, int numGlyphs, uint32_t radius, const float* positions) { checkInit(); if (!mCurrentFont) { @@ -1025,7 +1025,7 @@ FontRenderer::DropShadow FontRenderer::renderDropShadow(SkPaint* paint, const ch mBounds = NULL; Rect bounds; - mCurrentFont->measure(paint, text, startIndex, len, numGlyphs, &bounds); + mCurrentFont->measure(paint, text, startIndex, len, numGlyphs, &bounds, positions); uint32_t paddedWidth = (uint32_t) (bounds.right - bounds.left) + 2 * radius; uint32_t paddedHeight = (uint32_t) (bounds.top - bounds.bottom) + 2 * radius; @@ -1039,7 +1039,7 @@ FontRenderer::DropShadow FontRenderer::renderDropShadow(SkPaint* paint, const ch int penY = radius - bounds.bottom; mCurrentFont->render(paint, text, startIndex, len, numGlyphs, penX, penY, - dataBuffer, paddedWidth, paddedHeight); + Font::BITMAP, dataBuffer, paddedWidth, paddedHeight, NULL, positions); blurImage(dataBuffer, paddedWidth, paddedHeight, radius); DropShadow image; diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h index b7b4ec9683f9..9ed69325c914 100644 --- a/libs/hwui/FontRenderer.h +++ b/libs/hwui/FontRenderer.h @@ -184,7 +184,7 @@ protected: uint32_t bitmapW, uint32_t bitmapH, Rect *bounds, const float* positions); void measure(SkPaint* paint, const char* text, uint32_t start, uint32_t len, - int numGlyphs, Rect *bounds); + int numGlyphs, Rect *bounds, const float* positions); Font(FontRenderer* state, uint32_t fontId, float fontSize, int flags, uint32_t italicStyle, uint32_t scaleX, SkPaint::Style style, uint32_t strokeWidth); @@ -273,7 +273,7 @@ public: // After renderDropShadow returns, the called owns the memory in DropShadow.image // and is responsible for releasing it when it's done with it DropShadow renderDropShadow(SkPaint* paint, const char *text, uint32_t startIndex, - uint32_t len, int numGlyphs, uint32_t radius); + uint32_t len, int numGlyphs, uint32_t radius, const float* positions); GLuint getTexture(bool linearFiltering = false) { checkInit(); diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index 5fa3d3ebc9dc..6d781c77fa7a 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -2303,6 +2303,44 @@ status_t OpenGLRenderer::drawRect(float left, float top, float right, float bott return DrawGlInfo::kStatusDrew; } +void OpenGLRenderer::drawTextShadow(SkPaint* paint, const char* text, int bytesCount, int count, + const float* positions, FontRenderer& fontRenderer, int alpha, SkXfermode::Mode mode, + float x, float y) { + mCaches.activeTexture(0); + + // NOTE: The drop shadow will not perform gamma correction + // if shader-based correction is enabled + mCaches.dropShadowCache.setFontRenderer(fontRenderer); + const ShadowTexture* shadow = mCaches.dropShadowCache.get( + paint, text, bytesCount, count, mShadowRadius, positions); + const AutoTexture autoCleanup(shadow); + + const float sx = x - shadow->left + mShadowDx; + const float sy = y - shadow->top + mShadowDy; + + const int shadowAlpha = ((mShadowColor >> 24) & 0xFF) * mSnapshot->alpha; + int shadowColor = mShadowColor; + if (mShader) { + shadowColor = 0xffffffff; + } + + setupDraw(); + setupDrawWithTexture(true); + setupDrawAlpha8Color(shadowColor, shadowAlpha < 255 ? shadowAlpha : alpha); + setupDrawColorFilter(); + setupDrawShader(); + setupDrawBlending(true, mode); + setupDrawProgram(); + setupDrawModelView(sx, sy, sx + shadow->width, sy + shadow->height); + setupDrawTexture(shadow->id); + setupDrawPureColorUniforms(); + setupDrawColorFilterUniforms(); + setupDrawShaderUniforms(); + setupDrawMesh(NULL, (GLvoid*) gMeshTextureOffset); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount); +} + status_t OpenGLRenderer::drawPosText(const char* text, int bytesCount, int count, const float* positions, SkPaint* paint) { if (text == NULL || count == 0 || mSnapshot->isIgnored() || @@ -2331,6 +2369,11 @@ status_t OpenGLRenderer::drawPosText(const char* text, int bytesCount, int count SkXfermode::Mode mode; getAlphaAndMode(paint, &alpha, &mode); + if (CC_UNLIKELY(mHasShadow)) { + drawTextShadow(paint, text, bytesCount, count, positions, fontRenderer, alpha, mode, + 0.0f, 0.0f); + } + // Pick the appropriate texture filtering bool linearFilter = mSnapshot->transform->changesBounds(); if (pureTranslate && !linearFilter) { @@ -2424,39 +2467,7 @@ status_t OpenGLRenderer::drawText(const char* text, int bytesCount, int count, getAlphaAndMode(paint, &alpha, &mode); if (CC_UNLIKELY(mHasShadow)) { - mCaches.activeTexture(0); - - // NOTE: The drop shadow will not perform gamma correction - // if shader-based correction is enabled - mCaches.dropShadowCache.setFontRenderer(fontRenderer); - const ShadowTexture* shadow = mCaches.dropShadowCache.get( - paint, text, bytesCount, count, mShadowRadius); - const AutoTexture autoCleanup(shadow); - - const float sx = oldX - shadow->left + mShadowDx; - const float sy = oldY - shadow->top + mShadowDy; - - const int shadowAlpha = ((mShadowColor >> 24) & 0xFF) * mSnapshot->alpha; - int shadowColor = mShadowColor; - if (mShader) { - shadowColor = 0xffffffff; - } - - setupDraw(); - setupDrawWithTexture(true); - setupDrawAlpha8Color(shadowColor, shadowAlpha < 255 ? shadowAlpha : alpha); - setupDrawColorFilter(); - setupDrawShader(); - setupDrawBlending(true, mode); - setupDrawProgram(); - setupDrawModelView(sx, sy, sx + shadow->width, sy + shadow->height); - setupDrawTexture(shadow->id); - setupDrawPureColorUniforms(); - setupDrawColorFilterUniforms(); - setupDrawShaderUniforms(); - setupDrawMesh(NULL, (GLvoid*) gMeshTextureOffset); - - glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount); + drawTextShadow(paint, text, bytesCount, count, NULL, fontRenderer, alpha, mode, oldX, oldY); } // Pick the appropriate texture filtering diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h index 1926575bccc2..441e9fd6c8d8 100644 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -498,6 +498,24 @@ private: void drawTextDecorations(const char* text, int bytesCount, float length, float x, float y, SkPaint* paint); + /** + * Draws shadow layer on text (with optional positions). + * + * @param paint The paint to draw the shadow with + * @param text The text to draw + * @param bytesCount The number of bytes in the text + * @param count The number of glyphs in the text + * @param positions The x, y positions of individual glyphs (or NULL) + * @param fontRenderer The font renderer object + * @param alpha The alpha value for drawing the shadow + * @param mode The xfermode for drawing the shadow + * @param x The x coordinate where the shadow will be drawn + * @param y The y coordinate where the shadow will be drawn + */ + void drawTextShadow(SkPaint* paint, const char* text, int bytesCount, int count, + const float* positions, FontRenderer& fontRenderer, int alpha, SkXfermode::Mode mode, + float x, float y); + /** * Draws a path texture. Path textures are alpha8 bitmaps that need special * compositing to apply colors/filters/etc. @@ -507,7 +525,7 @@ private: * @param y The y coordinate where the texture will be drawn * @param paint The paint to draw the texture with */ - void drawPathTexture(const PathTexture* texture, float x, float y, SkPaint* paint); + void drawPathTexture(const PathTexture* texture, float x, float y, SkPaint* paint); /** * Resets the texture coordinates stored in mMeshVertices. Setting the values diff --git a/libs/hwui/TextDropShadowCache.cpp b/libs/hwui/TextDropShadowCache.cpp index bef137371d44..93aa8a5c0af3 100644 --- a/libs/hwui/TextDropShadowCache.cpp +++ b/libs/hwui/TextDropShadowCache.cpp @@ -102,13 +102,13 @@ void TextDropShadowCache::clear() { } ShadowTexture* TextDropShadowCache::get(SkPaint* paint, const char* text, uint32_t len, - int numGlyphs, uint32_t radius) { - ShadowText entry(paint, radius, len, text); + int numGlyphs, uint32_t radius, const float* positions) { + ShadowText entry(paint, radius, len, text, positions); ShadowTexture* texture = mCache.get(entry); if (!texture) { FontRenderer::DropShadow shadow = mRenderer->renderDropShadow(paint, text, 0, - len, numGlyphs, radius); + len, numGlyphs, radius, positions); texture = new ShadowTexture; texture->left = shadow.penX; diff --git a/libs/hwui/TextDropShadowCache.h b/libs/hwui/TextDropShadowCache.h index e2bdde1eca89..bae0c49349f6 100644 --- a/libs/hwui/TextDropShadowCache.h +++ b/libs/hwui/TextDropShadowCache.h @@ -35,8 +35,9 @@ struct ShadowText { ShadowText(): radius(0), len(0), textSize(0.0f), typeface(NULL) { } - ShadowText(SkPaint* paint, uint32_t radius, uint32_t len, const char* srcText): - radius(radius), len(len) { + ShadowText(SkPaint* paint, uint32_t radius, uint32_t len, const char* srcText, + const float* positions): + radius(radius), len(len), positions(positions) { // TODO: Propagate this through the API, we should not cast here text = (const char16_t*) srcText; @@ -66,11 +67,18 @@ struct ShadowText { uint32_t italicStyle; uint32_t scaleX; const char16_t* text; + const float* positions; String16 str; + Vector<float> positionsCopy; void copyTextLocally() { str.setTo((const char16_t*) text, len >> 1); text = str.string(); + if (positions != NULL) { + positionsCopy.clear(); + positionsCopy.appendArray(positions, len); + positions = positionsCopy.array(); + } } bool operator<(const ShadowText& rhs) const { @@ -81,7 +89,12 @@ struct ShadowText { LTE_INT(flags) { LTE_INT(italicStyle) { LTE_INT(scaleX) { - return memcmp(text, rhs.text, len) < 0; + int cmp = memcmp(text, rhs.text, len); + if (cmp < 0) return true; + if (cmp == 0 && rhs.positions != NULL) { + if (positions == NULL) return true; + return memcmp(positions, rhs.positions, len << 2) < 0; + } } } } @@ -117,7 +130,7 @@ public: void operator()(ShadowText& text, ShadowTexture*& texture); ShadowTexture* get(SkPaint* paint, const char* text, uint32_t len, - int numGlyphs, uint32_t radius); + int numGlyphs, uint32_t radius, const float* positions); /** * Clears the cache. This causes all textures to be deleted. diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Grain.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Grain.java new file mode 100644 index 000000000000..cd54c2eb5bc1 --- /dev/null +++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/Grain.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.rs.image; + +import java.lang.Math; + +import android.renderscript.Allocation; +import android.renderscript.Element; +import android.renderscript.RenderScript; +import android.renderscript.Script; +import android.renderscript.ScriptC; +import android.renderscript.Type; +import android.util.Log; +import android.widget.SeekBar; +import android.widget.TextView; + +public class Grain extends TestBase { + private ScriptC_grain mScript; + private Allocation mNoise; + private Allocation mNoise2; + + + public boolean onBar1Setup(SeekBar b, TextView t) { + t.setText("Strength"); + b.setProgress(50); + return true; + } + + public void onBar1Changed(int progress) { + float s = progress / 100.0f; + mScript.set_gNoiseStrength(s); + } + + public void createTest(android.content.res.Resources res) { + int width = mInPixelsAllocation.getType().getX(); + int height = mInPixelsAllocation.getType().getY(); + + Type.Builder tb = new Type.Builder(mRS, Element.U8(mRS)); + tb.setX(width); + tb.setY(height); + mNoise = Allocation.createTyped(mRS, tb.create()); + mNoise2 = Allocation.createTyped(mRS, tb.create()); + + mScript = new ScriptC_grain(mRS, res, R.raw.grain); + mScript.set_gWidth(width); + mScript.set_gHeight(height); + mScript.set_gNoiseStrength(0.5f); + mScript.set_gBlendSource(mNoise); + mScript.set_gNoise(mNoise2); + } + + public void runTest() { + mScript.forEach_genRand(mNoise); + mScript.forEach_blend9(mNoise2); + mScript.forEach_root(mInPixelsAllocation, mOutPixelsAllocation); + } + +} + diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java index e085582c3027..3a9838bf790a 100644 --- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java +++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java @@ -140,6 +140,9 @@ public class ImageProcessingActivity extends Activity case 5: mTest = new Greyscale(); break; + case 6: + mTest = new Grain(); + break; } mTest.createBaseTest(this, mBitmapIn); @@ -152,13 +155,14 @@ public class ImageProcessingActivity extends Activity } void setupTests() { - mTestNames = new String[6]; + mTestNames = new String[7]; mTestNames[0] = "Levels Vec3 Relaxed"; mTestNames[1] = "Levels Vec4 Relaxed"; mTestNames[2] = "Levels Vec3 Full"; mTestNames[3] = "Levels Vec4 Full"; mTestNames[4] = "Blur radius 25"; mTestNames[5] = "Greyscale"; + mTestNames[6] = "Grain"; mTestSpinner.setAdapter(new ArrayAdapter<String>( this, R.layout.spinner_layout, mTestNames)); } diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/grain.rs b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/grain.rs new file mode 100644 index 000000000000..97ae4fb3a38d --- /dev/null +++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/grain.rs @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma version(1) +#pragma rs java_package_name(com.android.rs.image) +#pragma rs_fp_relaxed + +void genRand(uchar *out) { + *out = (uchar)rsRand(0xff); +} + +/* + * Convolution matrix of distance 2 with fixed point of 'kShiftBits' bits + * shifted. Thus the sum of this matrix should be 'kShiftValue'. Entries of + * small values are not calculated to gain efficiency. + * The order ot pixels represented in this matrix is: + * 1 2 3 + * 4 0 5 + * 6 7 8 + * and the matrix should be: {230, 56, 114, 56, 114, 114, 56, 114, 56}. + * However, since most of the valus are identical, we only use the first three + * entries and the entries corresponding to the pixels is: + * 1 2 1 + * 2 0 2 + * 1 2 1 + */ + +int32_t gWidth; +int32_t gHeight; + +rs_allocation gBlendSource; +void blend9(uchar *out, uint32_t x, uint32_t y) { + uint32_t x1 = min(x+1, (uint32_t)gWidth); + uint32_t x2 = max(x-1, (uint32_t)0); + uint32_t y1 = min(y+1, (uint32_t)gHeight); + uint32_t y2 = max(y-1, (uint32_t)0); + + uint p00 = 56 * ((uchar *)rsGetElementAt(gBlendSource, x1, y1))[0]; + uint p01 = 114 * ((uchar *)rsGetElementAt(gBlendSource, x, y1))[0]; + uint p02 = 56 * ((uchar *)rsGetElementAt(gBlendSource, x2, y1))[0]; + uint p10 = 114 * ((uchar *)rsGetElementAt(gBlendSource, x1, y))[0]; + uint p11 = 230 * ((uchar *)rsGetElementAt(gBlendSource, x, y))[0]; + uint p12 = 114 * ((uchar *)rsGetElementAt(gBlendSource, x2, y))[0]; + uint p20 = 56 * ((uchar *)rsGetElementAt(gBlendSource, x1, y2))[0]; + uint p21 = 114 * ((uchar *)rsGetElementAt(gBlendSource, x, y2))[0]; + uint p22 = 56 * ((uchar *)rsGetElementAt(gBlendSource, x2, y2))[0]; + + p00 += p01; + p02 += p10; + p11 += p12; + p20 += p21; + + p22 += p00; + p02 += p11; + + p20 += p22; + p20 += p02; + + *out = (uchar)(p20 >> 10); +} + +float gNoiseStrength; + +rs_allocation gNoise; +void root(const uchar4 *in, uchar4 *out, uint32_t x, uint32_t y) { + float4 ip = convert_float4(*in); + float pnoise = (float) ((uchar *)rsGetElementAt(gNoise, x, y))[0]; + + float energy_level = ip.r + ip.g + ip.b; + float energy_mask = (28.f - sqrt(energy_level)) * 0.03571f; + pnoise = (pnoise - 128.f) * energy_mask; + + ip += pnoise * gNoiseStrength; + ip = clamp(ip, 0.f, 255.f); + + uchar4 p = convert_uchar4(ip); + p.a = 0xff; + *out = p; +} |