Merge "fix NPE in updateClientUids"
diff --git a/api/current.txt b/api/current.txt
index 1cf14aa..71b6b14 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -28963,7 +28963,9 @@
     ctor public QuickContactBadge(android.content.Context, android.util.AttributeSet);
     ctor public QuickContactBadge(android.content.Context, android.util.AttributeSet, int);
     method public void assignContactFromEmail(java.lang.String, boolean);
+    method public void assignContactFromEmail(java.lang.String, boolean, android.os.Bundle);
     method public void assignContactFromPhone(java.lang.String, boolean);
+    method public void assignContactFromPhone(java.lang.String, boolean, android.os.Bundle);
     method public void assignContactUri(android.net.Uri);
     method public void onClick(android.view.View);
     method public void setExcludeMimes(java.lang.String[]);
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 7739ff7..e0cf3b2 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -433,20 +433,16 @@
 
     @Override
     public boolean clipPath(Path path) {
-        // TODO: Implement
-        path.computeBounds(mPathBounds, true);
-        return nClipRect(mRenderer, mPathBounds.left, mPathBounds.top,
-                mPathBounds.right, mPathBounds.bottom, Region.Op.INTERSECT.nativeInt);
+        return nClipPath(mRenderer, path.mNativePath, Region.Op.INTERSECT.nativeInt);
     }
 
     @Override
     public boolean clipPath(Path path, Region.Op op) {
-        // TODO: Implement
-        path.computeBounds(mPathBounds, true);
-        return nClipRect(mRenderer, mPathBounds.left, mPathBounds.top,
-                mPathBounds.right, mPathBounds.bottom, op.nativeInt);
+        return nClipPath(mRenderer, path.mNativePath, op.nativeInt);
     }
 
+    private static native boolean nClipPath(int renderer, int path, int op);
+
     @Override
     public boolean clipRect(float left, float top, float right, float bottom) {
         return nClipRect(mRenderer, left, top, right, bottom, Region.Op.INTERSECT.nativeInt);
@@ -465,8 +461,8 @@
         return nClipRect(mRenderer, left, top, right, bottom, Region.Op.INTERSECT.nativeInt);
     }
     
-    private static native boolean nClipRect(int renderer, int left, int top, int right, int bottom,
-            int op);
+    private static native boolean nClipRect(int renderer, int left, int top,
+            int right, int bottom, int op);
 
     @Override
     public boolean clipRect(Rect rect) {
@@ -492,20 +488,16 @@
 
     @Override
     public boolean clipRegion(Region region) {
-        // TODO: Implement
-        region.getBounds(mClipBounds);
-        return nClipRect(mRenderer, mClipBounds.left, mClipBounds.top,
-                mClipBounds.right, mClipBounds.bottom, Region.Op.INTERSECT.nativeInt);
+        return nClipRegion(mRenderer, region.mNativeRegion, Region.Op.INTERSECT.nativeInt);
     }
 
     @Override
     public boolean clipRegion(Region region, Region.Op op) {
-        // TODO: Implement
-        region.getBounds(mClipBounds);
-        return nClipRect(mRenderer, mClipBounds.left, mClipBounds.top,
-                mClipBounds.right, mClipBounds.bottom, op.nativeInt);
+        return nClipRegion(mRenderer, region.mNativeRegion, op.nativeInt);
     }
 
+    private static native boolean nClipRegion(int renderer, int region, int op);
+
     @Override
     public boolean getClipBounds(Rect bounds) {
         return nGetClipBounds(mRenderer, bounds);
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 7ecdcbe..0d45bbc 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2013 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.
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-
 package android.view;
 
 import android.content.ComponentCallbacks2;
@@ -174,6 +173,17 @@
     public static final String DEBUG_SHOW_OVERDRAW_PROPERTY = "debug.hwui.show_overdraw";
 
     /**
+     * Turn on to allow region clipping (see
+     * {@link android.graphics.Canvas#clipPath(android.graphics.Path)} and
+     * {@link android.graphics.Canvas#clipRegion(android.graphics.Region)}.
+     *
+     * When this option is turned on a stencil buffer is always required.
+     * If this option is off a stencil buffer is only created when the overdraw
+     * debugging mode is turned on.
+     */
+    private static final boolean REGION_CLIPPING_ENABLED = false;
+
+    /**
      * A process can set this flag to false to prevent the use of hardware
      * rendering.
      * 
@@ -876,10 +886,12 @@
                 changed = true;
                 mShowOverdraw = value;
 
-                if (surface != null && isEnabled()) {
-                    if (validate()) {
-                        sEglConfig = loadEglConfig();
-                        invalidate(surface);
+                if (!REGION_CLIPPING_ENABLED) {
+                    if (surface != null && isEnabled()) {
+                        if (validate()) {
+                            sEglConfig = loadEglConfig();
+                            invalidate(surface);
+                        }
                     }
                 }
             }
@@ -1752,6 +1764,11 @@
 
         @Override
         int[] getConfig(boolean dirtyRegions) {
+            //noinspection PointlessBooleanExpression
+            final int stencilSize = mShowOverdraw || REGION_CLIPPING_ENABLED ?
+                    GLES20Canvas.getStencilSize() : 0;
+            final int swapBehavior = dirtyRegions ? EGL14.EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0;
+
             return new int[] {
                     EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT,
                     EGL_RED_SIZE, 8,
@@ -1760,14 +1777,12 @@
                     EGL_ALPHA_SIZE, 8,
                     EGL_DEPTH_SIZE, 0,
                     EGL_CONFIG_CAVEAT, EGL_NONE,
-                    // TODO: Find a better way to choose the stencil size
-                    EGL_STENCIL_SIZE, mShowOverdraw ? GLES20Canvas.getStencilSize() : 0,
-                    EGL_SURFACE_TYPE, EGL_WINDOW_BIT |
-                            (dirtyRegions ? EGL14.EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0),
+                    EGL_STENCIL_SIZE, stencilSize,
+                    EGL_SURFACE_TYPE, EGL_WINDOW_BIT | swapBehavior,
                     EGL_NONE
             };
         }
-        
+
         @Override
         void initCaches() {
             GLES20Canvas.initCaches();
diff --git a/core/java/android/widget/QuickContactBadge.java b/core/java/android/widget/QuickContactBadge.java
index 786afe2..622ac8f5 100644
--- a/core/java/android/widget/QuickContactBadge.java
+++ b/core/java/android/widget/QuickContactBadge.java
@@ -27,6 +27,7 @@
 import android.graphics.Canvas;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
+import android.os.Bundle;
 import android.provider.ContactsContract.CommonDataKinds.Email;
 import android.provider.ContactsContract.Contacts;
 import android.provider.ContactsContract.Intents;
@@ -50,6 +51,7 @@
     private Drawable mOverlay;
     private QueryHandler mQueryHandler;
     private Drawable mDefaultAvatar;
+    private Bundle mExtras = null;
 
     protected String[] mExcludeMimes = null;
 
@@ -58,6 +60,8 @@
     static final private int TOKEN_EMAIL_LOOKUP_AND_TRIGGER = 2;
     static final private int TOKEN_PHONE_LOOKUP_AND_TRIGGER = 3;
 
+    static final private String EXTRA_URI_CONTENT = "uri_content";
+
     static final String[] EMAIL_LOOKUP_PROJECTION = new String[] {
         RawContacts.CONTACT_ID,
         Contacts.LOOKUP_KEY,
@@ -175,7 +179,26 @@
      * until this view is clicked.
      */
     public void assignContactFromEmail(String emailAddress, boolean lazyLookup) {
+        assignContactFromEmail(emailAddress, lazyLookup, null);
+    }
+
+    /**
+     * Assign a contact based on an email address. This should only be used when
+     * the contact's URI is not available, as an extra query will have to be
+     * performed to lookup the URI based on the email.
+
+     @param emailAddress The email address of the contact.
+     @param lazyLookup If this is true, the lookup query will not be performed
+     until this view is clicked.
+     @param extras A bundle of extras to populate the contact edit page with if the contact
+     is not found and the user chooses to add the email address to an existing contact or
+     create a new contact. Uses the same string constants as those found in
+     {@link #ContactsContract.Intents.Insert}
+    */
+
+    public void assignContactFromEmail(String emailAddress, boolean lazyLookup, Bundle extras) {
         mContactEmail = emailAddress;
+        mExtras = extras;
         if (!lazyLookup) {
             mQueryHandler.startQuery(TOKEN_EMAIL_LOOKUP, null,
                     Uri.withAppendedPath(Email.CONTENT_LOOKUP_URI, Uri.encode(mContactEmail)),
@@ -186,6 +209,7 @@
         }
     }
 
+
     /**
      * Assign a contact based on a phone number. This should only be used when
      * the contact's URI is not available, as an extra query will have to be
@@ -196,7 +220,25 @@
      * until this view is clicked.
      */
     public void assignContactFromPhone(String phoneNumber, boolean lazyLookup) {
+        assignContactFromPhone(phoneNumber, lazyLookup, new Bundle());
+    }
+
+    /**
+     * Assign a contact based on a phone number. This should only be used when
+     * the contact's URI is not available, as an extra query will have to be
+     * performed to lookup the URI based on the phone number.
+     *
+     * @param phoneNumber The phone number of the contact.
+     * @param lazyLookup If this is true, the lookup query will not be performed
+     * until this view is clicked.
+     * @param extras A bundle of extras to populate the contact edit page with if the contact
+     * is not found and the user chooses to add the phone number to an existing contact or
+     * create a new contact. Uses the same string constants as those found in
+     * {@link #ContactsContract.Intents.Insert}
+     */
+    public void assignContactFromPhone(String phoneNumber, boolean lazyLookup, Bundle extras) {
         mContactPhone = phoneNumber;
+        mExtras = extras;
         if (!lazyLookup) {
             mQueryHandler.startQuery(TOKEN_PHONE_LOOKUP, null,
                     Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, mContactPhone),
@@ -213,15 +255,21 @@
 
     @Override
     public void onClick(View v) {
+        // If contact has been assigned, mExtras should no longer be null, but do a null check
+        // anyway just in case assignContactFromPhone or Email was called with a null bundle or
+        // wasn't assigned previously.
+        final Bundle extras = (mExtras == null) ? new Bundle() : mExtras;
         if (mContactUri != null) {
             QuickContact.showQuickContact(getContext(), QuickContactBadge.this, mContactUri,
                     QuickContact.MODE_LARGE, mExcludeMimes);
         } else if (mContactEmail != null) {
-            mQueryHandler.startQuery(TOKEN_EMAIL_LOOKUP_AND_TRIGGER, mContactEmail,
+            extras.putString(EXTRA_URI_CONTENT, mContactEmail);
+            mQueryHandler.startQuery(TOKEN_EMAIL_LOOKUP_AND_TRIGGER, extras,
                     Uri.withAppendedPath(Email.CONTENT_LOOKUP_URI, Uri.encode(mContactEmail)),
                     EMAIL_LOOKUP_PROJECTION, null, null, null);
         } else if (mContactPhone != null) {
-            mQueryHandler.startQuery(TOKEN_PHONE_LOOKUP_AND_TRIGGER, mContactPhone,
+            extras.putString(EXTRA_URI_CONTENT, mContactPhone);
+            mQueryHandler.startQuery(TOKEN_PHONE_LOOKUP_AND_TRIGGER, extras,
                     Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, mContactPhone),
                     PHONE_LOOKUP_PROJECTION, null, null, null);
         } else {
@@ -262,12 +310,12 @@
             Uri lookupUri = null;
             Uri createUri = null;
             boolean trigger = false;
-
+            Bundle extras = (cookie != null) ? (Bundle) cookie : new Bundle();
             try {
                 switch(token) {
                     case TOKEN_PHONE_LOOKUP_AND_TRIGGER:
                         trigger = true;
-                        createUri = Uri.fromParts("tel", (String)cookie, null);
+                        createUri = Uri.fromParts("tel", extras.getString(EXTRA_URI_CONTENT), null);
 
                         //$FALL-THROUGH$
                     case TOKEN_PHONE_LOOKUP: {
@@ -281,7 +329,8 @@
                     }
                     case TOKEN_EMAIL_LOOKUP_AND_TRIGGER:
                         trigger = true;
-                        createUri = Uri.fromParts("mailto", (String)cookie, null);
+                        createUri = Uri.fromParts("mailto",
+                                extras.getString(EXTRA_URI_CONTENT), null);
 
                         //$FALL-THROUGH$
                     case TOKEN_EMAIL_LOOKUP: {
@@ -309,6 +358,10 @@
             } else if (createUri != null) {
                 // Prompt user to add this person to contacts
                 final Intent intent = new Intent(Intents.SHOW_OR_CREATE_CONTACT, createUri);
+                if (extras != null) {
+                    extras.remove(EXTRA_URI_CONTENT);
+                    intent.putExtras(extras);
+                }
                 getContext().startActivity(intent);
             }
         }
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index d3ba11a..d705024 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -91,7 +91,7 @@
 	android/graphics/DrawFilter.cpp \
 	android/graphics/CreateJavaOutputStreamAdaptor.cpp \
 	android/graphics/Graphics.cpp \
-	android/graphics/HarfbuzzSkia.cpp \
+	android/graphics/HarfBuzzNGFaceSkia.cpp \
 	android/graphics/Interpolator.cpp \
 	android/graphics/LayerRasterizer.cpp \
 	android/graphics/MaskFilter.cpp \
@@ -170,8 +170,7 @@
 	external/icu4c/i18n \
 	external/icu4c/common \
 	external/jpeg \
-	external/harfbuzz/contrib \
-	external/harfbuzz/src \
+	external/harfbuzz_ng/src \
 	external/zlib \
 	frameworks/opt/emoji \
 	libcore/include
@@ -206,7 +205,7 @@
 	libwpa_client \
 	libjpeg \
 	libusbhost \
-	libharfbuzz \
+	libharfbuzz_ng \
 	libz
 
 ifeq ($(USE_OPENGL_RENDERER),true)
diff --git a/core/jni/android/graphics/HarfBuzzNGFaceSkia.cpp b/core/jni/android/graphics/HarfBuzzNGFaceSkia.cpp
new file mode 100644
index 0000000..1752e5b
--- /dev/null
+++ b/core/jni/android/graphics/HarfBuzzNGFaceSkia.cpp
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2012 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define LOG_TAG "TextLayoutCache"
+
+#include "HarfBuzzNGFaceSkia.h"
+
+#include <cutils/log.h>
+#include <SkFontHost.h>
+#include <SkPaint.h>
+#include <SkPath.h>
+#include <SkPoint.h>
+#include <SkRect.h>
+#include <SkUtils.h>
+
+#include <hb.h>
+
+namespace android {
+
+// Our implementation of the callbacks which Harfbuzz requires by using Skia
+// calls. See the Harfbuzz source for references about what these callbacks do.
+
+struct HarfBuzzFontData {
+    HarfBuzzFontData(SkPaint* paint) : m_paint(paint) { }
+    SkPaint* m_paint;
+};
+
+static void SkiaGetGlyphWidthAndExtents(SkPaint* paint, hb_codepoint_t codepoint, hb_position_t* width, hb_glyph_extents_t* extents)
+{
+    ALOG_ASSERT(codepoint <= 0xFFFF);
+    paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+
+    SkScalar skWidth;
+    SkRect skBounds;
+    uint16_t glyph = codepoint;
+
+    paint->getTextWidths(&glyph, sizeof(glyph), &skWidth, &skBounds);
+    ALOGD("returned glyph for %i: width = %f", codepoint, skWidth);
+    if (width)
+        *width = SkScalarToHBFixed(skWidth);
+    if (extents) {
+        // Invert y-axis because Skia is y-grows-down but we set up harfbuzz to be y-grows-up.
+        extents->x_bearing = SkScalarToHBFixed(skBounds.fLeft);
+        extents->y_bearing = SkScalarToHBFixed(-skBounds.fTop);
+        extents->width = SkScalarToHBFixed(skBounds.width());
+        extents->height = SkScalarToHBFixed(-skBounds.height());
+    }
+}
+
+static hb_bool_t harfbuzzGetGlyph(hb_font_t* hbFont, void* fontData, hb_codepoint_t unicode, hb_codepoint_t variationSelector, hb_codepoint_t* glyph, void* userData)
+{
+    HarfBuzzFontData* hbFontData = reinterpret_cast<HarfBuzzFontData*>(fontData);
+
+    if (unicode > 0x10ffff) {
+        unicode = 0xfffd;
+    }
+    SkPaint* paint = hbFontData->m_paint;
+    // It would be better to use kUTF32_TextEncoding directly
+    paint->setTextEncoding(SkPaint::kUTF16_TextEncoding);
+    uint16_t glyph16;
+    uint16_t unichar[2];
+    size_t size = SkUTF16_FromUnichar(unicode, unichar);
+    paint->textToGlyphs(unichar, size * sizeof(*unichar), &glyph16);
+    *glyph = glyph16;
+    return !!*glyph;
+}
+
+static hb_position_t harfbuzzGetGlyphHorizontalAdvance(hb_font_t* hbFont, void* fontData, hb_codepoint_t glyph, void* userData)
+{
+    HarfBuzzFontData* hbFontData = reinterpret_cast<HarfBuzzFontData*>(fontData);
+    hb_position_t advance = 0;
+
+    SkiaGetGlyphWidthAndExtents(hbFontData->m_paint, glyph, &advance, 0);
+    return advance;
+}
+
+static hb_bool_t harfbuzzGetGlyphHorizontalOrigin(hb_font_t* hbFont, void* fontData, hb_codepoint_t glyph, hb_position_t* x, hb_position_t* y, void* userData)
+{
+    // Just return true, following the way that Harfbuzz-FreeType
+    // implementation does.
+    return true;
+}
+
+static hb_bool_t harfbuzzGetGlyphExtents(hb_font_t* hbFont, void* fontData, hb_codepoint_t glyph, hb_glyph_extents_t* extents, void* userData)
+{
+    HarfBuzzFontData* hbFontData = reinterpret_cast<HarfBuzzFontData*>(fontData);
+
+    SkiaGetGlyphWidthAndExtents(hbFontData->m_paint, glyph, 0, extents);
+    return true;
+}
+
+static hb_font_funcs_t* harfbuzzSkiaGetFontFuncs()
+{
+    static hb_font_funcs_t* harfbuzzSkiaFontFuncs = 0;
+
+    // We don't set callback functions which we can't support.
+    // Harfbuzz will use the fallback implementation if they aren't set.
+    if (!harfbuzzSkiaFontFuncs) {
+        harfbuzzSkiaFontFuncs = hb_font_funcs_create();
+        hb_font_funcs_set_glyph_func(harfbuzzSkiaFontFuncs, harfbuzzGetGlyph, 0, 0);
+        hb_font_funcs_set_glyph_h_advance_func(harfbuzzSkiaFontFuncs, harfbuzzGetGlyphHorizontalAdvance, 0, 0);
+        hb_font_funcs_set_glyph_h_origin_func(harfbuzzSkiaFontFuncs, harfbuzzGetGlyphHorizontalOrigin, 0, 0);
+        hb_font_funcs_set_glyph_extents_func(harfbuzzSkiaFontFuncs, harfbuzzGetGlyphExtents, 0, 0);
+        hb_font_funcs_make_immutable(harfbuzzSkiaFontFuncs);
+    }
+    return harfbuzzSkiaFontFuncs;
+}
+
+hb_blob_t* harfbuzzSkiaReferenceTable(hb_face_t* face, hb_tag_t tag, void* userData)
+{
+    SkTypeface* typeface = reinterpret_cast<SkTypeface*>(userData);
+    SkFontID uniqueID = typeface->uniqueID();
+
+    const size_t tableSize = SkFontHost::GetTableSize(uniqueID, tag);
+    if (!tableSize)
+        return 0;
+
+    char* buffer = reinterpret_cast<char*>(malloc(tableSize));
+    if (!buffer)
+        return 0;
+    size_t actualSize = SkFontHost::GetTableData(uniqueID, tag, 0, tableSize, buffer);
+    if (tableSize != actualSize) {
+        free(buffer);
+        return 0;
+    }
+
+    return hb_blob_create(const_cast<char*>(buffer), tableSize,
+                          HB_MEMORY_MODE_WRITABLE, buffer, free);
+}
+
+static void destroyHarfBuzzFontData(void* data) {
+    delete (HarfBuzzFontData*)data;
+}
+
+hb_font_t* createFont(hb_face_t* face, SkPaint* paint, float sizeX, float sizeY) {
+    hb_font_t* font = hb_font_create(face);
+    
+    // Note: this needs to be reworked when we do subpixels
+    int x_ppem = floor(sizeX + 0.5);
+    int y_ppem = floor(sizeY + 0.5);
+    hb_font_set_ppem(font, x_ppem, y_ppem); 
+    hb_font_set_scale(font, HBFloatToFixed(sizeX), HBFloatToFixed(sizeY));
+
+    HarfBuzzFontData* data = new HarfBuzzFontData(paint);
+    hb_font_set_funcs(font, harfbuzzSkiaGetFontFuncs(), data, destroyHarfBuzzFontData);
+
+    return font;
+}
+
+} // namespace android
diff --git a/core/jni/android/graphics/HarfbuzzSkia.h b/core/jni/android/graphics/HarfBuzzNGFaceSkia.h
similarity index 71%
rename from core/jni/android/graphics/HarfbuzzSkia.h
rename to core/jni/android/graphics/HarfBuzzNGFaceSkia.h
index 2772f4d..23ec81a 100644
--- a/core/jni/android/graphics/HarfbuzzSkia.h
+++ b/core/jni/android/graphics/HarfBuzzNGFaceSkia.h
@@ -24,31 +24,35 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef HarfbuzzSkia_h
-#define HarfbuzzSkia_h
+#ifndef HarfBuzzNGFaceSkia_h
+#define HarfBuzzNGFaceSkia_h
 
-#include "SkScalar.h"
-#include "SkTypeface.h"
-#include "SkPaint.h"
+#include <SkScalar.h>
+#include <SkPaint.h>
 
-extern "C" {
-#include "harfbuzz-shaper.h"
-}
+#include <hb.h>
 
 namespace android {
 
-static inline float HBFixedToFloat(HB_Fixed v) {
-    // Harfbuzz uses 26.6 fixed point values for pixel offsets
-    return v * (1.0f / 64);
+static inline float
+HBFixedToFloat (hb_position_t v)
+{
+    return scalblnf (v, -8);
 }
 
-static inline HB_Fixed SkScalarToHBFixed(SkScalar value) {
-    // HB_Fixed is a 26.6 fixed point format.
-    return SkScalarToFloat(value) * 64.0f;
+static inline hb_position_t
+HBFloatToFixed (float v)
+{
+    return scalblnf (v, +8);
 }
 
-HB_Error harfbuzzSkiaGetTable(void* voidface, const HB_Tag, HB_Byte* buffer, HB_UInt* len);
-extern const HB_FontClass harfbuzzSkiaClass;
+static inline hb_position_t SkScalarToHBFixed(SkScalar value) {
+    return HBFloatToFixed(SkScalarToFloat(value));
+}
+
+hb_blob_t* harfbuzzSkiaReferenceTable(hb_face_t* face, hb_tag_t tag, void* userData);
+
+hb_font_t* createFont(hb_face_t* face, SkPaint* paint, float sizeX, float sizeY);
 
 }  // namespace android
 
diff --git a/core/jni/android/graphics/HarfbuzzSkia.cpp b/core/jni/android/graphics/HarfbuzzSkia.cpp
deleted file mode 100644
index 7e08379..0000000
--- a/core/jni/android/graphics/HarfbuzzSkia.cpp
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * Copyright 2011, The Android Open Source Project
- * Copyright 2011, Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#define LOG_TAG "HarfbuzzSkia"
-
-#include "HarfbuzzSkia.h"
-
-#include "SkFontHost.h"
-
-#include "SkPaint.h"
-#include "SkPath.h"
-#include "SkPoint.h"
-#include "SkRect.h"
-#include "SkTypeface.h"
-
-#include <utils/Log.h>
-
-extern "C" {
-#include "harfbuzz-shaper.h"
-}
-
-// This file implements the callbacks which Harfbuzz requires by using Skia
-// calls. See the Harfbuzz source for references about what these callbacks do.
-
-namespace android {
-
-static HB_Bool stringToGlyphs(HB_Font hbFont, const HB_UChar16* characters, hb_uint32 length,
-        HB_Glyph* glyphs, hb_uint32* glyphsSize, HB_Bool isRTL)
-{
-    SkPaint* paint = static_cast<SkPaint*>(hbFont->userData);
-    paint->setTextEncoding(SkPaint::kUTF16_TextEncoding);
-
-    uint16_t* skiaGlyphs = reinterpret_cast<uint16_t*>(glyphs);
-    int numGlyphs = paint->textToGlyphs(characters, length * sizeof(uint16_t), skiaGlyphs);
-
-    // HB_Glyph is 32-bit, but Skia outputs only 16-bit numbers. So our
-    // |glyphs| array needs to be converted.
-    for (int i = numGlyphs - 1; i >= 0; --i) {
-        glyphs[i] = skiaGlyphs[i];
-    }
-
-    *glyphsSize = numGlyphs;
-    return 1;
-}
-
-static void glyphsToAdvances(HB_Font hbFont, const HB_Glyph* glyphs, hb_uint32 numGlyphs,
-        HB_Fixed* advances, int flags)
-{
-    SkPaint* paint = static_cast<SkPaint*>(hbFont->userData);
-    paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding);
-
-    uint16_t* glyphs16 = new uint16_t[numGlyphs];
-    if (!glyphs16)
-        return;
-    for (unsigned i = 0; i < numGlyphs; ++i)
-        glyphs16[i] = glyphs[i];
-    SkScalar* scalarAdvances = reinterpret_cast<SkScalar*>(advances);
-    paint->getTextWidths(glyphs16, numGlyphs * sizeof(uint16_t), scalarAdvances);
-
-    // The |advances| values which Skia outputs are SkScalars, which are floats
-    // in Chromium. However, Harfbuzz wants them in 26.6 fixed point format.
-    // These two formats are both 32-bits long.
-    for (unsigned i = 0; i < numGlyphs; ++i) {
-        advances[i] = SkScalarToHBFixed(scalarAdvances[i]);
-#if DEBUG_ADVANCES
-        ALOGD("glyphsToAdvances -- advances[%d]=%d", i, advances[i]);
-#endif
-    }
-    delete glyphs16;
-}
-
-static HB_Bool canRender(HB_Font hbFont, const HB_UChar16* characters, hb_uint32 length)
-{
-    SkPaint* paint = static_cast<SkPaint*>(hbFont->userData);
-    paint->setTextEncoding(SkPaint::kUTF16_TextEncoding);
-
-    uint16_t* glyphs16 = new uint16_t[length];
-    int numGlyphs = paint->textToGlyphs(characters, length * sizeof(uint16_t), glyphs16);
-
-    bool result = true;
-    for (int i = 0; i < numGlyphs; ++i) {
-        if (!glyphs16[i]) {
-            result = false;
-            break;
-        }
-    }
-    delete glyphs16;
-    return result;
-}
-
-static HB_Error getOutlinePoint(HB_Font hbFont, HB_Glyph glyph, int flags, hb_uint32 point,
-        HB_Fixed* xPos, HB_Fixed* yPos, hb_uint32* resultingNumPoints)
-{
-    if (flags & HB_ShaperFlag_UseDesignMetrics)
-        // This is requesting pre-hinted positions. We can't support this.
-        return HB_Err_Invalid_Argument;
-
-    SkPaint* paint = static_cast<SkPaint*>(hbFont->userData);
-    paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding);
-
-    uint16_t glyph16 = glyph;
-    SkPath path;
-    paint->getTextPath(&glyph16, sizeof(glyph16), 0, 0, &path);
-    uint32_t numPoints = path.getPoints(0, 0);
-    if (point >= numPoints)
-        return HB_Err_Invalid_SubTable;
-    SkPoint* points = static_cast<SkPoint*>(malloc(sizeof(SkPoint) * (point + 1)));
-    if (!points)
-        return HB_Err_Invalid_SubTable;
-    // Skia does let us get a single point from the path.
-    path.getPoints(points, point + 1);
-    *xPos = SkScalarToHBFixed(points[point].fX);
-    *yPos = SkScalarToHBFixed(points[point].fY);
-    *resultingNumPoints = numPoints;
-    delete points;
-
-    return HB_Err_Ok;
-}
-
-static void getGlyphMetrics(HB_Font hbFont, HB_Glyph glyph, HB_GlyphMetrics* metrics)
-{
-    SkPaint* paint = static_cast<SkPaint*>(hbFont->userData);
-    paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding);
-
-    uint16_t glyph16 = glyph;
-    SkScalar width;
-    SkRect bounds;
-    paint->getTextWidths(&glyph16, sizeof(glyph16), &width, &bounds);
-
-    metrics->x = SkScalarToHBFixed(bounds.fLeft);
-    metrics->y = SkScalarToHBFixed(bounds.fTop);
-    metrics->width = SkScalarToHBFixed(bounds.width());
-    metrics->height = SkScalarToHBFixed(bounds.height());
-
-    metrics->xOffset = SkScalarToHBFixed(width);
-    // We can't actually get the |y| correct because Skia doesn't export
-    // the vertical advance. However, nor we do ever render vertical text at
-    // the moment so it's unimportant.
-    metrics->yOffset = 0;
-}
-
-static HB_Fixed getFontMetric(HB_Font hbFont, HB_FontMetric metric)
-{
-    SkPaint* paint = static_cast<SkPaint*>(hbFont->userData);
-
-    SkPaint::FontMetrics skiaMetrics;
-    paint->getFontMetrics(&skiaMetrics);
-
-    switch (metric) {
-    case HB_FontAscent:
-        return SkScalarToHBFixed(-skiaMetrics.fAscent);
-    // We don't support getting the rest of the metrics and Harfbuzz doesn't seem to need them.
-    default:
-        return 0;
-    }
-    return 0;
-}
-
-const HB_FontClass harfbuzzSkiaClass = {
-    stringToGlyphs,
-    glyphsToAdvances,
-    canRender,
-    getOutlinePoint,
-    getGlyphMetrics,
-    getFontMetric,
-};
-
-HB_Error harfbuzzSkiaGetTable(void* font, const HB_Tag tag, HB_Byte* buffer, HB_UInt* len)
-{
-    SkTypeface* typeface = static_cast<SkTypeface*>(font);
-
-    if (!typeface) {
-        ALOGD("Typeface cannot be null");
-        return HB_Err_Invalid_Argument;
-    }
-    const size_t tableSize = SkFontHost::GetTableSize(typeface->uniqueID(), tag);
-    if (!tableSize)
-        return HB_Err_Invalid_Argument;
-    // If Harfbuzz specified a NULL buffer then it's asking for the size of the table.
-    if (!buffer) {
-        *len = tableSize;
-        return HB_Err_Ok;
-    }
-
-    if (*len < tableSize)
-        return HB_Err_Invalid_Argument;
-    SkFontHost::GetTableData(typeface->uniqueID(), tag, 0, tableSize, buffer);
-    return HB_Err_Ok;
-}
-
-}  // namespace android
diff --git a/core/jni/android/graphics/TextLayoutCache.cpp b/core/jni/android/graphics/TextLayoutCache.cpp
index dce48a3..d7df402 100644
--- a/core/jni/android/graphics/TextLayoutCache.cpp
+++ b/core/jni/android/graphics/TextLayoutCache.cpp
@@ -22,13 +22,10 @@
 #include "TextLayout.h"
 #include "SkFontHost.h"
 #include "SkTypeface_android.h"
+#include "HarfBuzzNGFaceSkia.h"
 #include <unicode/unistr.h>
-#include <unicode/normlzr.h>
 #include <unicode/uchar.h>
-
-extern "C" {
-  #include "harfbuzz-unicode.h"
-}
+#include <hb-icu.h>
 
 namespace android {
 
@@ -341,20 +338,10 @@
     return mElapsedTime;
 }
 
-TextLayoutShaper::TextLayoutShaper() : mShaperItemGlyphArraySize(0) {
+TextLayoutShaper::TextLayoutShaper() {
     init();
 
-    mFontRec.klass = &harfbuzzSkiaClass;
-    mFontRec.userData = 0;
-
-    // Note that the scaling values (x_ and y_ppem, x_ and y_scale) will be set
-    // below, when the paint transform and em unit of the actual shaping font
-    // are known.
-
-    memset(&mShaperItem, 0, sizeof(mShaperItem));
-
-    mShaperItem.font = &mFontRec;
-    mShaperItem.font->userData = &mShapingPaint;
+    mBuffer = hb_buffer_create();
 }
 
 void TextLayoutShaper::init() {
@@ -366,8 +353,9 @@
 }
 
 TextLayoutShaper::~TextLayoutShaper() {
+    hb_buffer_destroy(mBuffer);
+
     unrefTypefaces();
-    deleteShaperItemGlyphArrays();
 }
 
 void TextLayoutShaper::computeValues(TextLayoutValue* value, const SkPaint* paint, const UChar* chars,
@@ -394,7 +382,7 @@
         bool forceLTR = false;
         bool forceRTL = false;
 
-        switch (dirFlags) {
+        switch (dirFlags & kBidi_Mask) {
             case kBidi_LTR: bidiReq = 0; break; // no ICU constant, canonical LTR level
             case kBidi_RTL: bidiReq = 1; break; // no ICU constant, canonical RTL level
             case kBidi_Default_LTR: bidiReq = UBIDI_DEFAULT_LTR; break;
@@ -478,7 +466,7 @@
                             ALOGD("Processing Bidi Run = %d -- run-start = %d, run-len = %d, isRTL = %d",
                                     i, startRun, lengthRun, isRTL);
 #endif
-                            computeRunValues(paint, chars + startRun, lengthRun, isRTL,
+                            computeRunValues(paint, chars, startRun, lengthRun, contextCount, isRTL,
                                     outAdvances, outTotalAdvance, outGlyphs, outPos);
 
                         }
@@ -502,7 +490,7 @@
             ALOGD("Using a SINGLE BiDi Run "
                     "-- run-start = %d, run-len = %d, isRTL = %d", start, count, isRTL);
 #endif
-            computeRunValues(paint, chars + start, count, isRTL,
+            computeRunValues(paint, chars, start, count, contextCount, isRTL,
                     outAdvances, outTotalAdvance, outGlyphs, outPos);
         }
 
@@ -512,18 +500,197 @@
 #endif
 }
 
-static void logGlyphs(HB_ShaperItem shaperItem) {
-    ALOGD("         -- glyphs count=%d", shaperItem.num_glyphs);
-    for (size_t i = 0; i < shaperItem.num_glyphs; i++) {
-        ALOGD("         -- glyph[%d] = %d, offset.x = %0.2f, offset.y = %0.2f", i,
-                shaperItem.glyphs[i],
-                HBFixedToFloat(shaperItem.offsets[i].x),
-                HBFixedToFloat(shaperItem.offsets[i].y));
+#define HB_IsHighSurrogate(ucs) \
+    (((ucs) & 0xfc00) == 0xd800)
+
+#define HB_IsLowSurrogate(ucs) \
+    (((ucs) & 0xfc00) == 0xdc00)
+
+#ifndef HB_SurrogateToUcs4
+#define HB_SurrogateToUcs4_(high, low) \
+    (((hb_codepoint_t)(high))<<10) + (low) - 0x35fdc00;
+#endif
+
+#define HB_InvalidCodePoint ~0u
+
+hb_codepoint_t
+utf16_to_code_point(const uint16_t *chars, size_t len, ssize_t *iter) {
+  const uint16_t v = chars[(*iter)++];
+  if (HB_IsHighSurrogate(v)) {
+    // surrogate pair
+    if (size_t(*iter) >= len) {
+      // the surrogate is incomplete.
+      return HB_InvalidCodePoint;
+    }
+    const uint16_t v2 = chars[(*iter)++];
+    if (!HB_IsLowSurrogate(v2)) {
+      // invalidate surrogate pair.
+      (*iter)--;
+      return HB_InvalidCodePoint;
+    }
+
+    return HB_SurrogateToUcs4(v, v2);
+  }
+
+  if (HB_IsLowSurrogate(v)) {
+    // this isn't a valid code point
+    return HB_InvalidCodePoint;
+  }
+
+  return v;
+}
+
+hb_codepoint_t
+utf16_to_code_point_prev(const uint16_t *chars, size_t len, ssize_t *iter) {
+  const uint16_t v = chars[(*iter)--];
+  if (HB_IsLowSurrogate(v)) {
+    // surrogate pair
+    if (*iter < 0) {
+      // the surrogate is incomplete.
+      return HB_InvalidCodePoint;
+    }
+    const uint16_t v2 = chars[(*iter)--];
+    if (!HB_IsHighSurrogate(v2)) {
+      // invalidate surrogate pair.
+      (*iter)++;
+      return HB_InvalidCodePoint;
+    }
+
+    return HB_SurrogateToUcs4(v2, v);
+  }
+
+  if (HB_IsHighSurrogate(v)) {
+    // this isn't a valid code point
+    return HB_InvalidCodePoint;
+  }
+
+  return v;
+}
+
+struct ScriptRun {
+    hb_script_t script;
+    size_t pos;
+    size_t length;
+};
+
+hb_script_t code_point_to_script(hb_codepoint_t codepoint) {
+    static hb_unicode_funcs_t* u;
+    if (!u) {
+        u = hb_icu_get_unicode_funcs();
+    }
+    return hb_unicode_script(u, codepoint);
+}
+
+bool
+hb_utf16_script_run_next(ScriptRun* run, const uint16_t *chars, size_t len, ssize_t *iter) {
+  if (size_t(*iter) == len)
+    return false;
+
+  run->pos = *iter;
+  const uint32_t init_cp = utf16_to_code_point(chars, len, iter);
+  const hb_script_t init_script = code_point_to_script(init_cp);
+  hb_script_t current_script = init_script;
+  run->script = init_script;
+
+  for (;;) {
+    if (size_t(*iter) == len)
+      break;
+    const ssize_t prev_iter = *iter;
+    const uint32_t cp = utf16_to_code_point(chars, len, iter);
+    const hb_script_t script = code_point_to_script(cp);
+
+    if (script != current_script) {
+        /* BEGIN android-changed
+           The condition was not correct by doing "a == b == constant"
+           END android-changed */
+      if (current_script == HB_SCRIPT_INHERITED && init_script == HB_SCRIPT_INHERITED) {
+        // If we started off as inherited, we take whatever we can find.
+        run->script = script;
+        current_script = script;
+        continue;
+      } else if (script == HB_SCRIPT_INHERITED) {
+        continue;
+      } else {
+        *iter = prev_iter;
+        break;
+      }
+    }
+  }
+
+  if (run->script == HB_SCRIPT_INHERITED)
+    run->script = HB_SCRIPT_COMMON;
+
+  run->length = *iter - run->pos;
+  return true;
+}
+
+bool
+hb_utf16_script_run_prev(ScriptRun* run, const uint16_t *chars, size_t len, ssize_t *iter) {
+  if (*iter == -1)
+    return false;
+
+  const size_t ending_index = *iter;
+  const uint32_t init_cp = utf16_to_code_point_prev(chars, len, iter);
+  const hb_script_t init_script = code_point_to_script(init_cp);
+  hb_script_t current_script = init_script;
+  run->script = init_script;
+
+  for (;;) {
+    if (*iter < 0)
+      break;
+    const ssize_t prev_iter = *iter;
+    const uint32_t cp = utf16_to_code_point_prev(chars, len, iter);
+    const hb_script_t script = code_point_to_script(cp);
+
+    if (script != current_script) {
+      if (current_script == HB_SCRIPT_INHERITED && init_script == HB_SCRIPT_INHERITED) {
+        // If we started off as inherited, we take whatever we can find.
+        run->script = script;
+        current_script = script;
+        continue;
+      } else if (script == HB_SCRIPT_INHERITED) {
+        /* BEGIN android-changed
+           We apply the same fix for Chrome to Android.
+           Chrome team will talk with upsteam about it.
+           Just assume that whatever follows this combining character is within
+           the same script.  This is incorrect if you had language1 + combining
+           char + language 2, but that is rare and this code is suspicious
+           anyway.
+           END android-changed */
+        continue;
+      } else {
+        *iter = prev_iter;
+        break;
+      }
+    }
+  }
+
+  if (run->script == HB_SCRIPT_INHERITED)
+    run->script = HB_SCRIPT_COMMON;
+
+  run->pos = *iter + 1;
+  run->length = ending_index - *iter;
+  return true;
+}
+
+
+static void logGlyphs(hb_buffer_t* buffer) {
+    unsigned int numGlyphs;
+    hb_glyph_info_t* info = hb_buffer_get_glyph_infos(buffer, &numGlyphs);
+    hb_glyph_position_t* positions = hb_buffer_get_glyph_positions(buffer, NULL);
+    ALOGD("         -- glyphs count=%d", numGlyphs);
+    for (size_t i = 0; i < numGlyphs; i++) {
+        ALOGD("         -- glyph[%d] = %d, cluster = %u, advance = %0.2f, offset.x = %0.2f, offset.y = %0.2f", i,
+                info[i].codepoint,
+                info[i].cluster,
+                HBFixedToFloat(positions[i].x_advance),
+                HBFixedToFloat(positions[i].x_offset),
+                HBFixedToFloat(positions[i].y_offset));
     }
 }
 
-void TextLayoutShaper::computeRunValues(const SkPaint* paint, const UChar* chars,
-        size_t count, bool isRTL,
+void TextLayoutShaper::computeRunValues(const SkPaint* paint, const UChar* contextChars,
+        size_t start, size_t count, size_t contextCount, bool isRTL,
         Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance,
         Vector<jchar>* const outGlyphs, Vector<jfloat>* const outPos) {
     if (!count) {
@@ -535,95 +702,9 @@
     for (size_t i = 0; i < count; i++) {
         outAdvances->add(0);
     }
-    UErrorCode error = U_ZERO_ERROR;
-    bool useNormalizedString = false;
-    for (ssize_t i = count - 1; i >= 0; --i) {
-        UChar ch1 = chars[i];
-        if (::ublock_getCode(ch1) == UBLOCK_COMBINING_DIACRITICAL_MARKS) {
-            // So we have found a diacritic, let's get now the main code point which is paired
-            // with it. As we can have several diacritics in a row, we need to iterate back again
-#if DEBUG_GLYPHS
-            ALOGD("The BiDi run '%s' is containing a Diacritic at position %d",
-                    String8(chars, count).string(), int(i));
-#endif
-            ssize_t j = i - 1;
-            for (; j >= 0;  --j) {
-                UChar ch2 = chars[j];
-                if (::ublock_getCode(ch2) != UBLOCK_COMBINING_DIACRITICAL_MARKS) {
-                    break;
-                }
-            }
-
-            // We could not found the main code point, so we will just use the initial chars
-            if (j < 0) {
-                break;
-            }
-
-#if DEBUG_GLYPHS
-            ALOGD("Found main code point at index %d", int(j));
-#endif
-            // We found the main code point, so we can normalize the "chunk" and fill
-            // the remaining with ZWSP so that the Paint.getTextWidth() APIs will still be able
-            // to get one advance per char
-            mBuffer.remove();
-            Normalizer::normalize(UnicodeString(chars + j, i - j + 1),
-                    UNORM_NFC, 0 /* no options */, mBuffer, error);
-            if (U_SUCCESS(error)) {
-                if (!useNormalizedString) {
-                    useNormalizedString = true;
-                    mNormalizedString.setTo(false /* not terminated*/, chars, count);
-                }
-                // Set the normalized chars
-                for (ssize_t k = j; k < j + mBuffer.length(); ++k) {
-                    mNormalizedString.setCharAt(k, mBuffer.charAt(k - j));
-                }
-                // Fill the remain part with ZWSP (ZWNJ and ZWJ would lead to weird results
-                // because some fonts are missing those glyphs)
-                for (ssize_t k = j + mBuffer.length(); k <= i; ++k) {
-                    mNormalizedString.setCharAt(k, UNICODE_ZWSP);
-                }
-            }
-            i = j - 1;
-        }
-    }
-
-    // Reverse "BiDi mirrored chars" in RTL mode only
-    // See: http://www.unicode.org/Public/6.0.0/ucd/extracted/DerivedBinaryProperties.txt
-    // This is a workaround because Harfbuzz is not able to do mirroring in all cases and
-    // script-run splitting with Harfbuzz is splitting on parenthesis
-    if (isRTL) {
-        for (ssize_t i = 0; i < ssize_t(count); i++) {
-            UChar32 ch = chars[i];
-            if (!u_isMirrored(ch)) continue;
-            if (!useNormalizedString) {
-                useNormalizedString = true;
-                mNormalizedString.setTo(false /* not terminated*/, chars, count);
-            }
-            UChar result =  (UChar) u_charMirror(ch);
-            mNormalizedString.setCharAt(i, result);
-#if DEBUG_GLYPHS
-            ALOGD("Rewriting codepoint '%d' to '%d' at position %d",
-                    ch, mNormalizedString[i], int(i));
-#endif
-        }
-    }
-
-#if DEBUG_GLYPHS
-    if (useNormalizedString) {
-        ALOGD("Will use normalized string '%s', length = %d",
-                    String8(mNormalizedString.getTerminatedBuffer(),
-                            mNormalizedString.length()).string(),
-                    mNormalizedString.length());
-    } else {
-        ALOGD("Normalization is not needed or cannot be done, using initial string");
-    }
-#endif
-
-    assert(mNormalizedString.length() == count);
 
     // Set the string properties
-    mShaperItem.string = useNormalizedString ? mNormalizedString.getTerminatedBuffer() : chars;
-    mShaperItem.stringLength = count;
+    const UChar* chars = contextChars + start;
 
     // Define shaping paint properties
     mShapingPaint.setTextSize(paint->getTextSize());
@@ -637,130 +718,66 @@
 
     // Split the BiDi run into Script runs. Harfbuzz will populate the pos, length and script
     // into the shaperItem
-    ssize_t indexFontRun = isRTL ? mShaperItem.stringLength - 1 : 0;
-    unsigned numCodePoints = 0;
+    ssize_t indexFontRun = isRTL ? count - 1 : 0;
     jfloat totalAdvance = *outTotalAdvance;
+    ScriptRun run;  // relative to chars
     while ((isRTL) ?
-            hb_utf16_script_run_prev(&numCodePoints, &mShaperItem.item, mShaperItem.string,
-                    mShaperItem.stringLength, &indexFontRun):
-            hb_utf16_script_run_next(&numCodePoints, &mShaperItem.item, mShaperItem.string,
-                    mShaperItem.stringLength, &indexFontRun)) {
-
-        ssize_t startScriptRun = mShaperItem.item.pos;
-        size_t countScriptRun = mShaperItem.item.length;
-        ssize_t endScriptRun = startScriptRun + countScriptRun;
+            hb_utf16_script_run_prev(&run, chars, count, &indexFontRun):
+            hb_utf16_script_run_next(&run, chars, count, &indexFontRun)) {
 
 #if DEBUG_GLYPHS
         ALOGD("-------- Start of Script Run --------");
         ALOGD("Shaping Script Run with");
         ALOGD("         -- isRTL = %d", isRTL);
-        ALOGD("         -- HB script = %d", mShaperItem.item.script);
-        ALOGD("         -- startFontRun = %d", int(startScriptRun));
-        ALOGD("         -- endFontRun = %d", int(endScriptRun));
-        ALOGD("         -- countFontRun = %d", countScriptRun);
-        ALOGD("         -- run = '%s'", String8(chars + startScriptRun, countScriptRun).string());
+        ALOGD("         -- HB script = %c%c%c%c", HB_UNTAG(run.script));
+        ALOGD("         -- run.pos = %d", int(run.pos));
+        ALOGD("         -- run.length = %d", int(run.length));
+        ALOGD("         -- run = '%s'", String8(chars + run.pos, run.length).string());
         ALOGD("         -- string = '%s'", String8(chars, count).string());
 #endif
 
+        hb_buffer_reset(mBuffer);
+        // Note: if we want to set unicode functions, etc., this is the place.
+        
+        hb_buffer_set_direction(mBuffer, isRTL ? HB_DIRECTION_RTL : HB_DIRECTION_LTR);
+        hb_buffer_set_script(mBuffer, run.script);
+        // Should set language here (for bug 7004056)
+        hb_buffer_add_utf16(mBuffer, contextChars, contextCount, start + run.pos, run.length);
+
         // Initialize Harfbuzz Shaper and get the base glyph count for offsetting the glyphIDs
         // and shape the Font run
-        size_t glyphBaseCount = shapeFontRun(paint, isRTL);
+        size_t glyphBaseCount = shapeFontRun(paint);
+        unsigned int numGlyphs;
+        hb_glyph_info_t* info = hb_buffer_get_glyph_infos(mBuffer, &numGlyphs);
+        hb_glyph_position_t* positions = hb_buffer_get_glyph_positions(mBuffer, NULL);
 
 #if DEBUG_GLYPHS
         ALOGD("Got from Harfbuzz");
         ALOGD("         -- glyphBaseCount = %d", glyphBaseCount);
-        ALOGD("         -- num_glypth = %d", mShaperItem.num_glyphs);
-        ALOGD("         -- kerning_applied = %d", mShaperItem.kerning_applied);
+        ALOGD("         -- num_glyph = %d", numGlyphs);
         ALOGD("         -- isDevKernText = %d", paint->isDevKernText());
+        ALOGD("         -- initial totalAdvance = %f", totalAdvance);
 
-        logGlyphs(mShaperItem);
+        logGlyphs(mBuffer);
 #endif
 
-        if (mShaperItem.advances == NULL || mShaperItem.num_glyphs == 0) {
-#if DEBUG_GLYPHS
-            ALOGD("Advances array is empty or num_glypth = 0");
-#endif
-            continue;
+        for (size_t i = 0; i < numGlyphs; i++) {
+            size_t cluster = info[i].cluster - start;
+            float xAdvance = HBFixedToFloat(positions[i].x_advance);
+            outAdvances->replaceAt(outAdvances->itemAt(cluster) + xAdvance, cluster);
+            outGlyphs->add(info[i].codepoint + glyphBaseCount);
+            float xo = HBFixedToFloat(positions[i].x_offset);
+            float yo = -HBFixedToFloat(positions[i].y_offset);
+            outPos->add(totalAdvance + xo + yo * skewX);
+            outPos->add(yo);
+            totalAdvance += xAdvance;
         }
-
-#if DEBUG_GLYPHS
-        ALOGD("Returned logclusters");
-        for (size_t i = 0; i < mShaperItem.num_glyphs; i++) {
-            ALOGD("         -- lc[%d] = %d, hb-adv[%d] = %0.2f", i, mShaperItem.log_clusters[i],
-                    i, HBFixedToFloat(mShaperItem.advances[i]));
-        }
-#endif
-        jfloat totalFontRunAdvance = 0;
-        size_t clusterStart = 0;
-        for (size_t i = 0; i < countScriptRun; i++) {
-            size_t cluster = mShaperItem.log_clusters[i];
-            size_t clusterNext = i == countScriptRun - 1 ? mShaperItem.num_glyphs :
-                mShaperItem.log_clusters[i + 1];
-            if (cluster != clusterNext) {
-                jfloat advance = 0;
-                // The advance for the cluster is the sum of the advances of all glyphs within
-                // the cluster.
-                for (size_t j = cluster; j < clusterNext; j++) {
-                    advance += HBFixedToFloat(mShaperItem.advances[j]);
-                }
-                totalFontRunAdvance += advance;
-                outAdvances->replaceAt(advance, startScriptRun + clusterStart);
-                clusterStart = i + 1;
-            }
-        }
-
-#if DEBUG_ADVANCES
-        ALOGD("Returned advances");
-        for (size_t i = 0; i < countScriptRun; i++) {
-            ALOGD("         -- hb-adv[%d] = %0.2f, log_clusters = %d, total = %0.2f", i,
-                    (*outAdvances)[i], mShaperItem.log_clusters[i], totalFontRunAdvance);
-        }
-#endif
-
-        // Get Glyphs and reverse them in place if RTL
-        if (outGlyphs) {
-            size_t countGlyphs = mShaperItem.num_glyphs;
-#if DEBUG_GLYPHS
-            ALOGD("Returned script run glyphs -- count = %d", countGlyphs);
-#endif
-            for (size_t i = 0; i < countGlyphs; i++) {
-                jchar glyph = glyphBaseCount +
-                        (jchar) mShaperItem.glyphs[(!isRTL) ? i : countGlyphs - 1 - i];
-#if DEBUG_GLYPHS
-                ALOGD("         -- glyph[%d] = %d", i, glyph);
-#endif
-                outGlyphs->add(glyph);
-            }
-        }
-
-        // Get glyph positions (and reverse them in place if RTL)
-        if (outPos) {
-            size_t countGlyphs = mShaperItem.num_glyphs;
-            jfloat x = totalAdvance;
-            for (size_t i = 0; i < countGlyphs; i++) {
-                size_t index = (!isRTL) ? i : countGlyphs - 1 - i;
-                float xo = HBFixedToFloat(mShaperItem.offsets[index].x);
-                float yo = HBFixedToFloat(mShaperItem.offsets[index].y);
-                // Apply skewX component of transform to position offsets. Note
-                // that scale has already been applied through x_ and y_scale
-                // set in the mFontRec.
-                outPos->add(x + xo + yo * skewX);
-                outPos->add(yo);
-#if DEBUG_GLYPHS
-                ALOGD("         -- hb adv[%d] = %f, log_cluster[%d] = %d",
-                        index, HBFixedToFloat(mShaperItem.advances[index]),
-                        index, mShaperItem.log_clusters[index]);
-#endif
-                x += HBFixedToFloat(mShaperItem.advances[index]);
-            }
-        }
-
-        totalAdvance += totalFontRunAdvance;
     }
 
     *outTotalAdvance = totalAdvance;
 
 #if DEBUG_GLYPHS
+    ALOGD("         -- final totalAdvance = %f", totalAdvance);
     ALOGD("-------- End of Script Run --------");
 #endif
 }
@@ -774,37 +791,33 @@
  * for the default font live in a global cache.
  */
 SkTypeface* TextLayoutShaper::typefaceForScript(const SkPaint* paint, SkTypeface* typeface,
-        HB_Script script) {
+        hb_script_t script) {
     SkTypeface::Style currentStyle = SkTypeface::kNormal;
     if (typeface) {
         currentStyle = typeface->style();
     }
-    typeface = SkCreateTypefaceForScript(script, currentStyle);
+    typeface = SkCreateTypefaceForScriptNG(script, currentStyle);
 #if DEBUG_GLYPHS
     ALOGD("Using Harfbuzz Script %d, Style %d", script, currentStyle);
 #endif
     return typeface;
 }
 
-bool TextLayoutShaper::isComplexScript(HB_Script script) {
+bool TextLayoutShaper::isComplexScript(hb_script_t script) {
     switch (script) {
-    case HB_Script_Common:
-    case HB_Script_Greek:
-    case HB_Script_Cyrillic:
-    case HB_Script_Hangul:
-    case HB_Script_Inherited:
+    case HB_SCRIPT_COMMON:
+    case HB_SCRIPT_GREEK:
+    case HB_SCRIPT_CYRILLIC:
+    case HB_SCRIPT_HANGUL:
+    case HB_SCRIPT_INHERITED:
         return false;
     default:
         return true;
     }
 }
 
-size_t TextLayoutShaper::shapeFontRun(const SkPaint* paint, bool isRTL) {
-    // Reset kerning
-    mShaperItem.kerning_applied = false;
-
+size_t TextLayoutShaper::shapeFontRun(const SkPaint* paint) {
     // Update Harfbuzz Shaper
-    mShaperItem.item.bidiLevel = isRTL;
 
     SkTypeface* typeface = paint->getTypeface();
 
@@ -813,19 +826,21 @@
     // when we are shaping any script that needs to use a fallback Font.
     // If we are a "common" script we dont need to shift
     size_t baseGlyphCount = 0;
-    SkUnichar firstUnichar = 0;
-    if (isComplexScript(mShaperItem.item.script)) {
-        const uint16_t* text16 = (const uint16_t*) (mShaperItem.string + mShaperItem.item.pos);
-        const uint16_t* text16End = text16 + mShaperItem.item.length;
-        firstUnichar = SkUTF16_NextUnichar(&text16);
-        while (firstUnichar == ' ' && text16 < text16End) {
-            firstUnichar = SkUTF16_NextUnichar(&text16);
+    hb_codepoint_t firstUnichar = 0;
+    if (isComplexScript(hb_buffer_get_script(mBuffer))) {
+        unsigned int numGlyphs;
+        hb_glyph_info_t* info = hb_buffer_get_glyph_infos(mBuffer, &numGlyphs);
+        for (size_t i = 0; i < numGlyphs; i++) {
+            firstUnichar = info[i].codepoint;
+            if (firstUnichar != ' ') {
+                break;
+            }
         }
         baseGlyphCount = paint->getBaseGlyphCount(firstUnichar);
     }
 
     if (baseGlyphCount != 0) {
-        typeface = typefaceForScript(paint, typeface, mShaperItem.item.script);
+        typeface = typefaceForScript(paint, typeface, hb_buffer_get_script(mBuffer));
         if (!typeface) {
             typeface = mDefaultTypeface;
             SkSafeRef(typeface);
@@ -844,94 +859,44 @@
     }
 
     mShapingPaint.setTypeface(typeface);
-    mShaperItem.face = getCachedHBFace(typeface);
+    hb_face_t* face = referenceCachedHBFace(typeface);
 
-    int textSize = paint->getTextSize();
-    float scaleX = paint->getTextScaleX();
-    mFontRec.x_ppem = floor(scaleX * textSize + 0.5);
-    mFontRec.y_ppem = textSize;
-    uint32_t unitsPerEm = SkFontHost::GetUnitsPerEm(typeface->uniqueID());
-    // x_ and y_scale are the conversion factors from font design space
-    // (unitsPerEm) to 1/64th of device pixels in 16.16 format.
-    const int kDevicePixelFraction = 64;
-    const int kMultiplyFor16Dot16 = 1 << 16;
-    float emScale = kDevicePixelFraction * kMultiplyFor16Dot16 / (float)unitsPerEm;
-    mFontRec.x_scale = emScale * scaleX * textSize;
-    mFontRec.y_scale = emScale * textSize;
+    float sizeY = paint->getTextSize();
+    float sizeX = sizeY * paint->getTextScaleX();
+    hb_font_t* font = createFont(face, &mShapingPaint, sizeX, sizeY);
+    hb_face_destroy(face);
 
 #if DEBUG_GLYPHS
-    ALOGD("Run typeface = %p, uniqueID = %d, hb_face = %p",
-            typeface, typeface->uniqueID(), mShaperItem.face);
+    ALOGD("Run typeface = %p, uniqueID = %d, face = %p",
+            typeface, typeface->uniqueID(), face);
 #endif
     SkSafeUnref(typeface);
 
-    // Shape
-    assert(mShaperItem.item.length > 0); // Harfbuzz will overwrite other memory if length is 0.
-    size_t size = mShaperItem.item.length * 3 / 2;
-    while (!doShaping(size)) {
-        // We overflowed our glyph arrays. Resize and retry.
-        // HB_ShapeItem fills in shaperItem.num_glyphs with the needed size.
-        size = mShaperItem.num_glyphs * 2;
-    }
+    hb_shape(font, mBuffer, NULL, 0);
+    hb_font_destroy(font);
+
     return baseGlyphCount;
 }
 
-bool TextLayoutShaper::doShaping(size_t size) {
-    if (size > mShaperItemGlyphArraySize) {
-        deleteShaperItemGlyphArrays();
-        createShaperItemGlyphArrays(size);
-    }
-    mShaperItem.num_glyphs = mShaperItemGlyphArraySize;
-    memset(mShaperItem.offsets, 0, mShaperItem.num_glyphs * sizeof(HB_FixedPoint));
-    return HB_ShapeItem(&mShaperItem);
-}
-
-void TextLayoutShaper::createShaperItemGlyphArrays(size_t size) {
-#if DEBUG_GLYPHS
-    ALOGD("Creating Glyph Arrays with size = %d", size);
-#endif
-    mShaperItemGlyphArraySize = size;
-
-    // These arrays are all indexed by glyph.
-    mShaperItem.glyphs = new HB_Glyph[size];
-    mShaperItem.attributes = new HB_GlyphAttributes[size];
-    mShaperItem.advances = new HB_Fixed[size];
-    mShaperItem.offsets = new HB_FixedPoint[size];
-
-    // Although the log_clusters array is indexed by character, Harfbuzz expects that
-    // it is big enough to hold one element per glyph.  So we allocate log_clusters along
-    // with the other glyph arrays above.
-    mShaperItem.log_clusters = new unsigned short[size];
-}
-
-void TextLayoutShaper::deleteShaperItemGlyphArrays() {
-    delete[] mShaperItem.glyphs;
-    delete[] mShaperItem.attributes;
-    delete[] mShaperItem.advances;
-    delete[] mShaperItem.offsets;
-    delete[] mShaperItem.log_clusters;
-}
-
-HB_Face TextLayoutShaper::getCachedHBFace(SkTypeface* typeface) {
+hb_face_t* TextLayoutShaper::referenceCachedHBFace(SkTypeface* typeface) {
     SkFontID fontId = typeface->uniqueID();
     ssize_t index = mCachedHBFaces.indexOfKey(fontId);
     if (index >= 0) {
-        return mCachedHBFaces.valueAt(index);
+        return hb_face_reference(mCachedHBFaces.valueAt(index));
     }
-    HB_Face face = HB_NewFace(typeface, harfbuzzSkiaGetTable);
-    if (face) {
+    // TODO: destroy function
+    hb_face_t* face = hb_face_create_for_tables(harfbuzzSkiaReferenceTable, typeface, NULL);
 #if DEBUG_GLYPHS
-        ALOGD("Created HB_NewFace %p from paint typeface = %p", face, typeface);
+    ALOGD("Created HB_NewFace %p from paint typeface = %p", face, typeface);
 #endif
-        mCachedHBFaces.add(fontId, face);
-    }
-    return face;
+    mCachedHBFaces.add(fontId, face);
+    return hb_face_reference(face);
 }
 
 void TextLayoutShaper::purgeCaches() {
     size_t cacheSize = mCachedHBFaces.size();
     for (size_t i = 0; i < cacheSize; i++) {
-        HB_FreeFace(mCachedHBFaces.valueAt(i));
+        hb_face_destroy(mCachedHBFaces.valueAt(i));
     }
     mCachedHBFaces.clear();
     unrefTypefaces();
diff --git a/core/jni/android/graphics/TextLayoutCache.h b/core/jni/android/graphics/TextLayoutCache.h
index 22de523..06bb941 100644
--- a/core/jni/android/graphics/TextLayoutCache.h
+++ b/core/jni/android/graphics/TextLayoutCache.h
@@ -35,11 +35,9 @@
 #include <SkLanguage.h>
 
 #include <unicode/ubidi.h>
-#include <unicode/ushape.h>
 #include <unicode/unistr.h>
 
-#include "HarfbuzzSkia.h"
-#include "harfbuzz-shaper.h"
+#include <hb.h>
 
 #include <android_runtime/AndroidRuntime.h>
 
@@ -189,14 +187,9 @@
 
 private:
     /**
-     * Harfbuzz shaper item
+     * Harfbuzz buffer for shaping
      */
-    HB_ShaperItem mShaperItem;
-
-    /**
-     * Harfbuzz font
-     */
-    HB_FontRec mFontRec;
+    hb_buffer_t* mBuffer;
 
     /**
      * Skia Paint used for shaping
@@ -211,30 +204,15 @@
     /**
      * Cache of Harfbuzz faces
      */
-    KeyedVector<SkFontID, HB_Face> mCachedHBFaces;
-
-    /**
-     * Cache of glyph array size
-     */
-    size_t mShaperItemGlyphArraySize;
-
-    /**
-     * Buffer for containing the ICU normalized form of a run
-     */
-    UnicodeString mNormalizedString;
-
-    /**
-     * Buffer for normalizing a piece of a run with ICU
-     */
-    UnicodeString mBuffer;
+    KeyedVector<SkFontID, hb_face_t*> mCachedHBFaces;
 
     void init();
     void unrefTypefaces();
 
     SkTypeface* typefaceForScript(const SkPaint* paint, SkTypeface* typeface,
-        HB_Script script);
+        hb_script_t script);
 
-    size_t shapeFontRun(const SkPaint* paint, bool isRTL);
+    size_t shapeFontRun(const SkPaint* paint);
 
     void computeValues(const SkPaint* paint, const UChar* chars,
             size_t start, size_t count, size_t contextCount, int dirFlags,
@@ -242,17 +220,14 @@
             Vector<jchar>* const outGlyphs, Vector<jfloat>* const outPos);
 
     void computeRunValues(const SkPaint* paint, const UChar* chars,
-            size_t count, bool isRTL,
+            size_t start, size_t count, size_t contextCount, bool isRTL,
             Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance,
             Vector<jchar>* const outGlyphs, Vector<jfloat>* const outPos);
 
-    SkTypeface* getCachedTypeface(SkTypeface** typeface, HB_Script script, SkTypeface::Style style);
-    HB_Face getCachedHBFace(SkTypeface* typeface);
+    SkTypeface* setCachedTypeface(SkTypeface** typeface, hb_script_t script, SkTypeface::Style style);
+    hb_face_t* referenceCachedHBFace(SkTypeface* typeface);
 
-    bool doShaping(size_t size);
-    void createShaperItemGlyphArrays(size_t size);
-    void deleteShaperItemGlyphArrays();
-    bool isComplexScript(HB_Script script);
+    bool isComplexScript(hb_script_t script);
 
 }; // TextLayoutShaper
 
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 7d886da..de14826 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -275,6 +275,16 @@
     return renderer->clipRect(float(left), float(top), float(right), float(bottom), op);
 }
 
+static bool android_view_GLES20Canvas_clipPath(JNIEnv* env, jobject clazz,
+        OpenGLRenderer* renderer, SkPath* path, SkRegion::Op op) {
+    return renderer->clipPath(path, op);
+}
+
+static bool android_view_GLES20Canvas_clipRegion(JNIEnv* env, jobject clazz,
+        OpenGLRenderer* renderer, SkRegion* region, SkRegion::Op op) {
+    return renderer->clipRegion(region, op);
+}
+
 static bool android_view_GLES20Canvas_getClipBounds(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, jobject rect) {
     const android::uirenderer::Rect& bounds(renderer->getClipBounds());
@@ -961,6 +971,8 @@
     { "nQuickReject",       "(IFFFFI)Z",       (void*) android_view_GLES20Canvas_quickReject },
     { "nClipRect",          "(IFFFFI)Z",       (void*) android_view_GLES20Canvas_clipRectF },
     { "nClipRect",          "(IIIIII)Z",       (void*) android_view_GLES20Canvas_clipRect },
+    { "nClipPath",          "(III)Z",          (void*) android_view_GLES20Canvas_clipPath },
+    { "nClipRegion",        "(III)Z",          (void*) android_view_GLES20Canvas_clipRegion },
 
     { "nTranslate",         "(IFF)V",          (void*) android_view_GLES20Canvas_translate },
     { "nRotate",            "(IF)V",           (void*) android_view_GLES20Canvas_rotate },
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java
index a6057de..649e39d 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java
@@ -28,6 +28,7 @@
 import android.net.wifi.WifiConfiguration.IpAssignment;
 import android.net.wifi.WifiConfiguration.KeyMgmt;
 import android.net.wifi.WifiConfiguration.ProxySettings;
+import android.net.wifi.WifiEnterpriseConfig;
 import android.net.LinkAddress;
 import android.net.LinkProperties;
 import android.net.RouteInfo;
@@ -67,7 +68,6 @@
  *      networkprefixlength.
  */
 public class AccessPointParserHelper {
-    private static final String KEYSTORE_SPACE = "keystore://";
     private static final String TAG = "AccessPointParserHelper";
     static final int NONE = 0;
     static final int WEP = 1;
@@ -212,14 +212,11 @@
                         config.allowedKeyManagement.set(KeyMgmt.WPA_EAP);
                         config.allowedKeyManagement.set(KeyMgmt.IEEE8021X);
                         // Initialize other fields.
-                        config.phase2.setValue("");
-                        config.ca_cert.setValue("");
-                        config.client_cert.setValue("");
-                        config.engine.setValue("");
-                        config.engine_id.setValue("");
-                        config.key_id.setValue("");
-                        config.identity.setValue("");
-                        config.anonymous_identity.setValue("");
+                        config.enterpriseConfig.setPhase2Method(WifiEnterpriseConfig.Phase2.NONE);
+                        config.enterpriseConfig.setCaCertificate("");
+                        config.enterpriseConfig.setClientCertificate("");
+                        config.enterpriseConfig.setIdentity("");
+                        config.enterpriseConfig.setAnonymousIdentity("");
                         break;
                     default:
                         throw new SAXException();
@@ -246,7 +243,7 @@
                         config.preSharedKey = '"' + passwordStr + '"';
                     }
                 } else if (securityType == EAP) {
-                    config.password.setValue(passwordStr);
+                    config.enterpriseConfig.setPassword(passwordStr);
                 } else {
                     throw new SAXException();
                 }
@@ -257,33 +254,46 @@
                 if (!validateEapValue(eapValue)) {
                     throw new SAXException();
                 }
-                config.eap.setValue(eapValue);
+		if (eapValue.equals("TLS")) {
+		    config.enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.TLS);
+		} else if (eapValue.equals("TTLS")) {
+		    config.enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.TTLS);
+		} else if (eapValue.equals("PEAP")) {
+		    config.enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.PEAP);
+		}
                 eap = false;
             }
             if (phase2) {
                 String phase2Value = new String(ch, start, length);
-                config.phase2.setValue("auth=" + phase2Value);
+		if (phase2Value.equals("PAP")) {
+                    config.enterpriseConfig.setPhase2Method(WifiEnterpriseConfig.Phase2.PAP);
+		} else if (phase2Value.equals("MSCHAP")) {
+                    config.enterpriseConfig.setPhase2Method(WifiEnterpriseConfig.Phase2.MSCHAP);
+		} else if (phase2Value.equals("MSCHAPV2")) {
+                    config.enterpriseConfig.setPhase2Method(WifiEnterpriseConfig.Phase2.MSCHAPV2);
+		} else if (phase2Value.equals("GTC")) {
+                    config.enterpriseConfig.setPhase2Method(WifiEnterpriseConfig.Phase2.GTC);
+		}
                 phase2 = false;
             }
             if (identity) {
                 String identityValue = new String(ch, start, length);
-                config.identity.setValue(identityValue);
+                config.enterpriseConfig.setIdentity(identityValue);
                 identity = false;
             }
             if (anonymousidentity) {
                 String anonyId = new String(ch, start, length);
-                config.anonymous_identity.setValue(anonyId);
+                config.enterpriseConfig.setAnonymousIdentity(anonyId);
                 anonymousidentity = false;
             }
             if (cacert) {
                 String cacertValue = new String(ch, start, length);
-                // need to install the credentail to "keystore://"
-                config.ca_cert.setValue(KEYSTORE_SPACE);
+                config.enterpriseConfig.setCaCertificate(cacertValue);
                 cacert = false;
             }
             if (usercert) {
                 String usercertValue = new String(ch, start, length);
-                config.client_cert.setValue(KEYSTORE_SPACE);
+                config.enterpriseConfig.setClientCertificate(usercertValue);
                 usercert = false;
             }
             if (ip) {
diff --git a/libs/hwui/Debug.h b/libs/hwui/Debug.h
index 6795ac3..dfc4e25c 100644
--- a/libs/hwui/Debug.h
+++ b/libs/hwui/Debug.h
@@ -35,6 +35,9 @@
 // Turn on to enable layers debugging when rendered as regions
 #define DEBUG_LAYERS_AS_REGIONS 0
 
+// Turn on to enable debugging when the clip is not a rect
+#define DEBUG_CLIP_REGIONS 0
+
 // Turn on to display debug info about vertex/fragment shaders
 #define DEBUG_PROGRAMS 0
 
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 06574cd..f0c9ce4 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -44,6 +44,8 @@
     "SetMatrix",
     "ConcatMatrix",
     "ClipRect",
+    "ClipPath",
+    "ClipRegion",
     "DrawDisplayList",
     "DrawLayer",
     "DrawBitmap",
@@ -166,6 +168,10 @@
         delete mPaints.itemAt(i);
     }
 
+    for (size_t i = 0; i < mRegions.size(); i++) {
+        delete mRegions.itemAt(i);
+    }
+
     for (size_t i = 0; i < mPaths.size(); i++) {
         SkPath* path = mPaths.itemAt(i);
         caches.pathCache.remove(path);
@@ -182,6 +188,7 @@
     mShaders.clear();
     mSourcePaths.clear();
     mPaints.clear();
+    mRegions.clear();
     mPaths.clear();
     mMatrices.clear();
     mLayers.clear();
@@ -259,20 +266,10 @@
 
     caches.resourceCache.unlock();
 
-    const Vector<SkPaint*>& paints = recorder.getPaints();
-    for (size_t i = 0; i < paints.size(); i++) {
-        mPaints.add(paints.itemAt(i));
-    }
-
-    const Vector<SkPath*>& paths = recorder.getPaths();
-    for (size_t i = 0; i < paths.size(); i++) {
-        mPaths.add(paths.itemAt(i));
-    }
-
-    const Vector<SkMatrix*>& matrices = recorder.getMatrices();
-    for (size_t i = 0; i < matrices.size(); i++) {
-        mMatrices.add(matrices.itemAt(i));
-    }
+    mPaints.appendVector(recorder.getPaints());
+    mRegions.appendVector(recorder.getRegions());
+    mPaths.appendVector(recorder.getPaths());
+    mMatrices.appendVector(recorder.getMatrices());
 }
 
 void DisplayList::init() {
@@ -429,6 +426,18 @@
                         f1, f2, f3, f4, regionOp);
             }
             break;
+            case ClipPath: {
+                SkPath* path = getPath();
+                int regionOp = getInt();
+                ALOGD("%s%s %d", (char*) indent, OP_NAMES[op], regionOp);
+            }
+            break;
+            case ClipRegion: {
+                SkRegion* region = getRegion();
+                int regionOp = getInt();
+                ALOGD("%s%s %d", (char*) indent, OP_NAMES[op], regionOp);
+            }
+            break;
             case DrawDisplayList: {
                 DisplayList* displayList = getDisplayList();
                 int32_t flags = getInt();
@@ -1031,6 +1040,20 @@
                 renderer.clipRect(f1, f2, f3, f4, (SkRegion::Op) regionOp);
             }
             break;
+            case ClipPath: {
+                SkPath* path = getPath();
+                int32_t regionOp = getInt();
+                DISPLAY_LIST_LOGD("%s%s %d", (char*) indent, OP_NAMES[op], regionOp);
+                renderer.clipPath(path, (SkRegion::Op) regionOp);
+            }
+            break;
+            case ClipRegion: {
+                SkRegion* region = getRegion();
+                int32_t regionOp = getInt();
+                DISPLAY_LIST_LOGD("%s%s %d", (char*) indent, OP_NAMES[op], regionOp);
+                renderer.clipRegion(region, (SkRegion::Op) regionOp);
+            }
+            break;
             case DrawDisplayList: {
                 DisplayList* displayList = getDisplayList();
                 int32_t flags = getInt();
@@ -1415,6 +1438,9 @@
     mPaints.clear();
     mPaintMap.clear();
 
+    mRegions.clear();
+    mRegionMap.clear();
+
     mPaths.clear();
     mPathMap.clear();
 
@@ -1571,6 +1597,20 @@
     return OpenGLRenderer::clipRect(left, top, right, bottom, op);
 }
 
+bool DisplayListRenderer::clipPath(SkPath* path, SkRegion::Op op) {
+    addOp(DisplayList::ClipPath);
+    addPath(path);
+    addInt(op);
+    return OpenGLRenderer::clipPath(path, op);
+}
+
+bool DisplayListRenderer::clipRegion(SkRegion* region, SkRegion::Op op) {
+    addOp(DisplayList::ClipRegion);
+    addRegion(region);
+    addInt(op);
+    return OpenGLRenderer::clipRegion(region, op);
+}
+
 status_t DisplayListRenderer::drawDisplayList(DisplayList* displayList,
         Rect& dirty, int32_t flags, uint32_t level) {
     // dirty is an out parameter and should not be recorded,
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index fb01753..f55f1f2 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -85,6 +85,8 @@
         SetMatrix,
         ConcatMatrix,
         ClipRect,
+        ClipPath,
+        ClipRegion,
         // Drawing operations
         DrawDisplayList,
         DrawLayer,
@@ -457,6 +459,10 @@
         return (SkPath*) getInt();
     }
 
+    SkRegion* getRegion() {
+        return (SkRegion*) getInt();
+    }
+
     SkPaint* getPaint(OpenGLRenderer& renderer) {
         return renderer.filterPaint((SkPaint*) getInt());
     }
@@ -496,6 +502,7 @@
     Vector<SkPaint*> mPaints;
     Vector<SkPath*> mPaths;
     SortedVector<SkPath*> mSourcePaths;
+    Vector<SkRegion*> mRegions;
     Vector<SkMatrix*> mMatrices;
     Vector<SkiaShader*> mShaders;
     Vector<Layer*> mLayers;
@@ -577,6 +584,8 @@
     virtual void concatMatrix(SkMatrix* matrix);
 
     virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op);
+    virtual bool clipPath(SkPath* path, SkRegion::Op op);
+    virtual bool clipRegion(SkRegion* region, SkRegion::Op op);
 
     virtual status_t drawDisplayList(DisplayList* displayList, Rect& dirty, int32_t flags,
             uint32_t level = 0);
@@ -657,6 +666,10 @@
         return mSourcePaths;
     }
 
+    const Vector<SkRegion*>& getRegions() const {
+        return mRegions;
+    }
+
     const Vector<Layer*>& getLayers() const {
         return mLayers;
     }
@@ -802,6 +815,26 @@
         return paintCopy;
     }
 
+    inline SkRegion* addRegion(SkRegion* region) {
+        if (!region) {
+            addInt((int) NULL);
+            return region;
+        }
+
+        SkRegion* regionCopy = mRegionMap.valueFor(region);
+        // TODO: Add generation ID to SkRegion
+        if (regionCopy == NULL) {
+            regionCopy = new SkRegion(*region);
+            // replaceValueFor() performs an add if the entry doesn't exist
+            mRegionMap.replaceValueFor(region, regionCopy);
+            mRegions.add(regionCopy);
+        }
+
+        addInt((int) regionCopy);
+
+        return regionCopy;
+    }
+
     inline void addDisplayList(DisplayList* displayList) {
         // TODO: To be safe, the display list should be ref-counted in the
         //       resources cache, but we rely on the caller (UI toolkit) to
@@ -876,6 +909,9 @@
 
     SortedVector<SkPath*> mSourcePaths;
 
+    Vector<SkRegion*> mRegions;
+    DefaultKeyedVector<SkRegion*, SkRegion*> mRegionMap;
+
     Vector<SkiaShader*> mShaders;
     DefaultKeyedVector<SkiaShader*, SkiaShader*> mShaderMap;
 
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 8cda729..bb1edbb 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -1288,10 +1288,38 @@
     bool clipped = mSnapshot->clip(left, top, right, bottom, op);
     if (clipped) {
         dirtyClip();
+#if DEBUG_CLIP_REGIONS
+        if (!isDeferred() && mSnapshot->clipRegion && !mSnapshot->clipRegion->isRect()) {
+            int count = 0;
+            Vector<float> rects;
+            SkRegion::Iterator it(*mSnapshot->clipRegion);
+            while (!it.done()) {
+                const SkIRect& r = it.rect();
+                rects.push(r.fLeft);
+                rects.push(r.fTop);
+                rects.push(r.fRight);
+                rects.push(r.fBottom);
+                count++;
+                it.next();
+            }
+
+            drawColorRects(rects.array(), count, 0x7f00ff00, SkXfermode::kSrcOver_Mode, true);
+        }
+#endif
     }
     return !mSnapshot->clipRect->isEmpty();
 }
 
+bool OpenGLRenderer::clipPath(SkPath* path, SkRegion::Op op) {
+    const SkRect& bounds = path->getBounds();
+    return clipRect(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, op);
+}
+
+bool OpenGLRenderer::clipRegion(SkRegion* region, SkRegion::Op op) {
+    const SkIRect& bounds = region->getBounds();
+    return clipRect(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, op);
+}
+
 Rect* OpenGLRenderer::getClipRect() {
     return mSnapshot->clipRect;
 }
@@ -3046,6 +3074,19 @@
         return DrawGlInfo::kStatusDone;
     }
 
+    int color = paint->getColor();
+    // If a shader is set, preserve only the alpha
+    if (mShader) {
+        color |= 0x00ffffff;
+    }
+    SkXfermode::Mode mode = getXfermode(paint->getXfermode());
+
+    return drawColorRects(rects, count, color, mode);
+}
+
+status_t OpenGLRenderer::drawColorRects(const float* rects, int count, int color,
+        SkXfermode::Mode mode, bool ignoreTransform) {
+
     float left = FLT_MAX;
     float top = FLT_MAX;
     float right = FLT_MIN;
@@ -3081,13 +3122,6 @@
 
     if (count == 0) return DrawGlInfo::kStatusDone;
 
-    int color = paint->getColor();
-    // If a shader is set, preserve only the alpha
-    if (mShader) {
-        color |= 0x00ffffff;
-    }
-    SkXfermode::Mode mode = getXfermode(paint->getXfermode());
-
     setupDraw();
     setupDrawNoTexture();
     setupDrawColor(color, ((color >> 24) & 0xFF) * mSnapshot->alpha);
@@ -3096,7 +3130,7 @@
     setupDrawBlending(mode);
     setupDrawProgram();
     setupDrawDirtyRegionsDisabled();
-    setupDrawModelView(0.0f, 0.0f, 1.0f, 1.0f);
+    setupDrawModelView(0.0f, 0.0f, 1.0f, 1.0f, ignoreTransform, true);
     setupDrawColorUniforms();
     setupDrawShaderUniforms();
     setupDrawColorFilterUniforms();
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 5520edb..f07325f 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -164,6 +164,8 @@
     ANDROID_API bool quickReject(float left, float top, float right, float bottom);
     bool quickRejectNoScissor(float left, float top, float right, float bottom);
     virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op);
+    virtual bool clipPath(SkPath* path, SkRegion::Op op);
+    virtual bool clipRegion(SkRegion* region, SkRegion::Op op);
     virtual Rect* getClipRect();
 
     virtual status_t drawDisplayList(DisplayList* displayList, Rect& dirty, int32_t flags,
@@ -498,7 +500,8 @@
 
     /**
      * Draws a colored rectangle with the specified color. The specified coordinates
-     * are transformed by the current snapshot's transform matrix.
+     * are transformed by the current snapshot's transform matrix unless specified
+     * otherwise.
      *
      * @param left The left coordinate of the rectangle
      * @param top The top coordinate of the rectangle
@@ -512,6 +515,20 @@
             int color, SkXfermode::Mode mode, bool ignoreTransform = false);
 
     /**
+     * Draws a series of colored rectangles with the specified color. The specified
+     * coordinates are transformed by the current snapshot's transform matrix unless
+     * specified otherwise.
+     *
+     * @param rects A list of rectangles, 4 floats (left, top, right, bottom)
+     *              per rectangle
+     * @param color The rectangles' ARGB color, defined as a packed 32 bits word
+     * @param mode The Skia xfermode to use
+     * @param ignoreTransform True if the current transform should be ignored
+     */
+    status_t drawColorRects(const float* rects, int count, int color,
+            SkXfermode::Mode mode, bool ignoreTransform = false);
+
+    /**
      * Draws the shape represented by the specified path texture.
      * This method invokes drawPathTexture() but takes into account
      * the extra left/top offset and the texture offset to correctly
diff --git a/libs/hwui/Snapshot.cpp b/libs/hwui/Snapshot.cpp
index fbc8455..d947299 100644
--- a/libs/hwui/Snapshot.cpp
+++ b/libs/hwui/Snapshot.cpp
@@ -130,6 +130,7 @@
     switch (op) {
         case SkRegion::kIntersect_Op: {
             if (CC_UNLIKELY(clipRegion)) {
+                ensureClipRegion();
                 clipped = clipRegionOp(r.left, r.top, r.right, r.bottom, SkRegion::kIntersect_Op);
             } else {
                 clipped = clipRect->intersect(r);
@@ -142,6 +143,7 @@
         }
         case SkRegion::kUnion_Op: {
             if (CC_UNLIKELY(clipRegion)) {
+                ensureClipRegion();
                 clipped = clipRegionOp(r.left, r.top, r.right, r.bottom, SkRegion::kUnion_Op);
             } else {
                 clipped = clipRect->unionWith(r);
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ClipRegionActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ClipRegionActivity.java
index b2a508b..d5daa5f 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/ClipRegionActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ClipRegionActivity.java
@@ -18,13 +18,7 @@
 
 import android.app.Activity;
 import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
 import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffXfermode;
 import android.graphics.Region;
 import android.os.Bundle;
 import android.view.View;
@@ -50,8 +44,10 @@
             canvas.save();
             canvas.clipRect(100.0f, 100.0f, getWidth() - 100.0f, getHeight() - 100.0f,
                     Region.Op.DIFFERENCE);
-            canvas.drawARGB(255, 255, 0, 0);
+            canvas.drawARGB(128, 255, 0, 0);
             canvas.restore();
+
+            invalidate();
         }
     }
 }