refresh from trunk
check-point for lcd text rendering
diff --git a/include/core/SkFontHost.h b/include/core/SkFontHost.h
index 03ebfc7..5a49146 100644
--- a/include/core/SkFontHost.h
+++ b/include/core/SkFontHost.h
@@ -131,6 +131,20 @@
 
     ///////////////////////////////////////////////////////////////////////////
 
+    /** Given a filled-out rec, the fonthost may decide to modify it to reflect
+        what the host is actually capable of fulfilling. For example, if the
+        rec is requesting a level of hinting that, for this host, maps some
+        other level (e.g. kFull -> kNormal), it should update the rec to reflect
+        what will actually be done. This is an optimization so that the font
+        cache does not contain different recs (i.e. keys) that in reality map to
+        the same output.
+
+        A lazy (but valid) fonthost can do nothing in its FilterRec routine.
+     */
+    static void FilterRec(SkScalerContext::Rec* rec);
+
+    ///////////////////////////////////////////////////////////////////////////
+
     /** Return the number of tables in the font
      */
     static int CountTables(SkFontID);
@@ -187,6 +201,38 @@
         white (table[1]) gamma tables.
     */
     static void GetGammaTables(const uint8_t* tables[2]);
+
+    ///////////////////////////////////////////////////////////////////////////
+
+    /** LCDs either have their color elements arranged horizontally or
+        vertically. When rendering subpixel glyphs we need to know which way
+        round they are.
+
+        Note, if you change this after startup, you'll need to flush the glyph
+        cache because it'll have the wrong type of masks cached.
+    */
+    enum LCDOrientation {
+        kHorizontal_LCDOrientation = 0,    //!< this is the default
+        kVertical_LCDOrientation   = 1,
+    };
+
+    static void SetSubpixelOrientation(LCDOrientation orientation);
+    static LCDOrientation GetSubpixelOrientation();
+
+    /** LCD color elements can vary in order. For subpixel text we need to know
+        the order which the LCDs uses so that the color fringes are in the
+        correct place.
+
+        Note, if you change this after startup, you'll need to flush the glyph
+        cache because it'll have the wrong type of masks cached.
+    */
+    enum LCDOrder {
+        kRGB_LCDOrder = 0,    //!< this is the default
+        kBGR_LCDOrder = 1,
+    };
+
+    static void SetSubpixelOrder(LCDOrder order);
+    static LCDOrder GetSubpixelOrder();
 };
 
 #endif
diff --git a/include/core/SkMask.h b/include/core/SkMask.h
index b72a5c5..6cbf37a 100644
--- a/include/core/SkMask.h
+++ b/include/core/SkMask.h
@@ -28,11 +28,28 @@
         kBW_Format, //!< 1bit per pixel mask (e.g. monochrome)
         kA8_Format, //!< 8bits per pixel mask (e.g. antialiasing)
         k3D_Format, //!< 3 8bit per pixl planes: alpha, mul, add
-        kLCD_Format //!< 3 bytes/pixel: r/g/b
+
+        /* The LCD formats look like this in memory:
+
+           First, there's an A8 plane which contains the average alpha value for
+           each pixel. Because of this, the LCD formats can be passed directly
+           to functions which expect an A8 and everything will just work.
+
+           After that in memory, there's a bitmap of 32-bit values which have
+           been RGB order corrected for the current screen (based on the
+           settings in SkFontHost at the time of renderering). The alpha value
+           for each pixel is the maximum of the three alpha values.
+
+           kHorizontalLCD_Format has an extra column of pixels on the left and right
+           edges. kVerticalLCD_Format has an extra row at the top and bottom.
+        */
+
+        kHorizontalLCD_Format, //!< 4 bytes/pixel: a/r/g/b
+        kVerticalLCD_Format, //!< 4 bytes/pixel: a/r/g/b
     };
-    
+
     enum {
-        kCountMaskFormats = kLCD_Format + 1
+        kCountMaskFormats = kVerticalLCD_Format + 1
     };
 
     uint8_t*    fImage;
@@ -78,6 +95,29 @@
         return fImage + x - fBounds.fLeft + (y - fBounds.fTop) * fRowBytes;
     }
 
+    /** Return an address into the 32-bit plane of an LCD or VerticalLCD mask
+        for the given position.
+    */
+    const uint32_t* getAddrLCD(int x, int y) const {
+        SkASSERT(fFormat == kHorizontalLCD_Format || fFormat == kVerticalLCD_Format);
+        SkASSERT(fBounds.contains(x, y));
+        SkASSERT(fImage != NULL);
+
+        return reinterpret_cast<const uint32_t*>(fImage + SkAlign4(fRowBytes * fBounds.height())) +
+               x - fBounds.fLeft + (y - fBounds.fTop) * rowWordsLCD();
+    }
+
+    /** Return the number of 32-bit words in a row of the 32-bit plane of an
+       LCD or VerticalLCD mask.
+    */
+    unsigned rowWordsLCD() const {
+        SkASSERT(fFormat == kHorizontalLCD_Format || fFormat == kVerticalLCD_Format);
+        if (fFormat == kHorizontalLCD_Format)
+            return fBounds.width() + 2;
+        else
+            return fBounds.width();
+    }
+
     static uint8_t* AllocImage(size_t bytes);
     static void FreeImage(void* image);
     
@@ -86,6 +126,10 @@
         kJustRenderImage_CreateMode,        //!< render into preallocate mask
         kComputeBoundsAndRenderImage_CreateMode  //!< compute bounds, alloc image and render into it
     };
+
+    static bool FormatIsLCD(Format fm) {
+        return kHorizontalLCD_Format == fm || kVerticalLCD_Format == fm;
+    }
 };
 
 #endif
diff --git a/include/core/SkPaint.h b/include/core/SkPaint.h
index 5a01cd6..ed60a20 100644
--- a/include/core/SkPaint.h
+++ b/include/core/SkPaint.h
@@ -69,6 +69,33 @@
     */
     void reset();
 
+    /** Specifies the level of hinting to be performed. These names are taken
+        from the Gnome/Cairo names for the same. They are translated into
+        Freetype concepts the same as in cairo-ft-font.c:
+           kNo_Hinting     -> FT_LOAD_NO_HINTING
+           kSlight_Hinting -> FT_LOAD_TARGET_LIGHT
+           kNormal_Hinting -> <default, no option>
+           kFull_Hinting   -> <same as kNormalHinting, unless we are rendering
+                              subpixel glyphs, in which case TARGET_LCD or
+                              TARGET_LCD_V is used>
+    */
+    enum Hinting {
+        kNo_Hinting            = 0,
+        kSlight_Hinting        = 1,
+        kNormal_Hinting        = 2,     //!< this is the default
+        kFull_Hinting          = 3,
+    };
+
+    Hinting getHinting() const
+    {
+        return static_cast<Hinting>(fHinting);
+    }
+
+    void setHinting(Hinting hintingLevel)
+    {
+        fHinting = hintingLevel;
+    }
+
     /** Specifies the bit values that are stored in the paint's flags.
     */
     enum Flags {
@@ -79,10 +106,13 @@
         kStrikeThruText_Flag  = 0x10,   //!< mask to enable strike-thru text
         kFakeBoldText_Flag    = 0x20,   //!< mask to enable fake-bold text
         kLinearText_Flag      = 0x40,   //!< mask to enable linear-text
-        kSubpixelText_Flag    = 0x80,   //!< mask to enable subpixel-text
+        kSubpixelText_Flag    = 0x80,   //!< mask to enable subpixel text positioning
         kDevKernText_Flag     = 0x100,  //!< mask to enable device kerning text
+        kLCDRenderText_Flag   = 0x200,  //!< mask to enable subpixel glyph renderering
+        // when adding extra flags, note that the fFlags member is specified
+        // with a bit-width and you'll have to expand it.
 
-        kAllFlags = 0x1FF
+        kAllFlags = 0x3FF
     };
 
     /** Return the paint's flags. Use the Flag enum to test flag values.
@@ -143,12 +173,23 @@
         return SkToBool(this->getFlags() & kSubpixelText_Flag);
     }
     
-    /** Helper for setFlags(), setting or clearing the kSubpixelText_Flag bit
-        @param subpixelText true to set the subpixelText bit in the paint's
-                            flags, false to clear it.
+    /** Helper for setFlags(), setting or clearing the kSubpixelText_Flag
+       bit @param subpixelText true to set the subpixelText bit in the paint's flags,
+                               false to clear it.
     */
     void setSubpixelText(bool subpixelText);
-    
+
+    bool isLCDRenderText() const
+    {
+        return SkToBool(this->getFlags() & kLCDRenderText_Flag);
+    }
+
+    /** Helper for setFlags(), setting or clearing the kLCDRenderText_Flag bit
+        @param subpixelRender true to set the subpixelRenderText bit in the paint's flags,
+                              false to clear it.
+    */
+    void setLCDRenderText(bool subpixelRender);
+
     /** Helper for getFlags(), returning true if kUnderlineText_Flag bit is set
         @return true if the underlineText bit is set in the paint's flags.
     */
@@ -749,12 +790,13 @@
     SkColor         fColor;
     SkScalar        fWidth;
     SkScalar        fMiterLimit;
-    unsigned        fFlags : 9;
+    unsigned        fFlags : 10;
     unsigned        fTextAlign : 2;
     unsigned        fCapType : 2;
     unsigned        fJoinType : 2;
     unsigned        fStyle : 2;
     unsigned        fTextEncoding : 2;  // 3 values
+    unsigned        fHinting : 2;
 
     SkDrawCacheProc    getDrawCacheProc() const;
     SkMeasureCacheProc getMeasureCacheProc(TextBufferDirection dir,
diff --git a/include/core/SkScalerContext.h b/include/core/SkScalerContext.h
index b06a443..29c28f7 100644
--- a/include/core/SkScalerContext.h
+++ b/include/core/SkScalerContext.h
@@ -136,34 +136,59 @@
     }
     
     void toMask(SkMask* mask) const;
+
+    /** Given a glyph which is has a mask format of LCD or VerticalLCD, take
+        the A8 plane in fImage and produce a valid LCD plane from it.
+    */
+    void expandA8ToLCD() const;
 };
 
 class SkScalerContext {
 public:
-    enum Hints {
-        kNo_Hints,
-        kSubpixel_Hints,
-        kNormal_Hints
-    };
     enum Flags {
         kFrameAndFill_Flag  = 0x01,
         kDevKernText_Flag   = 0x02,
         kGammaForBlack_Flag = 0x04, // illegal to set both Gamma flags
-        kGammaForWhite_Flag = 0x08  // illegal to set both Gamma flags
+        kGammaForWhite_Flag = 0x08, // illegal to set both Gamma flags
+        // together, these two flags resulting in a two bit value which matches
+        // up with the SkPaint::Hinting enum.
+        kHintingBit1_Flag   = 0x10,
+        kHintingBit2_Flag   = 0x20,
     };
+private:
+    enum {
+        kHintingMask = kHintingBit1_Flag | kHintingBit2_Flag
+    };
+public:
     struct Rec {
         uint32_t    fFontID;
         SkScalar    fTextSize, fPreScaleX, fPreSkewX;
         SkScalar    fPost2x2[2][2];
         SkScalar    fFrameWidth, fMiterLimit;
-        uint8_t     fHints;
+        bool        fSubpixelPositioning;
         uint8_t     fMaskFormat;
         uint8_t     fStrokeJoin;
         uint8_t     fFlags;
-        
+
         void    getMatrixFrom2x2(SkMatrix*) const;
         void    getLocalMatrix(SkMatrix*) const;
         void    getSingleMatrix(SkMatrix*) const;
+
+        SkPaint::Hinting getHinting() const {
+            return static_cast<SkPaint::Hinting>((fFlags & kHintingMask) >> 4);
+        }
+
+        void setHinting(SkPaint::Hinting hinting) {
+            fFlags = (fFlags & ~kHintingMask) | (hinting << 4);
+        }
+
+        SkMask::Format getFormat() const {
+            return static_cast<SkMask::Format>(fMaskFormat);
+        }
+
+        bool isLCD() const {
+            return SkMask::FormatIsLCD(this->getFormat());
+        }
     };
 
     SkScalerContext(const SkDescriptor* desc);
diff --git a/include/core/SkUserConfig.h b/include/core/SkUserConfig.h
index e5528cc..a72aa1a 100644
--- a/include/core/SkUserConfig.h
+++ b/include/core/SkUserConfig.h
@@ -135,7 +135,6 @@
                       const char* function, const char* format, ...);
 
 
-
 /*  If SK_DEBUG is defined, then you can optionally define SK_SUPPORT_UNITTEST
     which will run additional self-tests at startup. These can take a long time,
     so this flag is optional.
diff --git a/src/core/SkBitmapProcState.cpp b/src/core/SkBitmapProcState.cpp
index dbdcc27..379a7b3 100644
--- a/src/core/SkBitmapProcState.cpp
+++ b/src/core/SkBitmapProcState.cpp
@@ -302,6 +302,20 @@
 #define FILTER_TO_DST(c)        SkCompact_rgb_16((c) >> 5)
 #include "SkBitmapProcState_shaderproc.h"
 
+
+#define TILEX_PROCF(fx, max)    (((fx) & 0xFFFF) * ((max) + 1) >> 16)
+#define TILEY_PROCF(fy, max)    (((fy) & 0xFFFF) * ((max) + 1) >> 16)
+#define TILEX_LOW_BITS(fx, max) ((((fx) & 0xFFFF) * ((max) + 1) >> 12) & 0xF)
+#define TILEY_LOW_BITS(fy, max) ((((fy) & 0xFFFF) * ((max) + 1) >> 12) & 0xF)
+
+#define MAKENAME(suffix)        Repeat_S16_D16 ## suffix
+#define SRCTYPE                 uint16_t
+#define DSTTYPE                 uint16_t
+#define CHECKSTATE(state)       SkASSERT(state.fBitmap->config() == SkBitmap::kRGB_565_Config)
+#define SRC_TO_FILTER(src)      src
+#define FILTER_TO_DST(c)        SkCompact_rgb_16((c) >> 5)
+#include "SkBitmapProcState_shaderproc.h"
+
 ///////////////////////////////////////////////////////////////////////////////
 
 static bool valid_for_filtering(unsigned dimension) {
@@ -485,8 +499,13 @@
     fSampleProc16 = gSample16[index];
 
     // our special-case shaderprocs
-    if (clamp_clamp && (7 == index)) {
-        fShaderProc16 = Clamp_S16_D16_filter_DX_shaderproc;
+    if (S16_D16_filter_DX == fSampleProc16) {
+        if (clamp_clamp) {
+            fShaderProc16 = Clamp_S16_D16_filter_DX_shaderproc;
+        } else if (SkShader::kRepeat_TileMode == fTileModeX &&
+                   SkShader::kRepeat_TileMode == fTileModeY) {
+            fShaderProc16 = Repeat_S16_D16_filter_DX_shaderproc;
+        }
     }
     return true;
 }
diff --git a/src/core/SkBitmapProcState_shaderproc.h b/src/core/SkBitmapProcState_shaderproc.h
index b0384e7..070a62b 100644
--- a/src/core/SkBitmapProcState_shaderproc.h
+++ b/src/core/SkBitmapProcState_shaderproc.h
@@ -1,14 +1,5 @@
 #define SCALE_FILTER_NAME       MAKENAME(_filter_DX_shaderproc)
 
-#ifndef PREAMBLE
-    #define PREAMBLE(state)
-    #define PREAMBLE_PARAM_X
-    #define PREAMBLE_PARAM_Y
-    #define PREAMBLE_ARG_X
-    #define PREAMBLE_ARG_Y
-#endif
-
-
 static void SCALE_FILTER_NAME(const SkBitmapProcState& s, int x, int y,
                               DSTTYPE* SK_RESTRICT colors, int count) {
     SkASSERT((s.fInvType & ~(SkMatrix::kTranslate_Mask |
@@ -18,8 +9,6 @@
     SkASSERT(s.fDoFilter);
     SkDEBUGCODE(CHECKSTATE(s);)
 
-    PREAMBLE(s);
-
     const unsigned maxX = s.fBitmap->width() - 1;
     const SkFixed oneX = s.fFilterOneX;
     const SkFixed dx = s.fInvSx;
@@ -65,19 +54,15 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-#undef MAKENAME
 #undef TILEX_PROCF
 #undef TILEY_PROCF
 #undef TILEX_LOW_BITS
 #undef TILEY_LOW_BITS
-#ifdef CHECK_FOR_DECAL
-    #undef CHECK_FOR_DECAL
-#endif
+#undef MAKENAME
+#undef SRCTYPE
+#undef DSTTYPE
+#undef CHECKSTATE
+#undef SRC_TO_FILTER
+#undef FILTER_TO_DST
 
 #undef SCALE_FILTER_NAME
-
-#undef PREAMBLE
-#undef PREAMBLE_PARAM_X
-#undef PREAMBLE_PARAM_Y
-#undef PREAMBLE_ARG_X
-#undef PREAMBLE_ARG_Y
diff --git a/src/core/SkBlitter_ARGB32.cpp b/src/core/SkBlitter_ARGB32.cpp
index ed2fc0e..d3e5714 100644
--- a/src/core/SkBlitter_ARGB32.cpp
+++ b/src/core/SkBlitter_ARGB32.cpp
@@ -21,6 +21,25 @@
 #include "SkUtils.h"
 #include "SkXfermode.h"
 
+#if defined(SK_SUPPORT_LCDTEXT)
+namespace skia_blitter_support {
+// subpixel helper functions from SkBlitter_ARGB32_Subpixel.cpp
+uint32_t* adjustForSubpixelClip(const SkMask& mask,
+                                const SkIRect& clip, const SkBitmap& device,
+                                int* widthAdjustment, int* heightAdjustment,
+                                const uint32_t** alpha32);
+extern uint32_t BlendLCDPixelWithColor(const uint32_t alphaPixel, const uint32_t originalPixel,
+                                       const uint32_t sourcePixel);
+extern uint32_t BlendLCDPixelWithOpaqueColor(const uint32_t alphaPixel, const uint32_t originalPixel,
+                                             const uint32_t sourcePixel);
+extern uint32_t BlendLCDPixelWithBlack(const uint32_t alphaPixel, const uint32_t originalPixel);
+}
+
+using namespace skia_blitter_support;
+#endif
+
+//////////////////////////////////////////////////////////////////////////////////////
+
 SkARGB32_Blitter::SkARGB32_Blitter(const SkBitmap& device, const SkPaint& paint)
         : INHERITED(device) {
     uint32_t color = paint.getColor();
@@ -201,12 +220,45 @@
     int width = clip.width();
     int height = clip.height();
 
-    uint32_t*       device = fDevice.getAddr32(x, y);
-    const uint8_t*  alpha = mask.getAddr(x, y);
-    uint32_t        srcColor = fPMColor;
-    unsigned        devRB = fDevice.rowBytes() - (width << 2);
-    unsigned        maskRB = mask.fRowBytes - width;
+#if defined(SK_SUPPORT_LCDTEXT)
+    const bool      lcdMode = mask.fFormat == SkMask::kHorizontalLCD_Format;
+    const bool      verticalLCDMode = mask.fFormat == SkMask::kVerticalLCD_Format;
+#endif
 
+    // In LCD mode the masks have either an extra couple of rows or columns on the edges.
+    uint32_t        srcColor = fPMColor;
+
+#if defined(SK_SUPPORT_LCDTEXT)
+    if (lcdMode || verticalLCDMode) {
+        int widthAdjustment, heightAdjustment;
+        const uint32_t* alpha32;
+        uint32_t* device = adjustForSubpixelClip(mask, clip, fDevice, &widthAdjustment, &heightAdjustment, &alpha32);
+
+        width += widthAdjustment;
+        height += heightAdjustment;
+
+        unsigned devRB = fDevice.rowBytes() - (width << 2);
+        unsigned alphaExtraRowWords = mask.rowWordsLCD() - width;
+
+        do {
+            unsigned w = width;
+            do {
+                const uint32_t alphaPixel = *alpha32++;
+                const uint32_t originalPixel = *device;
+                *device++ = BlendLCDPixelWithOpaqueColor(alphaPixel, originalPixel, srcColor);
+            } while (--w != 0);
+            device = (uint32_t*)((char*)device + devRB);
+            alpha32 += alphaExtraRowWords;
+        } while (--height != 0);
+
+        return;
+    }
+#endif
+
+    uint32_t*      device = fDevice.getAddr32(x, y);
+    const uint8_t* alpha = mask.getAddr(x, y);
+    unsigned       maskRB = mask.fRowBytes - width;
+    unsigned       devRB = fDevice.rowBytes() - (width << 2);
     do {
         int w = width;
         do {
@@ -298,18 +350,49 @@
 
         SkARGB32_BlitBW(fDevice, mask, clip, black);
     } else {
-        uint32_t*       device = fDevice.getAddr32(clip.fLeft, clip.fTop);
-        const uint8_t*  alpha = mask.getAddr(clip.fLeft, clip.fTop);
+#if defined(SK_SUPPORT_LCDTEXT)
+        const bool      lcdMode = mask.fFormat == SkMask::kHorizontalLCD_Format;
+        const bool      verticalLCDMode = mask.fFormat == SkMask::kVerticalLCD_Format;
+#endif
+
+        // In LCD mode the masks have either an extra couple of rows or columns on the edges.
         unsigned        width = clip.width();
         unsigned        height = clip.height();
-        unsigned        deviceRB = fDevice.rowBytes() - (width << 2);
-        unsigned        maskRB = mask.fRowBytes - width;
 
         SkASSERT((int)height > 0);
         SkASSERT((int)width > 0);
-        SkASSERT((int)deviceRB >= 0);
-        SkASSERT((int)maskRB >= 0);
 
+#if defined(SK_SUPPORT_LCDTEXT)
+        if (lcdMode || verticalLCDMode) {
+            int widthAdjustment, heightAdjustment;
+            const uint32_t* alpha32;
+            uint32_t* device = adjustForSubpixelClip(mask, clip, fDevice, &widthAdjustment, &heightAdjustment, &alpha32);
+
+            width += widthAdjustment;
+            height += heightAdjustment;
+
+            unsigned deviceRB = fDevice.rowBytes() - (width << 2);
+            unsigned alphaExtraRowWords = mask.rowWordsLCD() - width;
+
+            do {
+                unsigned w = width;
+                do {
+                    const uint32_t alphaPixel = *alpha32++;
+                    const uint32_t originalPixel = *device;
+                    *device++ = BlendLCDPixelWithBlack(alphaPixel, originalPixel);
+                } while (--w != 0);
+                device = (uint32_t*)((char*)device + deviceRB);
+                alpha32 += alphaExtraRowWords;
+            } while (--height != 0);
+
+            return;
+        }
+#endif
+
+        uint32_t*      device = fDevice.getAddr32(clip.fLeft, clip.fTop);
+        unsigned       maskRB = mask.fRowBytes - width;
+        unsigned       deviceRB = fDevice.rowBytes() - (width << 2);
+        const uint8_t* alpha = mask.getAddr(clip.fLeft, clip.fTop);
         do {
             unsigned w = width;
             do {
@@ -482,4 +565,3 @@
         } 
     }
 }
-
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index 2413168..23031c5 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -893,20 +893,28 @@
         return true;
     }
 
-    const SkRectCompareType& clipR = this->getLocalClipBoundsCompareType();
+    if (fMCRec->fMatrix->getType() & SkMatrix::kPerspective_Mask) {
+        SkRect dst;
+        fMCRec->fMatrix->mapRect(&dst, rect);
+        SkIRect idst;
+        dst.roundOut(&idst);
+        return !SkIRect::Intersects(idst, fMCRec->fRegion->getBounds());
+    } else {
+        const SkRectCompareType& clipR = this->getLocalClipBoundsCompareType();
 
-    // for speed, do the most likely reject compares first
-    SkScalarCompareType userT = SkScalarToCompareType(rect.fTop);
-    SkScalarCompareType userB = SkScalarToCompareType(rect.fBottom);
-    if (userT >= clipR.fBottom || userB <= clipR.fTop) {
-        return true;
+        // for speed, do the most likely reject compares first
+        SkScalarCompareType userT = SkScalarToCompareType(rect.fTop);
+        SkScalarCompareType userB = SkScalarToCompareType(rect.fBottom);
+        if (userT >= clipR.fBottom || userB <= clipR.fTop) {
+            return true;
+        }
+        SkScalarCompareType userL = SkScalarToCompareType(rect.fLeft);
+        SkScalarCompareType userR = SkScalarToCompareType(rect.fRight);
+        if (userL >= clipR.fRight || userR <= clipR.fLeft) {
+            return true;
+        }
+        return false;
     }
-    SkScalarCompareType userL = SkScalarToCompareType(rect.fLeft);
-    SkScalarCompareType userR = SkScalarToCompareType(rect.fRight);
-    if (userL >= clipR.fRight || userR <= clipR.fLeft) {
-        return true;
-    }    
-    return false;
 }
 
 bool SkCanvas::quickReject(const SkPath& path, EdgeType et) const {
diff --git a/src/core/SkEdge.cpp b/src/core/SkEdge.cpp
index f790d02..92c78c8 100644
--- a/src/core/SkEdge.cpp
+++ b/src/core/SkEdge.cpp
@@ -419,8 +419,9 @@
     if (clip)
     {
         do {
-            for (;!this->updateCubic();)
-                ;
+            if (!this->updateCubic()) {
+                return 0;
+            }
         } while (!this->intersectsClip(*clip));
         this->chopLineWithClip(*clip);
         return 1;
diff --git a/src/core/SkPaint.cpp b/src/core/SkPaint.cpp
index 8b2a21b..cb78734 100644
--- a/src/core/SkPaint.cpp
+++ b/src/core/SkPaint.cpp
@@ -57,6 +57,7 @@
     fTextAlign  = kLeft_Align;
     fStyle      = kFill_Style;
     fTextEncoding = kUTF8_TextEncoding;
+    fHinting    = kNormal_Hinting;
 }
 
 SkPaint::SkPaint(const SkPaint& src)
@@ -144,6 +145,11 @@
     this->setFlags(SkSetClearMask(fFlags, doSubpixel, kSubpixelText_Flag));
 }
 
+void SkPaint::setLCDRenderText(bool doLCDRender)
+{
+    this->setFlags(SkSetClearMask(fFlags, doLCDRender, kLCDRenderText_Flag));
+}
+
 void SkPaint::setLinearText(bool doLinearText)
 {
     this->setFlags(SkSetClearMask(fFlags, doLinearText, kLinearText_Flag));
@@ -1118,25 +1124,24 @@
 static SkMask::Format computeMaskFormat(const SkPaint& paint)
 {
     uint32_t flags = paint.getFlags();
-    
-    return (flags & SkPaint::kAntiAlias_Flag) ? SkMask::kA8_Format : SkMask::kBW_Format;
+
+    if (flags & SkPaint::kLCDRenderText_Flag)
+#if defined(SK_SUPPORT_LCDTEXT)
+        return SkFontHost::GetSubpixelOrientation() == SkFontHost::kHorizontal_LCDOrientation ?
+                   SkMask::kHorizontalLCD_Format : SkMask::kVerticalLCD_Format;
+#else
+        return SkMask::kA8_Format;
+#endif
+    if (flags & SkPaint::kAntiAlias_Flag)
+        return SkMask::kA8_Format;
+    return SkMask::kBW_Format;
 }
 
-static SkScalerContext::Hints computeScalerHints(const SkPaint& paint)
+void SkScalerContext::MakeRec(const SkPaint& paint,
+                              const SkMatrix* deviceMatrix, Rec* rec)
 {
-    uint32_t flags = paint.getFlags();
-    
-    if (flags & SkPaint::kLinearText_Flag)
-        return SkScalerContext::kNo_Hints;
-    else if (flags & SkPaint::kSubpixelText_Flag)
-        return SkScalerContext::kSubpixel_Hints;
-    else
-        return SkScalerContext::kNormal_Hints;
-}
-
-void SkScalerContext::MakeRec(const SkPaint& paint, const SkMatrix* deviceMatrix, Rec* rec)
-{
-    SkASSERT(deviceMatrix == NULL || (deviceMatrix->getType() & SkMatrix::kPerspective_Mask) == 0);
+    SkASSERT(deviceMatrix == NULL ||
+             (deviceMatrix->getType() & SkMatrix::kPerspective_Mask) == 0);
 
     rec->fFontID = SkTypeface::UniqueID(paint.getTypeface());
     rec->fTextSize = paint.getTextSize();
@@ -1194,9 +1199,17 @@
         rec->fStrokeJoin = 0;
     }
 
-    rec->fHints = SkToU8(computeScalerHints(paint));
+    rec->fSubpixelPositioning = paint.isSubpixelText();
     rec->fMaskFormat = SkToU8(computeMaskFormat(paint));
     rec->fFlags = SkToU8(flags);
+    rec->setHinting(paint.getHinting());
+
+    /*  Allow the fonthost to modify our rec before we use it as a key into the
+        cache. This way if we're asking for something that they will ignore,
+        they can modify our rec up front, so we don't create duplicate cache
+        entries.
+     */
+    SkFontHost::FilterRec(rec);
 }
 
 #define MIN_SIZE_FOR_EFFECT_BUFFER  1024
diff --git a/src/core/SkPath.cpp b/src/core/SkPath.cpp
index 082d2e8..794681c 100644
--- a/src/core/SkPath.cpp
+++ b/src/core/SkPath.cpp
@@ -986,8 +986,8 @@
         // A special case: if both points are NaN, SkPoint::operation== returns
         // false, but the iterator expects that they are treated as the same.
         // (consider SkPoint is a 2-dimension float point).
-        if (SkScalarIsNaN(fLastPt.fX) && SkScalarIsNaN(fLastPt.fY) &&
-            SkScalarIsNaN(fMoveTo.fX) && SkScalarIsNaN(fMoveTo.fY)) {
+        if (SkScalarIsNaN(fLastPt.fX) || SkScalarIsNaN(fLastPt.fY) ||
+            SkScalarIsNaN(fMoveTo.fX) || SkScalarIsNaN(fMoveTo.fY)) {
             return kClose_Verb;
         }
 
diff --git a/src/core/SkScalerContext.cpp b/src/core/SkScalerContext.cpp
index 7d66c2a..eab015a 100644
--- a/src/core/SkScalerContext.cpp
+++ b/src/core/SkScalerContext.cpp
@@ -16,6 +16,7 @@
 */
 
 #include "SkScalerContext.h"
+#include "SkColorPriv.h"
 #include "SkDescriptor.h"
 #include "SkDraw.h"
 #include "SkFontHost.h"
@@ -45,11 +46,18 @@
 }
 
 size_t SkGlyph::computeImageSize() const {
-    size_t size = this->rowBytes() * fHeight;
-    if (fMaskFormat == SkMask::k3D_Format) {
-        size *= 3;
+    const size_t size = this->rowBytes() * fHeight;
+
+    switch (fMaskFormat) {
+    case SkMask::kHorizontalLCD_Format:
+        return SkAlign4(size) + sizeof(uint32_t) * ((fWidth + 2) * fHeight);
+    case SkMask::kVerticalLCD_Format:
+        return SkAlign4(size) + sizeof(uint32_t) * (fWidth * (fHeight + 2));
+    case SkMask::k3D_Format:
+        return 3 * size;
+    default:
+        return size;
     }
-    return size;
 }
 
 void SkGlyph::zeroMetrics() {
@@ -63,6 +71,48 @@
     fLsbDelta = 0;
 }
 
+void SkGlyph::expandA8ToLCD() const {
+    SkASSERT(fMaskFormat == SkMask::kHorizontalLCD_Format ||
+             fMaskFormat == SkMask::kVerticalLCD_Format);
+
+#if defined(SK_SUPPORT_LCDTEXT)
+    uint8_t* input = reinterpret_cast<uint8_t*>(fImage);
+    uint32_t* output = reinterpret_cast<uint32_t*>(input + SkAlign4(rowBytes() * fHeight));
+
+    if (fMaskFormat == SkMask::kHorizontalLCD_Format) {
+        for (unsigned y = 0; y < fHeight; ++y) {
+            const uint8_t* inputRow = input;
+            *output++ = 0;  // make the extra column on the left clear
+            for (unsigned x = 0; x < fWidth; ++x) {
+                const uint8_t alpha = *inputRow++;
+                *output++ = SkPackARGB32(alpha, alpha, alpha, alpha);
+            }
+            *output++ = 0;
+
+            input += rowBytes();
+        }
+    } else {
+        const unsigned outputRowBytes = sizeof(uint32_t) * fWidth;
+        memset(output, 0, outputRowBytes);
+        output += fWidth;
+
+        for (unsigned y = 0; y < fHeight; ++y) {
+            const uint8_t* inputRow = input;
+            for (unsigned x = 0; x < fWidth; ++x) {
+                const uint8_t alpha = *inputRow++;
+                *output++ = SkPackARGB32(alpha, alpha, alpha, alpha);
+            }
+
+            input += rowBytes();
+        }
+
+        memset(output, 0, outputRowBytes);
+        output += fWidth;
+    }
+#else
+#endif
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 #ifdef SK_DEBUG
@@ -329,6 +379,9 @@
 
         this->internalGetPath(*glyph, &fillPath, &devPath, &fillToDevMatrix);
 
+        const bool lcdMode = fRec.fMaskFormat == SkMask::kHorizontalLCD_Format ||
+                             fRec.fMaskFormat == SkMask::kVerticalLCD_Format;
+
         if (fRasterizer) {
             SkMask  mask;
             
@@ -349,7 +402,7 @@
             SkPaint     paint;
             SkDraw      draw;
 
-            if (SkMask::kA8_Format == fRec.fMaskFormat) {
+            if (SkMask::kA8_Format == fRec.fMaskFormat || lcdMode) {
                 config = SkBitmap::kA8_Config;
                 paint.setAntiAlias(true);
             } else {
@@ -372,6 +425,9 @@
             draw.fBounder = NULL;
             draw.drawPath(devPath, paint);
         }
+
+        if (lcdMode)
+            glyph->expandA8ToLCD();
     } else {
         this->getGlyphContext(*glyph)->generateImage(*glyph);
     }
diff --git a/src/core/SkScan_Path.cpp b/src/core/SkScan_Path.cpp
index ead1b85..211259f 100644
--- a/src/core/SkScan_Path.cpp
+++ b/src/core/SkScan_Path.cpp
@@ -479,10 +479,9 @@
     SkEdge          headEdge, tailEdge, *last;
 
     SkASSERT(count <= maxCount);
-    if (count == 0) {
+    if (count < 2) {
         return;
     }
-    SkASSERT(count > 1);
 
     // this returns the first and last edge after they're sorted into a dlink list
     edge = sort_edges(list, count, &last);
diff --git a/src/ports/SkFontHost_FreeType.cpp b/src/ports/SkFontHost_FreeType.cpp
index b30aba5..dbba1a2 100644
--- a/src/ports/SkFontHost_FreeType.cpp
+++ b/src/ports/SkFontHost_FreeType.cpp
@@ -15,6 +15,7 @@
 ** limitations under the License.
 */
 
+#include "SkColorPriv.h"
 #include "SkScalerContext.h"
 #include "SkBitmap.h"
 #include "SkCanvas.h"
@@ -32,6 +33,11 @@
 #include FT_OUTLINE_H
 #include FT_SIZES_H
 #include FT_TRUETYPE_TABLES_H
+
+#if defined(SK_SUPPORT_LCDTEXT)
+#include FT_LCD_FILTER_H
+#endif
+
 #ifdef   FT_ADVANCES_H
 #include FT_ADVANCES_H
 #endif
@@ -43,6 +49,7 @@
 #include <freetype/ftsizes.h>
 #include <freetype/tttables.h>
 #include <freetype/ftadvanc.h>
+#include <freetype/ftlcdfil.h>
 #endif
 
 //#define ENABLE_GLYPH_SPEW     // for tracing calls
@@ -69,6 +76,21 @@
 
 /////////////////////////////////////////////////////////////////////////
 
+static bool
+InitFreetype() {
+    FT_Error err = FT_Init_FreeType(&gFTLibrary);
+    if (err)
+        return false;
+
+#if defined(SK_SUPPORT_LCDTEXT)
+    // Setup LCD filtering. This reduces colour fringes for LCD rendered
+    // glyphs.
+    err = FT_Library_SetLcdFilter(gFTLibrary, FT_LCD_FILTER_DEFAULT);
+#endif
+
+    return true;
+}
+
 class SkScalerContext_FreeType : public SkScalerContext {
 public:
     SkScalerContext_FreeType(const SkDescriptor* desc);
@@ -240,16 +262,26 @@
 
 ///////////////////////////////////////////////////////////////////////////
 
+void SkFontHost::FilterRec(SkScalerContext::Rec* rec) {
+    SkPaint::Hinting h = rec->getHinting();
+    if (SkPaint::kFull_Hinting == h && !rec->isLCD()) {
+        // collapse full->normaling hinting if we're not doing LCD
+        h = SkPaint::kNormal_Hinting;
+    } else if (rec->fSubpixelPositioning && SkPaint::kNo_Hinting != h) {
+        // to do subpixel, we must have at most slight hinting
+        h = SkPaint::kSlight_Hinting;
+    }
+    rec->setHinting(h);
+}
+
 SkScalerContext_FreeType::SkScalerContext_FreeType(const SkDescriptor* desc)
         : SkScalerContext(desc) {
     SkAutoMutexAcquire  ac(gFTMutex);
 
-    FT_Error    err;
-
     if (gFTCount == 0) {
-        err = FT_Init_FreeType(&gFTLibrary);
-//        SkDEBUGF(("FT_Init_FreeType returned %d\n", err));
-        SkASSERT(err == 0);
+        if (!InitFreetype()) {
+            sk_throw();
+        }
     }
     ++gFTCount;
 
@@ -275,7 +307,7 @@
            SkScalarToFloat(fRec.fPreScaleX), SkScalarToFloat(fRec.fPreSkewX),
            SkScalarToFloat(fRec.fPost2x2[0][0]), SkScalarToFloat(fRec.fPost2x2[0][1]),
            SkScalarToFloat(fRec.fPost2x2[1][0]), SkScalarToFloat(fRec.fPost2x2[1][1]),
-           fRec.fHints, fRec.fMaskFormat, keyString.c_str());
+           fRec.getHinting(), fRec.fMaskFormat, keyString.c_str());
 #endif
 
     //  now compute our scale factors
@@ -305,42 +337,31 @@
 
     // compute the flags we send to Load_Glyph
     {
-        uint32_t flags = FT_LOAD_DEFAULT;
-        uint32_t render_flags = FT_LOAD_TARGET_NORMAL;
+        FT_Int32 loadFlags = FT_LOAD_DEFAULT;
 
-        // we force autohinting at the moment
-
-        switch (fRec.fHints) {
-        case kNo_Hints:
-            flags |= FT_LOAD_NO_HINTING;
+        switch (fRec.getHinting()) {
+        case SkPaint::kNo_Hinting:
+            loadFlags = FT_LOAD_NO_HINTING;
             break;
-        case kSubpixel_Hints:
-            flags |= FT_LOAD_FORCE_AUTOHINT;
-            render_flags = FT_LOAD_TARGET_LIGHT;
+        case SkPaint::kSlight_Hinting:
+            loadFlags = FT_LOAD_TARGET_LIGHT;  // This implies FORCE_AUTOHINT
             break;
-        case kNormal_Hints:
-#ifdef ANDROID
-            // The following line disables the font's hinting tables. For
-            // Chromium we want font hinting on so that we can generate
-            // baselines that look at little like Firefox. It's expected that
-            // Mike Reed will rework this code sometime soon so we don't wish
-            // to make more extensive changes.
-            flags |= FT_LOAD_FORCE_AUTOHINT;
-            /*  Switch to light hinting (vertical only) to address some chars
-                that behaved poorly with NORMAL. In the future we could consider
-                making this choice exposed at runtime to the caller.
-            */
-            render_flags = FT_LOAD_TARGET_LIGHT;
-#endif
+        case SkPaint::kNormal_Hinting:
+            loadFlags = FT_LOAD_TARGET_NORMAL;
+            break;
+        case SkPaint::kFull_Hinting:
+            loadFlags = FT_LOAD_TARGET_NORMAL;
+            if (SkMask::kHorizontalLCD_Format == fRec.fMaskFormat)
+                loadFlags = FT_LOAD_TARGET_LCD;
+            else if (SkMask::kVerticalLCD_Format == fRec.fMaskFormat)
+                loadFlags = FT_LOAD_TARGET_LCD_V;
+            break;
+        default:
+            SkDebugf("---------- UNKNOWN hinting %d\n", fRec.getHinting());
             break;
         }
 
-        if (SkMask::kBW_Format == fRec.fMaskFormat)
-            render_flags = FT_LOAD_TARGET_MONO;
-        else if (SkMask::kLCD_Format == fRec.fMaskFormat)
-            render_flags = FT_LOAD_TARGET_LCD;
-
-        fLoadGlyphFlags = flags | render_flags;
+        fLoadGlyphFlags = loadFlags;
     }
 
     // now create the FT_Size
@@ -433,10 +454,12 @@
 
 static FT_Pixel_Mode compute_pixel_mode(SkMask::Format format) {
     switch (format) {
+        case SkMask::kHorizontalLCD_Format:
+        case SkMask::kVerticalLCD_Format:
+            SkASSERT(!"An LCD format should never be passed here");
+            return FT_PIXEL_MODE_GRAY;
         case SkMask::kBW_Format:
             return FT_PIXEL_MODE_MONO;
-        case SkMask::kLCD_Format:
-            return FT_PIXEL_MODE_LCD;
         case SkMask::kA8_Format:
         default:
             return FT_PIXEL_MODE_GRAY;
@@ -503,7 +526,7 @@
 
         FT_Outline_Get_CBox(&fFace->glyph->outline, &bbox);
 
-        if (kSubpixel_Hints == fRec.fHints) {
+        if (fRec.fSubpixelPositioning) {
             int dx = glyph->getSubXFixed() >> 10;
             int dy = glyph->getSubYFixed() >> 10;
             // negate dy since freetype-y-goes-up and skia-y-goes-down
@@ -536,7 +559,7 @@
         goto ERROR;
     }
 
-    if (kNormal_Hints == fRec.fHints) {
+    if (!fRec.fSubpixelPositioning) {
         glyph->fAdvanceX = SkFDot6ToFixed(fFace->glyph->advance.x);
         glyph->fAdvanceY = -SkFDot6ToFixed(fFace->glyph->advance.y);
         if (fRec.fFlags & kDevKernText_Flag) {
@@ -554,6 +577,16 @@
 #endif
 }
 
+#if defined(SK_SUPPORT_LCDTEXT)
+namespace skia_freetype_support {
+// extern functions from SkFontHost_FreeType_Subpixel
+extern void CopyFreetypeBitmapToLCDMask(const SkGlyph& dest, const FT_Bitmap& source);
+extern void CopyFreetypeBitmapToVerticalLCDMask(const SkGlyph& dest, const FT_Bitmap& source);
+}
+
+using namespace skia_freetype_support;
+#endif
+
 void SkScalerContext_FreeType::generateImage(const SkGlyph& glyph) {
     SkAutoMutexAcquire  ac(gFTMutex);
 
@@ -572,6 +605,9 @@
         return;
     }
 
+    const bool lcdRenderMode = fRec.fMaskFormat == SkMask::kHorizontalLCD_Format ||
+                               fRec.fMaskFormat == SkMask::kVerticalLCD_Format;
+
     switch ( fFace->glyph->format ) {
         case FT_GLYPH_FORMAT_OUTLINE: {
             FT_Outline* outline = &fFace->glyph->outline;
@@ -579,7 +615,7 @@
             FT_Bitmap   target;
 
             int dx = 0, dy = 0;
-            if (kSubpixel_Hints == fRec.fHints) {
+            if (fRec.fSubpixelPositioning) {
                 dx = glyph.getSubXFixed() >> 10;
                 dy = glyph.getSubYFixed() >> 10;
                 // negate dy since freetype-y-goes-up and skia-y-goes-down
@@ -597,6 +633,23 @@
             FT_Outline_Translate(outline, dx - ((bbox.xMin + dx) & ~63),
                                           dy - ((bbox.yMin + dy) & ~63));
 
+#if defined(SK_SUPPORT_LCDTEXT)
+            if (lcdRenderMode) {
+                // FT_Outline_Get_Bitmap cannot render LCD glyphs. In this case
+                // we have to call FT_Render_Glyph and memcpy the image out.
+                const bool isVertical = fRec.fMaskFormat == SkMask::kVerticalLCD_Format;
+                FT_Render_Mode mode = isVertical ? FT_RENDER_MODE_LCD_V : FT_RENDER_MODE_LCD;
+                FT_Render_Glyph(fFace->glyph, mode);
+
+                if (isVertical)
+                    CopyFreetypeBitmapToVerticalLCDMask(glyph, fFace->glyph->bitmap);
+                else
+                    CopyFreetypeBitmapToLCDMask(glyph, fFace->glyph->bitmap);
+
+                break;
+            }
+#endif
+
             target.width = glyph.fWidth;
             target.rows = glyph.fHeight;
             target.pitch = glyph.rowBytes();
@@ -652,6 +705,10 @@
                     dst += glyph.rowBytes();
                 }
             }
+
+            if (lcdRenderMode)
+                glyph.expandA8ToLCD();
+
         } break;
 
     default:
@@ -905,4 +962,3 @@
     FT_Done_FreeType(library);
     return (SkTypeface::Style)style;
 }
-