merge mozilla-inbound to mozilla-central a=merge
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Mon, 21 Dec 2015 11:52:31 +0100
changeset 277096 e6ba2d4a2e4930bb359f90312ef6f1ebdc34c0ac
parent 276993 091d6785608297bab2cf36b1b6a2d9a388b82a01 (current diff)
parent 277095 3a206e2652fc66e9ddea0228c120fa9986ef62b6 (diff)
child 277097 a8acaa9868df4aa8d801725cfa9ef744640fc402
child 277105 346a1b4ebe6fb6198f0707f0fe6c5038d374132b
child 277133 3f3f0361567c418a2f7c23a1930ba8ac953d3358
child 277181 8b3dc716047288e0cb92fc1a2ae25ef4a40c6569
push id29814
push usercbook@mozilla.com
push dateMon, 21 Dec 2015 10:52:58 +0000
treeherdermozilla-central@e6ba2d4a2e49 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone46.0a1
first release with
nightly linux32
e6ba2d4a2e49 / 46.0a1 / 20151221030239 / files
nightly linux64
e6ba2d4a2e49 / 46.0a1 / 20151221030239 / files
nightly mac
e6ba2d4a2e49 / 46.0a1 / 20151221030239 / files
nightly win32
e6ba2d4a2e49 / 46.0a1 / 20151221030239 / files
nightly win64
e6ba2d4a2e49 / 46.0a1 / 20151221030239 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
merge mozilla-inbound to mozilla-central a=merge
gfx/skia/skia/include/core/SkAdvancedTypefaceMetrics.h
gfx/skia/skia/include/core/SkColorShader.h
gfx/skia/skia/include/core/SkDeviceProperties.h
gfx/skia/skia/include/core/SkDrawPictureCallback.h
gfx/skia/skia/include/core/SkDynamicAnnotations.h
gfx/skia/skia/include/core/SkEndian.h
gfx/skia/skia/include/core/SkFlattenableBuffers.h
gfx/skia/skia/include/core/SkFloatBits.h
gfx/skia/skia/include/core/SkFloatingPoint.h
gfx/skia/skia/include/core/SkInstCnt.h
gfx/skia/skia/include/core/SkOnce.h
gfx/skia/skia/include/core/SkPaintOptionsAndroid.h
gfx/skia/skia/include/core/SkPatch.h
gfx/skia/skia/include/core/SkReadBuffer.h
gfx/skia/skia/include/core/SkReader32.h
gfx/skia/skia/include/core/SkTemplates.h
gfx/skia/skia/include/core/SkThread.h
gfx/skia/skia/include/core/SkWeakRefCnt.h
gfx/skia/skia/include/effects/SkAvoidXfermode.h
gfx/skia/skia/include/effects/SkBitmapSource.h
gfx/skia/skia/include/effects/SkMatrixImageFilter.h
gfx/skia/skia/include/effects/SkPorterDuff.h
gfx/skia/skia/include/effects/SkStippleMaskFilter.h
gfx/skia/skia/include/effects/SkTransparentShader.h
gfx/skia/skia/include/gpu/GrBackendEffectFactory.h
gfx/skia/skia/include/gpu/GrClipData.h
gfx/skia/skia/include/gpu/GrContextFactory.h
gfx/skia/skia/include/gpu/GrDrawEffect.h
gfx/skia/skia/include/gpu/GrEffect.h
gfx/skia/skia/include/gpu/GrEffectStage.h
gfx/skia/skia/include/gpu/GrEffectUnitTest.h
gfx/skia/skia/include/gpu/GrFontScaler.h
gfx/skia/skia/include/gpu/GrGlyph.h
gfx/skia/skia/include/gpu/GrPathRendererChain.h
gfx/skia/skia/include/gpu/GrTBackendEffectFactory.h
gfx/skia/skia/include/gpu/GrUserConfig.h
gfx/skia/skia/include/gpu/SkGpuDevice.h
gfx/skia/skia/include/gpu/gl/SkANGLEGLContext.h
gfx/skia/skia/include/gpu/gl/SkDebugGLContext.h
gfx/skia/skia/include/gpu/gl/SkGLContextHelper.h
gfx/skia/skia/include/gpu/gl/SkMesaGLContext.h
gfx/skia/skia/include/gpu/gl/SkNativeGLContext.h
gfx/skia/skia/include/pdf/SkPDFDevice.h
gfx/skia/skia/include/pdf/SkPDFDocument.h
gfx/skia/skia/include/ports/SkFontStyle.h
gfx/skia/skia/include/ports/SkTypeface_android.h
gfx/skia/skia/include/record/SkRecording.h
gfx/skia/skia/include/svg/SkSVGAttribute.h
gfx/skia/skia/include/svg/SkSVGBase.h
gfx/skia/skia/include/svg/SkSVGPaintState.h
gfx/skia/skia/include/svg/SkSVGParser.h
gfx/skia/skia/include/svg/SkSVGTypes.h
gfx/skia/skia/include/utils/SkCondVar.h
gfx/skia/skia/include/utils/SkDeferredCanvas.h
gfx/skia/skia/include/utils/SkPathUtils.h
gfx/skia/skia/include/utils/SkProxyCanvas.h
gfx/skia/skia/include/utils/SkRunnable.h
gfx/skia/skia/include/utils/SkThreadPool.h
gfx/skia/skia/include/utils/SkWGL.h
gfx/skia/skia/include/utils/ios/SkStream_NSData.h
gfx/skia/skia/include/views/SkOSWindow_NaCl.h
gfx/skia/skia/include/views/SkTextBox.h
gfx/skia/skia/include/views/android/AndroidKeyToSkKey.h
gfx/skia/skia/include/views/unix/XkeysToSkKeys.h
gfx/skia/skia/include/views/unix/keysym2ucs.h
gfx/skia/skia/include/xml/SkJS.h
gfx/skia/skia/src/animator/SkDrawTransparentShader.cpp
gfx/skia/skia/src/animator/SkDrawTransparentShader.h
gfx/skia/skia/src/animator/SkDrawable.cpp
gfx/skia/skia/src/animator/SkDrawable.h
gfx/skia/skia/src/core/SkBBoxHierarchyRecord.cpp
gfx/skia/skia/src/core/SkBBoxHierarchyRecord.h
gfx/skia/skia/src/core/SkBBoxRecord.cpp
gfx/skia/skia/src/core/SkBBoxRecord.h
gfx/skia/skia/src/core/SkBitmap_scroll.cpp
gfx/skia/skia/src/core/SkChecksum.h
gfx/skia/skia/src/core/SkDeviceImageFilterProxy.h
gfx/skia/skia/src/core/SkFlate.cpp
gfx/skia/skia/src/core/SkFlate.h
gfx/skia/skia/src/core/SkFloat.cpp
gfx/skia/skia/src/core/SkFloat.h
gfx/skia/skia/src/core/SkGlyphCache.cpp
gfx/skia/skia/src/core/SkInstCnt.cpp
gfx/skia/skia/src/core/SkLazyFnPtr.h
gfx/skia/skia/src/core/SkLazyPtr.h
gfx/skia/skia/src/core/SkMatrixClipStateMgr.cpp
gfx/skia/skia/src/core/SkMatrixClipStateMgr.h
gfx/skia/skia/src/core/SkPaintOptionsAndroid.cpp
gfx/skia/skia/src/core/SkPatch.cpp
gfx/skia/skia/src/core/SkPathHeap.cpp
gfx/skia/skia/src/core/SkPathHeap.h
gfx/skia/skia/src/core/SkPictureRangePlayback.cpp
gfx/skia/skia/src/core/SkPictureRangePlayback.h
gfx/skia/skia/src/core/SkPictureReplacementPlayback.cpp
gfx/skia/skia/src/core/SkPictureReplacementPlayback.h
gfx/skia/skia/src/core/SkPictureStateTree.cpp
gfx/skia/skia/src/core/SkPictureStateTree.h
gfx/skia/skia/src/core/SkProcSpriteBlitter.cpp
gfx/skia/skia/src/core/SkQuadTree.cpp
gfx/skia/skia/src/core/SkQuadTree.h
gfx/skia/skia/src/core/SkRecordAnalysis.cpp
gfx/skia/skia/src/core/SkRecordAnalysis.h
gfx/skia/skia/src/core/SkRecording.cpp
gfx/skia/skia/src/core/SkRecords.h
gfx/skia/skia/src/core/SkScaledImageCache.cpp
gfx/skia/skia/src/core/SkScaledImageCache.h
gfx/skia/skia/src/core/SkSinTable.h
gfx/skia/skia/src/core/SkTInternalSList.h
gfx/skia/skia/src/core/SkTObjectPool.h
gfx/skia/skia/src/core/SkTRefArray.h
gfx/skia/skia/src/core/SkThreadPriv.h
gfx/skia/skia/src/core/SkTileGrid.cpp
gfx/skia/skia/src/core/SkTileGrid.h
gfx/skia/skia/src/effects/SkAvoidXfermode.cpp
gfx/skia/skia/src/effects/SkBitmapSource.cpp
gfx/skia/skia/src/effects/SkColorFilterImageFilter.cpp
gfx/skia/skia/src/effects/SkMatrixImageFilter.cpp
gfx/skia/skia/src/effects/SkPorterDuff.cpp
gfx/skia/skia/src/effects/SkStippleMaskFilter.cpp
gfx/skia/skia/src/effects/SkTransparentShader.cpp
gfx/skia/skia/src/effects/gradients/SkBitmapCache.cpp
gfx/skia/skia/src/effects/gradients/SkBitmapCache.h
gfx/skia/skia/src/effects/gradients/SkTwoPointRadialGradient.cpp
gfx/skia/skia/src/effects/gradients/SkTwoPointRadialGradient.h
gfx/skia/skia/src/gpu/GrAAConvexPathRenderer.cpp
gfx/skia/skia/src/gpu/GrAAConvexPathRenderer.h
gfx/skia/skia/src/gpu/GrAAHairLinePathRenderer.cpp
gfx/skia/skia/src/gpu/GrAAHairLinePathRenderer.h
gfx/skia/skia/src/gpu/GrAARectRenderer.cpp
gfx/skia/skia/src/gpu/GrAARectRenderer.h
gfx/skia/skia/src/gpu/GrAddPathRenderers_default.cpp
gfx/skia/skia/src/gpu/GrAllocPool.cpp
gfx/skia/skia/src/gpu/GrAllocPool.h
gfx/skia/skia/src/gpu/GrAtlas.cpp
gfx/skia/skia/src/gpu/GrAtlas.h
gfx/skia/skia/src/gpu/GrBinHashKey.h
gfx/skia/skia/src/gpu/GrBitmapTextContext.cpp
gfx/skia/skia/src/gpu/GrBitmapTextContext.h
gfx/skia/skia/src/gpu/GrBlend.h
gfx/skia/skia/src/gpu/GrCacheID.cpp
gfx/skia/skia/src/gpu/GrClipData.cpp
gfx/skia/skia/src/gpu/GrClipMaskCache.cpp
gfx/skia/skia/src/gpu/GrClipMaskCache.h
gfx/skia/skia/src/gpu/GrContext.cpp
gfx/skia/skia/src/gpu/GrDefaultPathRenderer.cpp
gfx/skia/skia/src/gpu/GrDefaultPathRenderer.h
gfx/skia/skia/src/gpu/GrDistanceFieldTextContext.cpp
gfx/skia/skia/src/gpu/GrDistanceFieldTextContext.h
gfx/skia/skia/src/gpu/GrDrawState.cpp
gfx/skia/skia/src/gpu/GrDrawState.h
gfx/skia/skia/src/gpu/GrDrawTargetCaps.h
gfx/skia/skia/src/gpu/GrEffect.cpp
gfx/skia/skia/src/gpu/GrInOrderDrawBuffer.cpp
gfx/skia/skia/src/gpu/GrInOrderDrawBuffer.h
gfx/skia/skia/src/gpu/GrOrderedSet.h
gfx/skia/skia/src/gpu/GrPictureUtils.cpp
gfx/skia/skia/src/gpu/GrPictureUtils.h
gfx/skia/skia/src/gpu/GrPlotMgr.h
gfx/skia/skia/src/gpu/GrRectanizer_skyline.cpp
gfx/skia/skia/src/gpu/GrRedBlackTree.h
gfx/skia/skia/src/gpu/GrStencilAndCoverPathRenderer.cpp
gfx/skia/skia/src/gpu/GrStencilAndCoverPathRenderer.h
gfx/skia/skia/src/gpu/GrStencilBuffer.cpp
gfx/skia/skia/src/gpu/GrStencilBuffer.h
gfx/skia/skia/src/gpu/GrTBSearch.h
gfx/skia/skia/src/gpu/GrTHashTable.h
gfx/skia/skia/src/gpu/GrTemplates.h
gfx/skia/skia/src/gpu/GrTextStrike.cpp
gfx/skia/skia/src/gpu/GrTextStrike.h
gfx/skia/skia/src/gpu/GrTextStrike_impl.h
gfx/skia/skia/src/gpu/effects/GrCustomCoordsTextureEffect.cpp
gfx/skia/skia/src/gpu/effects/GrCustomCoordsTextureEffect.h
gfx/skia/skia/src/gpu/effects/GrDistanceFieldTextureEffect.cpp
gfx/skia/skia/src/gpu/effects/GrDistanceFieldTextureEffect.h
gfx/skia/skia/src/gpu/effects/GrVertexEffect.h
gfx/skia/skia/src/gpu/gl/GrGLAssembleGLESInterface.h
gfx/skia/skia/src/gpu/gl/GrGLEffect.h
gfx/skia/skia/src/gpu/gl/GrGLProgramEffects.cpp
gfx/skia/skia/src/gpu/gl/GrGLProgramEffects.h
gfx/skia/skia/src/gpu/gl/GrGLSL.cpp
gfx/skia/skia/src/gpu/gl/GrGLSL.h
gfx/skia/skia/src/gpu/gl/GrGLSL_impl.h
gfx/skia/skia/src/gpu/gl/GrGLShaderBuilder.cpp
gfx/skia/skia/src/gpu/gl/GrGLShaderBuilder.h
gfx/skia/skia/src/gpu/gl/GrGLShaderVar.h
gfx/skia/skia/src/gpu/gl/GrGLStencilBuffer.cpp
gfx/skia/skia/src/gpu/gl/GrGLStencilBuffer.h
gfx/skia/skia/src/gpu/gl/GrGLUniformHandle.h
gfx/skia/skia/src/gpu/gl/GrGLUniformManager.cpp
gfx/skia/skia/src/gpu/gl/GrGLUniformManager.h
gfx/skia/skia/src/gpu/gl/GrGLVertexEffect.h
gfx/skia/skia/src/gpu/gl/GrGpuGL.cpp
gfx/skia/skia/src/gpu/gl/GrGpuGL.h
gfx/skia/skia/src/gpu/gl/GrGpuGL_program.cpp
gfx/skia/skia/src/gpu/gl/SkGLContextHelper.cpp
gfx/skia/skia/src/gpu/gl/android/SkNativeGLContext_android.cpp
gfx/skia/skia/src/gpu/gl/iOS/SkNativeGLContext_iOS.mm
gfx/skia/skia/src/gpu/gl/mac/SkNativeGLContext_mac.cpp
gfx/skia/skia/src/gpu/gl/nacl/SkNativeGLContext_nacl.cpp
gfx/skia/skia/src/gpu/gl/unix/GrGLCreateNativeInterface_unix.cpp
gfx/skia/skia/src/gpu/gl/unix/SkNativeGLContext_unix.cpp
gfx/skia/skia/src/gpu/gl/win/SkNativeGLContext_win.cpp
gfx/skia/skia/src/image/SkImagePriv.cpp
gfx/skia/skia/src/image/SkImage_Codec.cpp
gfx/skia/skia/src/lazy/SkCachingPixelRef.cpp
gfx/skia/skia/src/lazy/SkCachingPixelRef.h
gfx/skia/skia/src/opts/SkBlitRect_opts_SSE2.cpp
gfx/skia/skia/src/opts/SkBlitRect_opts_SSE2.h
gfx/skia/skia/src/opts/SkBlitRow_opts_SSE4_asm.S
gfx/skia/skia/src/opts/SkBlitRow_opts_SSE4_x64_asm.S
gfx/skia/skia/src/opts/SkBlurImage_opts.h
gfx/skia/skia/src/opts/SkBlurImage_opts_SSE2.cpp
gfx/skia/skia/src/opts/SkBlurImage_opts_SSE2.h
gfx/skia/skia/src/opts/SkBlurImage_opts_SSE4.cpp
gfx/skia/skia/src/opts/SkBlurImage_opts_SSE4.h
gfx/skia/skia/src/opts/SkBlurImage_opts_arm.cpp
gfx/skia/skia/src/opts/SkBlurImage_opts_neon.cpp
gfx/skia/skia/src/opts/SkBlurImage_opts_neon.h
gfx/skia/skia/src/opts/SkBlurImage_opts_none.cpp
gfx/skia/skia/src/opts/SkMath_opts_SSE2.h
gfx/skia/skia/src/opts/SkMorphology_opts.h
gfx/skia/skia/src/opts/SkMorphology_opts_SSE2.cpp
gfx/skia/skia/src/opts/SkMorphology_opts_SSE2.h
gfx/skia/skia/src/opts/SkMorphology_opts_arm.cpp
gfx/skia/skia/src/opts/SkMorphology_opts_neon.cpp
gfx/skia/skia/src/opts/SkMorphology_opts_neon.h
gfx/skia/skia/src/opts/SkMorphology_opts_none.cpp
gfx/skia/skia/src/opts/SkTextureCompression_opts.h
gfx/skia/skia/src/opts/SkTextureCompression_opts_arm.cpp
gfx/skia/skia/src/opts/SkTextureCompression_opts_neon.cpp
gfx/skia/skia/src/opts/SkTextureCompression_opts_neon.h
gfx/skia/skia/src/opts/SkTextureCompression_opts_none.cpp
gfx/skia/skia/src/opts/SkUtils_opts_SSE2.cpp
gfx/skia/skia/src/opts/SkUtils_opts_SSE2.h
gfx/skia/skia/src/opts/SkUtils_opts_arm.cpp
gfx/skia/skia/src/opts/SkUtils_opts_none.cpp
gfx/skia/skia/src/opts/SkXfermode_opts_SSE2.cpp
gfx/skia/skia/src/opts/SkXfermode_opts_SSE2.h
gfx/skia/skia/src/opts/SkXfermode_opts_arm.cpp
gfx/skia/skia/src/opts/SkXfermode_opts_arm_neon.cpp
gfx/skia/skia/src/opts/SkXfermode_opts_arm_neon.h
gfx/skia/skia/src/opts/SkXfermode_opts_none.cpp
gfx/skia/skia/src/opts/memset.arm.S
gfx/skia/skia/src/opts/memset16_neon.S
gfx/skia/skia/src/opts/memset32_neon.S
gfx/skia/skia/src/pathops/SkDCubicIntersection.cpp
gfx/skia/skia/src/pathops/SkDQuadImplicit.cpp
gfx/skia/skia/src/pathops/SkDQuadImplicit.h
gfx/skia/skia/src/pathops/SkDQuadIntersection.cpp
gfx/skia/skia/src/pathops/SkPathOpsBounds.cpp
gfx/skia/skia/src/pathops/SkPathOpsTriangle.cpp
gfx/skia/skia/src/pathops/SkPathOpsTriangle.h
gfx/skia/skia/src/pathops/SkQuarticRoot.cpp
gfx/skia/skia/src/pathops/SkQuarticRoot.h
gfx/skia/skia/src/pdf/SkPDFCatalog.cpp
gfx/skia/skia/src/pdf/SkPDFCatalog.h
gfx/skia/skia/src/pdf/SkPDFDeviceFlattener.cpp
gfx/skia/skia/src/pdf/SkPDFDeviceFlattener.h
gfx/skia/skia/src/pdf/SkPDFDocument.cpp
gfx/skia/skia/src/pdf/SkPDFImage.cpp
gfx/skia/skia/src/pdf/SkPDFImage.h
gfx/skia/skia/src/pdf/SkPDFPage.cpp
gfx/skia/skia/src/pdf/SkPDFPage.h
gfx/skia/skia/src/pdf/SkTSet.h
gfx/skia/skia/src/ports/SkAtomics_sync.h
gfx/skia/skia/src/ports/SkAtomics_win.h
gfx/skia/skia/src/ports/SkBarriers_arm.h
gfx/skia/skia/src/ports/SkBarriers_tsan.h
gfx/skia/skia/src/ports/SkBarriers_x86.h
gfx/skia/skia/src/ports/SkDebug_nacl.cpp
gfx/skia/skia/src/ports/SkFontConfigInterface_android.cpp
gfx/skia/skia/src/ports/SkFontConfigParser_android.cpp
gfx/skia/skia/src/ports/SkFontConfigParser_android.h
gfx/skia/skia/src/ports/SkFontHost_android_old.cpp
gfx/skia/skia/src/ports/SkFontHost_linux.cpp
gfx/skia/skia/src/ports/SkFontHost_mac.cpp
gfx/skia/skia/src/ports/SkFontHost_none.cpp
gfx/skia/skia/src/ports/SkFontHost_win.cpp
gfx/skia/skia/src/ports/SkFontMgr_default_dw.cpp
gfx/skia/skia/src/ports/SkFontMgr_default_gdi.cpp
gfx/skia/skia/src/ports/SkMutex_pthread.h
gfx/skia/skia/src/ports/SkMutex_win.h
gfx/skia/skia/src/ports/SkOSFile_none.cpp
gfx/skia/skia/src/ports/SkXMLParser_empty.cpp
gfx/skia/skia/src/svg/SkSVG.cpp
gfx/skia/skia/src/svg/SkSVGCircle.cpp
gfx/skia/skia/src/svg/SkSVGCircle.h
gfx/skia/skia/src/svg/SkSVGClipPath.cpp
gfx/skia/skia/src/svg/SkSVGClipPath.h
gfx/skia/skia/src/svg/SkSVGDefs.cpp
gfx/skia/skia/src/svg/SkSVGDefs.h
gfx/skia/skia/src/svg/SkSVGElements.cpp
gfx/skia/skia/src/svg/SkSVGElements.h
gfx/skia/skia/src/svg/SkSVGEllipse.cpp
gfx/skia/skia/src/svg/SkSVGEllipse.h
gfx/skia/skia/src/svg/SkSVGFeColorMatrix.cpp
gfx/skia/skia/src/svg/SkSVGFeColorMatrix.h
gfx/skia/skia/src/svg/SkSVGFilter.cpp
gfx/skia/skia/src/svg/SkSVGFilter.h
gfx/skia/skia/src/svg/SkSVGG.cpp
gfx/skia/skia/src/svg/SkSVGG.h
gfx/skia/skia/src/svg/SkSVGGradient.cpp
gfx/skia/skia/src/svg/SkSVGGradient.h
gfx/skia/skia/src/svg/SkSVGGroup.cpp
gfx/skia/skia/src/svg/SkSVGGroup.h
gfx/skia/skia/src/svg/SkSVGImage.cpp
gfx/skia/skia/src/svg/SkSVGImage.h
gfx/skia/skia/src/svg/SkSVGLine.cpp
gfx/skia/skia/src/svg/SkSVGLine.h
gfx/skia/skia/src/svg/SkSVGLinearGradient.cpp
gfx/skia/skia/src/svg/SkSVGLinearGradient.h
gfx/skia/skia/src/svg/SkSVGMask.cpp
gfx/skia/skia/src/svg/SkSVGMask.h
gfx/skia/skia/src/svg/SkSVGMetadata.cpp
gfx/skia/skia/src/svg/SkSVGMetadata.h
gfx/skia/skia/src/svg/SkSVGPaintState.cpp
gfx/skia/skia/src/svg/SkSVGParser.cpp
gfx/skia/skia/src/svg/SkSVGPath.cpp
gfx/skia/skia/src/svg/SkSVGPath.h
gfx/skia/skia/src/svg/SkSVGPolygon.cpp
gfx/skia/skia/src/svg/SkSVGPolygon.h
gfx/skia/skia/src/svg/SkSVGPolyline.cpp
gfx/skia/skia/src/svg/SkSVGPolyline.h
gfx/skia/skia/src/svg/SkSVGRadialGradient.cpp
gfx/skia/skia/src/svg/SkSVGRadialGradient.h
gfx/skia/skia/src/svg/SkSVGRect.cpp
gfx/skia/skia/src/svg/SkSVGRect.h
gfx/skia/skia/src/svg/SkSVGSVG.cpp
gfx/skia/skia/src/svg/SkSVGSVG.h
gfx/skia/skia/src/svg/SkSVGStop.cpp
gfx/skia/skia/src/svg/SkSVGStop.h
gfx/skia/skia/src/svg/SkSVGSymbol.cpp
gfx/skia/skia/src/svg/SkSVGSymbol.h
gfx/skia/skia/src/svg/SkSVGText.cpp
gfx/skia/skia/src/svg/SkSVGText.h
gfx/skia/skia/src/svg/SkSVGUse.cpp
gfx/skia/skia/src/svg/SkSVGUse.h
gfx/skia/skia/src/utils/SkCondVar.cpp
gfx/skia/skia/src/utils/SkDeferredCanvas.cpp
gfx/skia/skia/src/utils/SkGatherPixelRefsAndRects.cpp
gfx/skia/skia/src/utils/SkGatherPixelRefsAndRects.h
gfx/skia/skia/src/utils/SkPDFRasterizer.cpp
gfx/skia/skia/src/utils/SkPDFRasterizer.h
gfx/skia/skia/src/utils/SkPathUtils.cpp
gfx/skia/skia/src/utils/SkPictureUtils.cpp
gfx/skia/skia/src/utils/SkProxyCanvas.cpp
gfx/skia/skia/src/utils/SkTLogic.h
gfx/skia/skia/src/utils/SkThreadUtils_pthread_linux.cpp
gfx/skia/skia/src/utils/SkThreadUtils_pthread_mach.cpp
gfx/skia/skia/src/utils/SkThreadUtils_pthread_other.cpp
gfx/skia/skia/src/utils/ios/SkFontHost_iOS.mm
gfx/skia/skia/src/utils/ios/SkImageDecoder_iOS.mm
gfx/skia/skia/src/utils/ios/SkOSFile_iOS.mm
gfx/skia/skia/src/utils/ios/SkStream_NSData.mm
gfx/skia/skia/src/views/SkTextBox.cpp
gfx/skia/skia/src/views/mac/SampleApp-Info.plist
gfx/skia/skia/src/views/mac/SampleApp.xib
gfx/skia/skia/src/views/mac/SampleAppDelegate.h
gfx/skia/skia/src/views/mac/SampleAppDelegate.mm
gfx/skia/skia/src/views/mac/SkOSWindow_Mac.cpp
gfx/skia/skia/src/xml/SkJS.cpp
gfx/skia/skia/src/xml/SkJSDisplayable.cpp
js/src/jit-test/tests/baseline/bug1081850.js
js/src/tests/js1_5/Regress/regress-326453.js
testing/web-platform/meta/2dcontext/path-objects/2d.path.arcTo.shape.curve1.html.ini
testing/web-platform/meta/2dcontext/path-objects/2d.path.arcTo.shape.curve2.html.ini
testing/web-platform/meta/url/a-element.xhtml.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/unregister-then-register-new-script.https.html.ini
testing/web-platform/tests/battery-status/battery-created-manual.html
testing/web-platform/tests/dom/nodes/Document-createProcessingInstruction.xhtml
testing/web-platform/tests/dom/nodes/Document-getElementsByTagName.xhtml
testing/web-platform/tests/dom/nodes/DocumentType-literal.xhtml
testing/web-platform/tests/dom/nodes/Element-childElement-null.svg
testing/web-platform/tests/dom/nodes/Element-childElement-null.xhtml
testing/web-platform/tests/dom/nodes/Element-childElementCount-dynamic-add.svg
testing/web-platform/tests/dom/nodes/Element-childElementCount-dynamic-add.xhtml
testing/web-platform/tests/dom/nodes/Element-childElementCount-dynamic-remove.svg
testing/web-platform/tests/dom/nodes/Element-childElementCount-dynamic-remove.xhtml
testing/web-platform/tests/dom/nodes/Element-childElementCount-nochild.svg
testing/web-platform/tests/dom/nodes/Element-childElementCount-nochild.xhtml
testing/web-platform/tests/dom/nodes/Element-childElementCount.svg
testing/web-platform/tests/dom/nodes/Element-childElementCount.xhtml
testing/web-platform/tests/dom/nodes/Element-firstElementChild-entity.xhtml
testing/web-platform/tests/dom/nodes/Element-firstElementChild-namespace.svg
testing/web-platform/tests/dom/nodes/Element-firstElementChild-namespace.xhtml
testing/web-platform/tests/dom/nodes/Element-firstElementChild.svg
testing/web-platform/tests/dom/nodes/Element-firstElementChild.xhtml
testing/web-platform/tests/dom/nodes/Element-lastElementChild.svg
testing/web-platform/tests/dom/nodes/Element-lastElementChild.xhtml
testing/web-platform/tests/dom/nodes/Element-nextElementSibling.svg
testing/web-platform/tests/dom/nodes/Element-nextElementSibling.xhtml
testing/web-platform/tests/dom/nodes/Element-previousElementSibling.svg
testing/web-platform/tests/dom/nodes/Element-previousElementSibling.xhtml
testing/web-platform/tests/dom/nodes/Element-siblingElement-null.svg
testing/web-platform/tests/dom/nodes/Element-siblingElement-null.xhtml
testing/web-platform/tests/dom/nodes/Node-nodeName.xhtml
testing/web-platform/tests/dom/nodes/ParentNode-querySelector-All.xht
testing/web-platform/tests/html/dom/documents/dom-tree-accessors/document.getElementsByName/document.getElementsByName-case.xhtml
testing/web-platform/tests/html/dom/documents/dom-tree-accessors/document.getElementsByName/document.getElementsByName-id.xhtml
testing/web-platform/tests/html/dom/documents/dom-tree-accessors/document.getElementsByName/document.getElementsByName-namespace.xhtml
testing/web-platform/tests/html/dom/documents/dom-tree-accessors/document.getElementsByName/document.getElementsByName-newelements.xhtml
testing/web-platform/tests/html/dom/documents/dom-tree-accessors/document.getElementsByName/document.getElementsByName-null-undef.xhtml
testing/web-platform/tests/html/dom/documents/dom-tree-accessors/document.getElementsByName/document.getElementsByName-param.xhtml
testing/web-platform/tests/html/semantics/scripting-1/the-script-element/script-for-event.xhtml
testing/web-platform/tests/html/semantics/scripting-1/the-script-element/script-text.xhtml
testing/web-platform/tests/resources/webidl2/test/invalid/idl/maplike-1type.widl
testing/web-platform/tests/resources/webidl2/test/invalid/idl/readonly-iterable.widl
testing/web-platform/tests/resources/webidl2/test/invalid/idl/setlike-2types.widl
testing/web-platform/tests/resources/webidl2/test/invalid/idl/typedef-nested.widl
testing/web-platform/tests/resources/webidl2/test/invalid/json/maplike-1type.json
testing/web-platform/tests/resources/webidl2/test/invalid/json/readonly-iterable.json
testing/web-platform/tests/resources/webidl2/test/invalid/json/setlike-2types.json
testing/web-platform/tests/resources/webidl2/test/invalid/json/typedef-nested.json
testing/web-platform/tests/resources/webidl2/test/syntax/idl/extended-attributes.widl
testing/web-platform/tests/resources/webidl2/test/syntax/idl/iterable.widl
testing/web-platform/tests/resources/webidl2/test/syntax/idl/legacyiterable.widl
testing/web-platform/tests/resources/webidl2/test/syntax/idl/maplike.widl
testing/web-platform/tests/resources/webidl2/test/syntax/idl/setlike.widl
testing/web-platform/tests/resources/webidl2/test/syntax/idl/typedef-nested.widl
testing/web-platform/tests/resources/webidl2/test/syntax/json/extended-attributes.json
testing/web-platform/tests/resources/webidl2/test/syntax/json/iterable.json
testing/web-platform/tests/resources/webidl2/test/syntax/json/legacyiterable.json
testing/web-platform/tests/resources/webidl2/test/syntax/json/maplike.json
testing/web-platform/tests/resources/webidl2/test/syntax/json/setlike.json
testing/web-platform/tests/resources/webidl2/test/syntax/json/typedef-nested.json
testing/web-platform/tests/resources/webidl2/test/syntax/opt/typedef-nested.json
testing/web-platform/tests/url/a-element.xhtml
--- a/CLOBBER
+++ b/CLOBBER
@@ -17,9 +17,9 @@
 #
 # Modifying this file will now automatically clobber the buildbot machines \o/
 #
 
 # Are you updating CLOBBER because you think it's needed for your WebIDL
 # changes to stick? As of bug 928195, this shouldn't be necessary! Please
 # don't change CLOBBER for WebIDL changes any more.
 
-Bug  1186934  followup needed to clear bustage
+Bug 1082598 - updating Skia
--- a/browser/installer/windows/nsis/shared.nsh
+++ b/browser/installer/windows/nsis/shared.nsh
@@ -347,16 +347,17 @@
 !define ShowShortcuts "!insertmacro ShowShortcuts"
 
 !macro AddAssociationIfNoneExist FILE_TYPE
   ClearErrors
   EnumRegKey $7 HKCR "${FILE_TYPE}" 0
   ${If} ${Errors}
     WriteRegStr SHCTX "SOFTWARE\Classes\${FILE_TYPE}"  "" "FirefoxHTML"
   ${EndIf}
+  WriteRegStr SHCTX "SOFTWARE\Classes\${FILE_TYPE}\OpenWithProgids" "FirefoxHTML" ""
 !macroend
 !define AddAssociationIfNoneExist "!insertmacro AddAssociationIfNoneExist"
 
 ; Adds the protocol and file handler registry entries for making Firefox the
 ; default handler (uses SHCTX).
 !macro SetHandlers
   ${GetLongPath} "$INSTDIR\${FileMainEXE}" $8
 
--- a/config/system-headers
+++ b/config/system-headers
@@ -413,17 +413,16 @@ Entry.h
 errno.h
 Errors.h
 Events.h
 exdisp.h
 ExDisp.h
 exe386.h
 execinfo.h
 extras.h
-fabdef.h
 fcntl.h
 features.h
 fibdef.h
 File.h
 filehdr.h
 files.h
 Files.h
 FindDirectory.h
@@ -623,17 +622,16 @@ libc_r.h
 libelf.h
 libelf/libelf.h
 libgen.h
 libgnome/gnome-url.h
 libgnome/libgnome.h
 libgnomeui/gnome-icon-lookup.h
 libgnomeui/gnome-icon-theme.h
 libgnomeui/gnome-ui-init.h
-lib$routines.h
 limits
 limits.h
 link.h
 #ifdef ANDROID
 linux/android_alarm.h
 linux/ashmem.h
 #endif
 linux/ioprio.h
@@ -884,17 +882,16 @@ rasdlg.h
 raserror.h
 ras.h
 regex.h
 Region.h
 resolv.h
 Resources.h
 Retrace.h
 rld_interface.h
-rmsdef.h
 Roster.h
 rpc.h
 rpcproxy.h
 rpc/types.h
 sane/sane.h
 sane/sanei.h
 sane/saneopts.h
 sched.h
@@ -922,17 +919,16 @@ signal.h
 SimpleGameSound.h
 SIOUX.h
 size_t.h
 sndio.h
 someincludefile.h
 Sound.h
 soundcard.h
 sqlite3.h
-ssdef.h
 sstream
 stack
 #ifdef ANDROID
 stagefright/AACWriter.h
 stagefright/AMRWriter.h
 stagefright/AudioSource.h
 stagefright/DataSource.h
 stagefright/foundation/ABase.h
@@ -1149,17 +1145,16 @@ UNavServicesDialogs.h
 UnicodeBlockObjects.h
 UnicodeConverter.h
 UnicodeUtilities.h
 unidef.h
 unikbd.h
 unistd.h
 unix.h
 unixio.h
-unixlib.h
 unknwn.h
 UPrinting.h
 UQuickTime.h
 UReanimator.h
 URegions.h
 URegistrar.h
 UResourceMgr.h
 utility
--- a/configure.in
+++ b/configure.in
@@ -9255,16 +9255,32 @@ export PYTHON
 export MOZILLA_CENTRAL_PATH=$_topsrcdir
 export STLPORT_CPPFLAGS
 export STLPORT_LIBS
 export JS_STANDALONE=no
 export DIST
 export MOZ_LINKER
 export ZLIB_IN_MOZGLUE
 export MOZ_MEMORY
+export AR
+export RANLIB
+export CPP
+export CC
+export CXX
+export LD
+export ARFLAGS
+export CPPFLAGS
+export CFLAGS
+export CXXFLAGS
+export LDFLAGS
+export HOST_CC
+export HOST_CXX
+export HOST_CFLAGS
+export HOST_CXXFLAGS
+export HOST_LDFLAGS
 
 if ! test -e js; then
     mkdir js
 fi
 
 AC_OUTPUT_SUBDIRS(js/src,$cache_file)
 ac_configure_args="$_SUBDIR_CONFIG_ARGS"
 
--- a/devtools/shared/heapsnapshot/DominatorTreeNode.js
+++ b/devtools/shared/heapsnapshot/DominatorTreeNode.js
@@ -1,26 +1,34 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
-const DEFAULT_MAX_DEPTH = 3;
+const { Visitor, walk } = require("resource://devtools/shared/heapsnapshot/CensusUtils.js");
+
+const DEFAULT_MAX_DEPTH = 4;
 const DEFAULT_MAX_SIBLINGS = 15;
 
 /**
  * A single node in a dominator tree.
  *
  * @param {NodeId} nodeId
  * @param {NodeSize} retainedSize
  */
-function DominatorTreeNode(nodeId, retainedSize) {
+function DominatorTreeNode(nodeId, label, shallowSize, retainedSize) {
   // The id of this node.
   this.nodeId = nodeId;
 
+  // The label structure generated by describing the given node.
+  this.label = label;
+
+  // The shallow size of this node.
+  this.shallowSize = shallowSize;
+
   // The retained size of this node.
   this.retainedSize = retainedSize;
 
   // The id of this node's parent or undefined if this node is the root.
   this.parentId = undefined;
 
   // An array of immediately dominated child `DominatorTreeNode`s, or undefined.
   this.children = undefined;
@@ -55,36 +63,143 @@ DominatorTreeNode.addChild = function (p
     parent.children = [];
   }
 
   parent.children.push(child);
   child.parentId = parent.nodeId;
 };
 
 /**
+ * A Visitor that is used to generate a label for a node in the heap snapshot
+ * and get its shallow size as well while we are at it.
+ */
+function LabelAndShallowSizeVisitor() {
+  // As we walk the description, we accumulate edges in this array.
+  this._labelPieces = [];
+
+  // Once we reach the non-zero count leaf node in the description, we move the
+  // labelPieces here to signify that we no longer need to accumulate edges.
+  this._label = undefined;
+
+  // Once we reach the non-zero count leaf node in the description, we grab the
+  // shallow size and place it here.
+  this._shallowSize = 0;
+}
+
+DominatorTreeNode.LabelAndShallowSizeVisitor = LabelAndShallowSizeVisitor;
+
+LabelAndShallowSizeVisitor.prototype = Object.create(Visitor);
+
+/**
+ * @overrides Visitor.prototype.enter
+ */
+LabelAndShallowSizeVisitor.prototype.enter = function (breakdown, report, edge) {
+  if (this._labelPieces && edge) {
+    this._labelPieces.push(edge);
+  }
+};
+
+/**
+ * @overrides Visitor.prototype.exit
+ */
+LabelAndShallowSizeVisitor.prototype.exit = function (breakdown, report, edge) {
+  if (this._labelPieces && edge) {
+    this._labelPieces.pop();
+  }
+};
+
+/**
+ * @overrides Visitor.prototype.count
+ */
+LabelAndShallowSizeVisitor.prototype.count = function (breakdown, report, edge) {
+  if (report.count === 0) {
+    return;
+  }
+
+  this._label = this._labelPieces;
+  this._labelPieces = undefined;
+
+  this._shallowSize = report.bytes;
+};
+
+/**
+ * Get the generated label structure accumulated by this visitor.
+ *
+ * @returns {Object}
+ */
+LabelAndShallowSizeVisitor.prototype.label = function () {
+  return this._label;
+};
+
+/**
+ * Get the shallow size of the node this visitor visited.
+ *
+ * @returns {Number}
+ */
+LabelAndShallowSizeVisitor.prototype.shallowSize = function () {
+  return this._shallowSize;
+};
+
+/**
+ * Generate a label structure for the node with the given id and grab its
+ * shallow size.
+ *
+ * What is a "label" structure? HeapSnapshot.describeNode essentially takes a
+ * census of a single node rather than the whole heap graph. The resulting
+ * report has only one count leaf that is non-zero. The label structure is the
+ * path in this report from the root to the non-zero count leaf.
+ *
+ * @param {Number} nodeId
+ * @param {HeapSnapshot} snapshot
+ * @param {Object} breakdown
+ *
+ * @returns {Object}
+ *          An object with the following properties:
+ *          - {Number} shallowSize
+ *          - {Object} label
+ */
+DominatorTreeNode.getLabelAndShallowSize = function (nodeId,
+                                                     snapshot,
+                                                     breakdown) {
+  const description = snapshot.describeNode(breakdown, nodeId);
+
+  const visitor = new LabelAndShallowSizeVisitor();
+  walk(breakdown, description, visitor);
+
+  return {
+    label: visitor.label(),
+    shallowSize: visitor.shallowSize(),
+  };
+};
+
+/**
  * Do a partial traversal of the given dominator tree and convert it into a tree
  * of `DominatorTreeNode`s. Dominator trees have a node for every node in the
  * snapshot's heap graph, so we must not allocate a JS object for every node. It
  * would be way too many and the node count is effectively unbounded.
  *
  * Go no deeper down the tree than `maxDepth` and only consider at most
  * `maxSiblings` within any single node's children.
  *
  * @param {DominatorTree} dominatorTree
  * @param {Number} maxDepth
  * @param {Number} maxSiblings
  *
  * @returns {DominatorTreeNode}
  */
 DominatorTreeNode.partialTraversal = function (dominatorTree,
+                                               snapshot,
+                                               breakdown,
                                                maxDepth = DEFAULT_MAX_DEPTH,
                                                maxSiblings = DEFAULT_MAX_SIBLINGS) {
   function dfs(nodeId, depth) {
-    const size = dominatorTree.getRetainedSize(nodeId);
-    const node = new DominatorTreeNode(nodeId, size);
+    const { label, shallowSize } =
+      DominatorTreeNode.getLabelAndShallowSize(nodeId, snapshot, breakdown);
+    const retainedSize = dominatorTree.getRetainedSize(nodeId);
+    const node = new DominatorTreeNode(nodeId, label, shallowSize, retainedSize);
     const childNodeIds = dominatorTree.getImmediatelyDominated(nodeId);
 
     const newDepth = depth + 1;
     if (newDepth < maxDepth) {
       const endIdx = Math.min(childNodeIds.length, maxSiblings);
       for (let i = 0; i < endIdx; i++) {
         DominatorTreeNode.addChild(node, dfs(childNodeIds[i], newDepth));
       }
--- a/devtools/shared/heapsnapshot/HeapAnalysesClient.js
+++ b/devtools/shared/heapsnapshot/HeapAnalysesClient.js
@@ -168,16 +168,18 @@ HeapAnalysesClient.prototype.computeDomi
 
 /**
  * Get the initial, partial view of the dominator tree with the given id.
  *
  * @param {Object} opts
  *        An object specifying options for this request.
  *        - {DominatorTreeId} dominatorTreeId
  *          The id of the dominator tree.
+ *        - {Object} breakdown
+ *          The breakdown used to generate node labels.
  *        - {Number} maxDepth
  *          The maximum depth to traverse down the tree to create this initial
  *          view.
  *        - {Number} maxSiblings
  *          The maximum number of siblings to visit within each traversed node's
  *          children.
  *
  * @returns {Promise<DominatorTreeNode>}
@@ -190,16 +192,18 @@ HeapAnalysesClient.prototype.getDominato
  * Get a subset of a nodes children in the dominator tree.
  *
  * @param {Object} opts
  *        An object specifying options for this request.
  *        - {DominatorTreeId} dominatorTreeId
  *          The id of the dominator tree.
  *        - {NodeId} nodeId
  *          The id of the node whose children are being found.
+ *        - {Object} breakdown
+ *          The breakdown used to generate node labels.
  *        - {Number} startIndex
  *          The starting index within the full set of immediately dominated
  *          children of the children being requested. Children are always sorted
  *          by greatest to least retained size.
  *        - {Number} maxCount
  *          The maximum number of children to return.
  *
  * @returns {Promise<Object>}
--- a/devtools/shared/heapsnapshot/HeapAnalysesWorker.js
+++ b/devtools/shared/heapsnapshot/HeapAnalysesWorker.js
@@ -99,80 +99,99 @@ workerHelper.createTask(self, "getCreati
  * The set of `DominatorTree`s that have been computed, mapped by their id (aka
  * the index into this array).
  *
  * @see /dom/webidl/DominatorTree.webidl
  */
 const dominatorTrees = [];
 
 /**
+ * The i^th HeapSnapshot in this array is the snapshot used to generate the i^th
+ * dominator tree in `dominatorTrees` above. This lets us map from a dominator
+ * tree id to the snapshot it came from.
+ */
+const dominatorTreeSnapshots = [];
+
+/**
  * @see HeapAnalysesClient.prototype.computeDominatorTree
  */
 workerHelper.createTask(self, "computeDominatorTree", snapshotFilePath => {
   const snapshot = snapshots[snapshotFilePath];
   if (!snapshot) {
     throw new Error(`No known heap snapshot for '${snapshotFilePath}'`);
   }
 
   const id = dominatorTrees.length;
   dominatorTrees.push(snapshot.computeDominatorTree());
+  dominatorTreeSnapshots.push(snapshot);
   return id;
 });
 
 /**
  * @see HeapAnalysesClient.prototype.getDominatorTree
  */
 workerHelper.createTask(self, "getDominatorTree", request => {
   const {
     dominatorTreeId,
+    breakdown,
     maxDepth,
     maxSiblings
   } = request;
 
   if (!(0 <= dominatorTreeId && dominatorTreeId < dominatorTrees.length)) {
     throw new Error(
       `There does not exist a DominatorTree with the id ${dominatorTreeId}`);
   }
 
-  return DominatorTreeNode.partialTraversal(dominatorTrees[dominatorTreeId],
+  const dominatorTree = dominatorTrees[dominatorTreeId];
+  const snapshot = dominatorTreeSnapshots[dominatorTreeId];
+
+  return DominatorTreeNode.partialTraversal(dominatorTree,
+                                            snapshot,
+                                            breakdown,
                                             maxDepth,
                                             maxSiblings);
 });
 
 /**
  * @see HeapAnalysesClient.prototype.getImmediatelyDominated
  */
 workerHelper.createTask(self, "getImmediatelyDominated", request => {
   const {
     dominatorTreeId,
     nodeId,
+    breakdown,
     startIndex,
     maxCount
   } = request;
 
   if (!(0 <= dominatorTreeId && dominatorTreeId < dominatorTrees.length)) {
     throw new Error(
       `There does not exist a DominatorTree with the id ${dominatorTreeId}`);
   }
 
   const dominatorTree = dominatorTrees[dominatorTreeId];
+  const snapshot = dominatorTreeSnapshots[dominatorTreeId];
+
   const childIds = dominatorTree.getImmediatelyDominated(nodeId);
   if (!childIds) {
     throw new Error(`${nodeId} is not a node id in the dominator tree`);
   }
 
   const start = startIndex || DEFAULT_START_INDEX;
   const count = maxCount || DEFAULT_MAX_COUNT;
   const end = start + count;
 
   const nodes = childIds
     .slice(start, end)
     .map(id => {
-      const size = dominatorTree.getRetainedSize(id);
-      const node = new DominatorTreeNode(id, size);
+      const { label, shallowSize } =
+        DominatorTreeNode.getLabelAndShallowSize(id, snapshot, breakdown);
+      const retainedSize = dominatorTree.getRetainedSize(id);
+      const node = new DominatorTreeNode(id, label, shallowSize, retainedSize);
       node.parentId = nodeId;
       // DominatorTree.getImmediatelyDominated will always return non-null here
       // because we got the id directly from the dominator tree.
       node.moreChildrenAvailable = dominatorTree.getImmediatelyDominated(id).length > 0;
       return node;
     });
 
   const moreChildrenAvailable = childIds.length > end;
--- a/devtools/shared/heapsnapshot/HeapSnapshot.cpp
+++ b/devtools/shared/heapsnapshot/HeapSnapshot.cpp
@@ -517,16 +517,53 @@ HeapSnapshot::TakeCensus(JSContext* cx, 
   }
 
   if (NS_WARN_IF(!handler.report(cx, rval))) {
     rv.Throw(NS_ERROR_OUT_OF_MEMORY);
     return;
   }
 }
 
+void
+HeapSnapshot::DescribeNode(JSContext* cx, JS::HandleObject breakdown, uint64_t nodeId,
+                           JS::MutableHandleValue rval, ErrorResult& rv) {
+  MOZ_ASSERT(breakdown);
+  JS::RootedValue breakdownVal(cx, JS::ObjectValue(*breakdown));
+  JS::ubi::CountTypePtr rootType = JS::ubi::ParseBreakdown(cx, breakdownVal);
+  if (NS_WARN_IF(!rootType)) {
+    rv.Throw(NS_ERROR_UNEXPECTED);
+    return;
+  }
+
+  JS::ubi::RootedCount rootCount(cx, rootType->makeCount());
+  if (NS_WARN_IF(!rootCount)) {
+    rv.Throw(NS_ERROR_OUT_OF_MEMORY);
+    return;
+  }
+
+  JS::ubi::Node::Id id(nodeId);
+  Maybe<JS::ubi::Node> node = getNodeById(id);
+  if (NS_WARN_IF(node.isNothing())) {
+    rv.Throw(NS_ERROR_INVALID_ARG);
+    return;
+  }
+
+  MallocSizeOf mallocSizeOf = GetCurrentThreadDebuggerMallocSizeOf();
+  if (NS_WARN_IF(!rootCount->count(mallocSizeOf, *node))) {
+    rv.Throw(NS_ERROR_OUT_OF_MEMORY);
+    return;
+  }
+
+  if (NS_WARN_IF(!rootCount->report(cx, rval))) {
+    rv.Throw(NS_ERROR_OUT_OF_MEMORY);
+    return;
+  }
+}
+
+
 already_AddRefed<DominatorTree>
 HeapSnapshot::ComputeDominatorTree(ErrorResult& rv)
 {
   Maybe<JS::ubi::DominatorTree> maybeTree;
   {
     auto ccrt = CycleCollectedJSRuntime::Get();
     MOZ_ASSERT(ccrt);
     auto rt = ccrt->Runtime();
--- a/devtools/shared/heapsnapshot/HeapSnapshot.h
+++ b/devtools/shared/heapsnapshot/HeapSnapshot.h
@@ -154,16 +154,19 @@ public:
     if (!p)
       return Nothing();
     return Some(JS::ubi::Node(const_cast<DeserializedNode*>(&*p)));
   }
 
   void TakeCensus(JSContext* cx, JS::HandleObject options,
                   JS::MutableHandleValue rval, ErrorResult& rv);
 
+  void DescribeNode(JSContext* cx, JS::HandleObject breakdown, uint64_t nodeId,
+                    JS::MutableHandleValue rval, ErrorResult& rv);
+
   already_AddRefed<DominatorTree> ComputeDominatorTree(ErrorResult& rv);
 
   dom::Nullable<uint64_t> GetCreationTime() {
     static const uint64_t maxTime = uint64_t(1) << 53;
     if (timestamp.isSome() && timestamp.ref() <= maxTime) {
       return dom::Nullable<uint64_t>(timestamp.ref());
     }
 
--- a/devtools/shared/heapsnapshot/tests/unit/head_heapsnapshot.js
+++ b/devtools/shared/heapsnapshot/tests/unit/head_heapsnapshot.js
@@ -17,16 +17,19 @@ const { addDebuggerToGlobal } =
 const { Task } = Cu.import("resource://gre/modules/Task.jsm", {});
 
 const DevToolsUtils = require("devtools/shared/DevToolsUtils");
 const HeapAnalysesClient =
   require("devtools/shared/heapsnapshot/HeapAnalysesClient");
 const Services = require("Services");
 const { censusReportToCensusTreeNode } = require("devtools/shared/heapsnapshot/census-tree-node");
 const CensusUtils = require("devtools/shared/heapsnapshot/CensusUtils");
+const DominatorTreeNode = require("devtools/shared/heapsnapshot/DominatorTreeNode");
+const { LabelAndShallowSizeVisitor } = DominatorTreeNode;
+
 
 // Always log packets when running tests. runxpcshelltests.py will throw
 // the output away anyway, unless you give it the --verbose flag.
 if (Services.appInfo &&
     Services.appInfo.processType == Services.appInfo.PROCESS_TYPE_DEFAULT) {
   Services.prefs.setBoolPref("devtools.debugger.log", true);
 }
 DevToolsUtils.dumpn.wantLogging = true;
@@ -291,8 +294,34 @@ function assertDiff(breakdown, first, se
   dumpn("Second census report: " + JSON.stringify(second, null, 4));
   dumpn("Expected delta-report: " + JSON.stringify(expected, null, 4));
 
   const actual = CensusUtils.diff(breakdown, first, second);
   dumpn("Actual delta-report: " + JSON.stringify(actual, null, 4));
 
   assertStructurallyEquivalent(actual, expected);
 }
+
+/**
+ * Assert that creating a label and getting a shallow size from the given node
+ * description with the specified breakdown is as expected.
+ *
+ * @param {Object} breakdown
+ * @param {Object} givenDescription
+ * @param {Number} expectedShallowSize
+ * @param {Object} expectedLabel
+ */
+function assertLabelAndShallowSize(breakdown, givenDescription, expectedShallowSize, expectedLabel) {
+  dumpn("Computing label and shallow size from node description:");
+  dumpn("Breakdown: " + JSON.stringify(breakdown, null, 4));
+  dumpn("Given description: " + JSON.stringify(givenDescription, null, 4));
+
+  const visitor = new LabelAndShallowSizeVisitor();
+  CensusUtils.walk(breakdown, description, visitor);
+
+  dumpn("Expected shallow size: " + expectedShallowSize);
+  dumpn("Actual shallow size: " + visitor.shallowSize());
+  equal(visitor.shallowSize(), expectedShallowSize, "Shallow size should be correct");
+
+  dumpn("Expected label: " + JSON.stringify(expectedLabel, null, 4));
+  dumpn("Actual label: " + JSON.stringify(visitor.label(), null, 4));
+  assertStructurallyEquivalent(visitor.label(), expectedLabel);
+}
new file mode 100644
--- /dev/null
+++ b/devtools/shared/heapsnapshot/tests/unit/test_DominatorTreeNode_LabelAndShallowSize_01.js
@@ -0,0 +1,46 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that we can generate label structures from node description reports.
+
+const breakdown = {
+  by: "coarseType",
+  objects: {
+    by: "objectClass",
+    then: { by: "count", count: true, bytes: true },
+    other: { by: "count", count: true, bytes: true },
+  },
+  strings: {
+    by: "internalType",
+    then: { by: "count", count: true, bytes: true },
+  },
+  scripts: {
+    by: "internalType",
+    then: { by: "count", count: true, bytes: true },
+  },
+  other: {
+    by: "internalType",
+    then: { by: "count", count: true, bytes: true },
+  },
+};
+
+const description = {
+  objects: {
+    Function: { count: 1, bytes: 32 },
+    other: { count: 0, bytes: 0 }
+  },
+  strings: {},
+  scripts: {},
+  other: {}
+};
+
+const expected = [
+  "objects",
+  "Function"
+];
+
+const shallowSize = 32;
+
+function run_test() {
+  assertLabelAndShallowSize(breakdown, description, shallowSize, expected);
+}
new file mode 100644
--- /dev/null
+++ b/devtools/shared/heapsnapshot/tests/unit/test_DominatorTreeNode_LabelAndShallowSize_02.js
@@ -0,0 +1,45 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that we can generate label structures from node description reports.
+
+const breakdown = {
+  by: "coarseType",
+  objects: {
+    by: "objectClass",
+    then: { by: "count", count: true, bytes: true },
+    other: { by: "count", count: true, bytes: true },
+  },
+  strings: {
+    by: "internalType",
+    then: { by: "count", count: true, bytes: true },
+  },
+  scripts: {
+    by: "internalType",
+    then: { by: "count", count: true, bytes: true },
+  },
+  other: {
+    by: "internalType",
+    then: { by: "count", count: true, bytes: true },
+  },
+};
+
+const description = {
+  objects: {
+    other: { count: 1, bytes: 10 }
+  },
+  strings: {},
+  scripts: {},
+  other: {}
+};
+
+const expected = [
+  "objects",
+  "other"
+];
+
+const shallowSize = 10;
+
+function run_test() {
+  assertLabelAndShallowSize(breakdown, description, shallowSize, expected);
+}
new file mode 100644
--- /dev/null
+++ b/devtools/shared/heapsnapshot/tests/unit/test_DominatorTreeNode_LabelAndShallowSize_03.js
@@ -0,0 +1,47 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that we can generate label structures from node description reports.
+
+const breakdown = {
+  by: "coarseType",
+  objects: {
+    by: "objectClass",
+    then: { by: "count", count: true, bytes: true },
+    other: { by: "count", count: true, bytes: true },
+  },
+  strings: {
+    by: "internalType",
+    then: { by: "count", count: true, bytes: true },
+  },
+  scripts: {
+    by: "internalType",
+    then: { by: "count", count: true, bytes: true },
+  },
+  other: {
+    by: "internalType",
+    then: { by: "count", count: true, bytes: true },
+  },
+};
+
+const description = {
+  objects: {
+    other: { count: 0, bytes: 0 }
+  },
+  strings: {
+    "JSString": { count: 1, bytes: 42 },
+  },
+  scripts: {},
+  other: {}
+};
+
+const expected = [
+  "strings",
+  "JSString"
+];
+
+const shallowSize = 42;
+
+function run_test() {
+  assertLabelAndShallowSize(breakdown, description, shallowSize, expected);
+}
new file mode 100644
--- /dev/null
+++ b/devtools/shared/heapsnapshot/tests/unit/test_DominatorTreeNode_LabelAndShallowSize_04.js
@@ -0,0 +1,53 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that we can generate label structures from node description reports.
+
+const breakdown = {
+  by: "coarseType",
+  objects: {
+    by: "objectClass",
+    then: {
+      by: "allocationStack",
+      then: { by: "count", count: true, bytes: true },
+      noStack: { by: "count", count: true, bytes: true },
+    },
+    other: { by: "count", count: true, bytes: true },
+  },
+  strings: {
+    by: "internalType",
+    then: { by: "count", count: true, bytes: true },
+  },
+  scripts: {
+    by: "internalType",
+    then: { by: "count", count: true, bytes: true },
+  },
+  other: {
+    by: "internalType",
+    then: { by: "count", count: true, bytes: true },
+  },
+};
+
+const stack = saveStack();
+
+const description = {
+  objects: {
+    Array: new Map([[stack, { count: 1, bytes: 512 }]]),
+    other: { count: 0, bytes: 0 }
+  },
+  strings: {},
+  scripts: {},
+  other: {}
+};
+
+const expected = [
+  "objects",
+  "Array",
+  stack
+];
+
+const shallowSize = 512;
+
+function run_test() {
+  assertLabelAndShallowSize(breakdown, description, shallowSize, expected);
+}
--- a/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_getDominatorTree_01.js
+++ b/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_getDominatorTree_01.js
@@ -2,28 +2,39 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Test the HeapAnalyses{Client,Worker} "getDominatorTree" request.
 
 function run_test() {
   run_next_test();
 }
 
+const breakdown = {
+  by: "coarseType",
+  objects: { by: "count", count: true, bytes: true },
+  scripts: { by: "count", count: true, bytes: true },
+  strings: { by: "count", count: true, bytes: true },
+  other: { by: "count", count: true, bytes: true },
+};
+
 add_task(function* () {
   const client = new HeapAnalysesClient();
 
   const snapshotFilePath = saveNewHeapSnapshot();
   yield client.readHeapSnapshot(snapshotFilePath);
   ok(true, "Should have read the heap snapshot");
 
   const dominatorTreeId = yield client.computeDominatorTree(snapshotFilePath);
   equal(typeof dominatorTreeId, "number",
         "should get a dominator tree id, and it should be a number");
 
-  const partialTree = yield client.getDominatorTree({ dominatorTreeId });
+  const partialTree = yield client.getDominatorTree({
+    dominatorTreeId,
+    breakdown
+  });
   ok(partialTree, "Should get a partial tree");
   equal(typeof partialTree, "object",
         "partialTree should be an object");
 
   function checkTree(node) {
     equal(typeof node.nodeId, "number", "each node should have an id");
 
     if (node === partialTree) {
--- a/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_getDominatorTree_02.js
+++ b/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_getDominatorTree_02.js
@@ -3,21 +3,29 @@
 
 // Test the HeapAnalyses{Client,Worker} "getDominatorTree" request with bad
 // dominator tree ids.
 
 function run_test() {
   run_next_test();
 }
 
+const breakdown = {
+  by: "coarseType",
+  objects: { by: "count", count: true, bytes: true },
+  scripts: { by: "count", count: true, bytes: true },
+  strings: { by: "count", count: true, bytes: true },
+  other: { by: "count", count: true, bytes: true },
+};
+
 add_task(function* () {
   const client = new HeapAnalysesClient();
 
   let threw = false;
   try {
-    yield client.getDominatorTree({ dominatorTreeId: 42 });
+    yield client.getDominatorTree({ dominatorTreeId: 42, breakdown });
   } catch (_) {
     threw = true;
   }
   ok(threw, "should throw when given a bad id");
 
   client.destroy();
 });
--- a/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_getImmediatelyDominated_01.js
+++ b/devtools/shared/heapsnapshot/tests/unit/test_HeapAnalyses_getImmediatelyDominated_01.js
@@ -2,42 +2,55 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Test the HeapAnalyses{Client,Worker} "getImmediatelyDominated" request.
 
 function run_test() {
   run_next_test();
 }
 
+const breakdown = {
+  by: "coarseType",
+  objects: { by: "count", count: true, bytes: true },
+  scripts: { by: "count", count: true, bytes: true },
+  strings: { by: "count", count: true, bytes: true },
+  other: { by: "count", count: true, bytes: true },
+};
+
 add_task(function* () {
   const client = new HeapAnalysesClient();
 
   const snapshotFilePath = saveNewHeapSnapshot();
   yield client.readHeapSnapshot(snapshotFilePath);
   const dominatorTreeId = yield client.computeDominatorTree(snapshotFilePath);
 
-  const partialTree = yield client.getDominatorTree({ dominatorTreeId });
+  const partialTree = yield client.getDominatorTree({
+    dominatorTreeId,
+    breakdown
+  });
   ok(partialTree.children.length > 0,
      "root should immediately dominate some nodes");
 
   // First, test getting a subset of children available.
   const response = yield client.getImmediatelyDominated({
     dominatorTreeId,
+    breakdown,
     nodeId: partialTree.nodeId,
     startIndex: 0,
     maxCount: partialTree.children.length - 1
   });
 
   ok(Array.isArray(response.nodes));
   ok(response.nodes.every(node => node.parentId === partialTree.nodeId));
   ok(response.moreChildrenAvailable);
 
   // Next, test getting a subset of children available.
   const secondResponse = yield client.getImmediatelyDominated({
     dominatorTreeId,
+    breakdown,
     nodeId: partialTree.nodeId,
     startIndex: 0,
     maxCount: Infinity
   });
 
   ok(Array.isArray(secondResponse.nodes));
   ok(secondResponse.nodes.every(node => node.parentId === partialTree.nodeId));
   ok(!secondResponse.moreChildrenAvailable);
new file mode 100644
--- /dev/null
+++ b/devtools/shared/heapsnapshot/tests/unit/test_HeapSnapshot_describeNode_01.js
@@ -0,0 +1,42 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that we can describe nodes with a breakdown.
+
+function run_test() {
+  const path = saveNewHeapSnapshot();
+  const snapshot = ChromeUtils.readHeapSnapshot(path);
+  ok(snapshot.describeNode);
+  equal(typeof snapshot.describeNode, "function");
+
+  const dt = snapshot.computeDominatorTree();
+
+  let threw = false;
+  try {
+    snapshot.describeNode(undefined, dt.root);
+  } catch (_) {
+    threw = true;
+  }
+  ok(threw, "Should require a breakdown");
+
+  const breakdown = {
+    by: "coarseType",
+    objects: { by: "objectClass" },
+    scripts: { by: "internalType" },
+    strings: { by: "internalType" },
+    other: { by: "internalType" }
+  };
+
+  threw = false;
+  try {
+    snapshot.describeNode(breakdown, 0);
+  } catch (_) {
+    threw = true;
+  }
+  ok(threw, "Should throw when given an invalid node id");
+
+  const description = snapshot.describeNode(breakdown, dt.root);
+  ok(description);
+  ok(description.other);
+  ok(description.other["JS::ubi::RootList"]);
+}
--- a/devtools/shared/heapsnapshot/tests/unit/xpcshell.ini
+++ b/devtools/shared/heapsnapshot/tests/unit/xpcshell.ini
@@ -28,16 +28,20 @@ support-files =
 [test_census-tree-node-06.js]
 [test_census-tree-node-07.js]
 [test_census-tree-node-08.js]
 [test_DominatorTree_01.js]
 [test_DominatorTree_02.js]
 [test_DominatorTree_03.js]
 [test_DominatorTree_04.js]
 [test_DominatorTree_05.js]
+[test_DominatorTreeNode_LabelAndShallowSize_01.js]
+[test_DominatorTreeNode_LabelAndShallowSize_02.js]
+[test_DominatorTreeNode_LabelAndShallowSize_03.js]
+[test_DominatorTreeNode_LabelAndShallowSize_04.js]
 [test_HeapAnalyses_computeDominatorTree_01.js]
 [test_HeapAnalyses_computeDominatorTree_02.js]
 [test_HeapAnalyses_getCreationTime_01.js]
 [test_HeapAnalyses_getDominatorTree_01.js]
 [test_HeapAnalyses_getDominatorTree_02.js]
 [test_HeapAnalyses_getImmediatelyDominated_01.js]
 [test_HeapAnalyses_readHeapSnapshot_01.js]
 [test_HeapAnalyses_takeCensusDiff_01.js]
@@ -46,16 +50,17 @@ support-files =
 [test_HeapAnalyses_takeCensus_02.js]
 [test_HeapAnalyses_takeCensus_03.js]
 [test_HeapAnalyses_takeCensus_04.js]
 [test_HeapAnalyses_takeCensus_05.js]
 [test_HeapAnalyses_takeCensus_06.js]
 [test_HeapAnalyses_takeCensus_07.js]
 [test_HeapSnapshot_creationTime_01.js]
 [test_HeapSnapshot_deepStack_01.js]
+[test_HeapSnapshot_describeNode_01.js]
 [test_HeapSnapshot_takeCensus_01.js]
 [test_HeapSnapshot_takeCensus_02.js]
 [test_HeapSnapshot_takeCensus_03.js]
 [test_HeapSnapshot_takeCensus_04.js]
 [test_HeapSnapshot_takeCensus_05.js]
 [test_HeapSnapshot_takeCensus_06.js]
 [test_HeapSnapshot_takeCensus_07.js]
 [test_HeapSnapshot_takeCensus_08.js]
--- a/dom/base/test/browser.ini
+++ b/dom/base/test/browser.ini
@@ -7,17 +7,16 @@ support-files =
   file_use_counter_svg_background.html
   file_use_counter_svg_list_style_image.html
   file_use_counter_svg_fill_pattern_definition.svg
   file_use_counter_svg_fill_pattern.svg
   file_use_counter_svg_fill_pattern_internal.svg
   file_use_counter_svg_fill_pattern_data.svg
 
 [browser_bug593387.js]
-skip-if = e10s # Bug ?????? - test directly touches content (contentWindow.iframe.addEventListener)
 [browser_bug902350.js]
 tags = mcb
 [browser_messagemanager_loadprocessscript.js]
 [browser_messagemanager_targetframeloader.js]
 [browser_pagehide_on_tab_close.js]
 skip-if = e10s # this tests non-e10s behavior. it's not expected to work in e10s.
 [browser_messagemanager_unload.js]
 [browser_state_notifications.js]
--- a/dom/canvas/WebGL2ContextQueries.cpp
+++ b/dom/canvas/WebGL2ContextQueries.cpp
@@ -1,16 +1,18 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "WebGL2Context.h"
 #include "GLContext.h"
 #include "WebGLQuery.h"
+#include "gfxPrefs.h"
+#include "nsThreadUtils.h"
 
 namespace mozilla {
 
 /*
  * We fake ANY_SAMPLES_PASSED and ANY_SAMPLES_PASSED_CONSERVATIVE with
  * SAMPLES_PASSED on desktop.
  *
  * OpenGL ES 3.0 spec 4.1.6:
@@ -250,16 +252,17 @@ WebGL2Context::EndQuery(GLenum target)
 
     if (target == LOCAL_GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN) {
         gl->fEndQuery(LOCAL_GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
     } else {
         gl->fEndQuery(SimulateOcclusionQueryTarget(gl, target));
     }
 
     UpdateBoundQuery(target, nullptr);
+    NS_DispatchToCurrentThread(new WebGLQuery::AvailableRunnable(activeQuery));
 }
 
 already_AddRefed<WebGLQuery>
 WebGL2Context::GetQuery(GLenum target, GLenum pname)
 {
     if (IsContextLost())
         return nullptr;
 
@@ -320,16 +323,21 @@ WebGL2Context::GetQueryParameter(JSConte
         /* See (spec getQueryObject 1)
          *     If this instance of WebGLQuery has never been active before, that
          *     mean that query->mGLName is not a query object yet.
          */
         ErrorInvalidOperation("getQueryObject: `query` has never been active.");
         return;
     }
 
+    // We must wait for an event loop before the query can be available
+    if (!query->mCanBeAvailable && !gfxPrefs::WebGLImmediateQueries()) {
+        return;
+    }
+
     MakeContextCurrent();
     GLuint returned = 0;
     switch (pname) {
     case LOCAL_GL_QUERY_RESULT_AVAILABLE:
         gl->fGetQueryObjectuiv(query->mGLName, LOCAL_GL_QUERY_RESULT_AVAILABLE, &returned);
         retval.set(JS::BooleanValue(returned != 0));
         return;
 
--- a/dom/canvas/WebGLFormats.cpp
+++ b/dom/canvas/WebGLFormats.cpp
@@ -780,17 +780,17 @@ FormatUsageAuthority::CreateForWebGL2(gl
     fnAllowES3TexFormat(FOO(DEPTH_COMPONENT16 ), true, false);
     fnAllowES3TexFormat(FOO(DEPTH_COMPONENT24 ), true, false);
     fnAllowES3TexFormat(FOO(DEPTH_COMPONENT32F), true, false);
     fnAllowES3TexFormat(FOO(DEPTH24_STENCIL8  ), true, false);
     fnAllowES3TexFormat(FOO(DEPTH32F_STENCIL8 ), true, false);
 
     // GLES 3.0.4, p147, table 3.19
     // GLES 3.0.4, p286+, $C.1 "ETC Compressed Texture Image Formats"
-
+#if ALLOW_ES3_FORMATS
     // Note that all compressed texture formats are filterable:
     // GLES 3.0.4 p161:
     // "[A] texture is complete unless any of the following conditions hold true:
     //  [...]
     //  * The effective internal format specified for the texture arrays is a sized
     //    internal color format that is not texture-filterable (see table 3.13) and [the
     //    mag filter requires filtering]."
     // Compressed formats are not sized internal color formats, and indeed they are not
@@ -800,17 +800,17 @@ FormatUsageAuthority::CreateForWebGL2(gl
     fnAllowES3TexFormat(FOO(COMPRESSED_RGBA8_ETC2_EAC                ), false, true);
     fnAllowES3TexFormat(FOO(COMPRESSED_SRGB8_ALPHA8_ETC2_EAC         ), false, true);
     fnAllowES3TexFormat(FOO(COMPRESSED_R11_EAC                       ), false, true);
     fnAllowES3TexFormat(FOO(COMPRESSED_RG11_EAC                      ), false, true);
     fnAllowES3TexFormat(FOO(COMPRESSED_SIGNED_R11_EAC                ), false, true);
     fnAllowES3TexFormat(FOO(COMPRESSED_SIGNED_RG11_EAC               ), false, true);
     fnAllowES3TexFormat(FOO(COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 ), false, true);
     fnAllowES3TexFormat(FOO(COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2), false, true);
-
+#endif
 #undef FOO
 
     // GLES 3.0.4, p206, "Required Renderbuffer Formats":
     // "Implementations are also required to support STENCIL_INDEX8. Requesting this
     //  internal format for a renderbuffer will allocate at least 8 stencil bit planes."
 
     auto usage = ptr->EditUsage(EffectiveFormat::STENCIL_INDEX8);
     usage->isRenderable = true;
--- a/dom/canvas/WebGLQuery.cpp
+++ b/dom/canvas/WebGLQuery.cpp
@@ -15,16 +15,17 @@ namespace mozilla {
 JSObject*
 WebGLQuery::WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto)
 {
     return dom::WebGLQueryBinding::Wrap(cx, this, givenProto);
 }
 
 WebGLQuery::WebGLQuery(WebGLContext* webgl)
     : WebGLContextBoundObject(webgl)
+    , mCanBeAvailable(false)
     , mGLName(0)
     , mType(0)
 {
     mContext->mQueries.insertBack(this);
 
     mContext->MakeContextCurrent();
     mContext->gl->fGenQueries(1, &mGLName);
 }
--- a/dom/canvas/WebGLQuery.h
+++ b/dom/canvas/WebGLQuery.h
@@ -5,28 +5,42 @@
 
 #ifndef WEBGL_QUERY_H_
 #define WEBGL_QUERY_H_
 
 #include "mozilla/LinkedList.h"
 #include "nsWrapperCache.h"
 
 #include "WebGLObjectModel.h"
+#include "nsThreadUtils.h"
 
 namespace mozilla {
 
 class WebGLQuery final
     : public nsWrapperCache
     , public WebGLRefCountedObject<WebGLQuery>
     , public LinkedListElement<WebGLQuery>
     , public WebGLContextBoundObject
 {
 public:
     explicit WebGLQuery(WebGLContext* webgl);
 
+    class AvailableRunnable final : public nsRunnable
+    {
+    public:
+        explicit AvailableRunnable(WebGLQuery* query) : mQuery(query) { }
+
+        NS_IMETHOD Run() override {
+            mQuery->mCanBeAvailable = true;
+            return NS_OK;
+        }
+    private:
+        const RefPtr<WebGLQuery> mQuery;
+    };
+
     bool IsActive() const;
 
     bool HasEverBeenActive() const {
         return mType != 0;
     }
 
     // WebGLRefCountedObject
     void Delete();
@@ -37,16 +51,18 @@ public:
     }
 
     // NS
     virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto) override;
 
     NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLQuery)
     NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLQuery)
 
+    // Track whether the event loop has spun
+    bool mCanBeAvailable;
 
 private:
     ~WebGLQuery() {
         DeleteOnce();
     };
 
     GLuint mGLName;
     GLenum mType;
--- a/dom/canvas/test/test_canvas.html
+++ b/dom/canvas/test/test_canvas.html
@@ -14396,22 +14396,17 @@ ctx.moveTo(50, 25);
 ctx.quadraticCurveTo(50, 25, 50, 25);
 ctx.stroke();
 
 ctx.beginPath();
 ctx.moveTo(50, 25);
 ctx.bezierCurveTo(50, 25, 50, 25, 50, 25);
 ctx.stroke();
 
-if (IsAzureSkia()) {
-  isPixel(ctx, 50,25, 0,255,0,255, 0);
-} else {
-  todo_isPixel(ctx, 50,25, 0,255,0,255, 0);
-}
-
+todo_isPixel(ctx, 50,25, 0,255,0,255, 0);
 
 }
 </script>
 
 <!-- [[[ test_2d.path.stroke.prune.line.html ]]] -->
 
 <p>Canvas test: 2d.path.stroke.prune.line</p>
 <!-- Testing: Zero-length line segments from lineTo are removed before stroking -->
@@ -14433,21 +14428,17 @@ ctx.lineWidth = 100;
 ctx.lineCap = 'round';
 ctx.lineJoin = 'round';
 
 ctx.beginPath();
 ctx.moveTo(50, 25);
 ctx.lineTo(50, 25);
 ctx.stroke();
 
-if (IsAzureSkia()) {
-  isPixel(ctx, 50,25, 0,255,0,255, 0);
-} else {
-  todo_isPixel(ctx, 50,25, 0,255,0,255, 0);
-}
+todo_isPixel(ctx, 50,25, 0,255,0,255, 0);
 
 }
 </script>
 
 <!-- [[[ test_2d.path.stroke.prune.rect.html ]]] -->
 
 <p>Canvas test: 2d.path.stroke.prune.rect</p>
 <!-- Testing: Zero-length line segments from rect and strokeRect are removed before stroking -->
--- a/dom/devicestorage/DeviceStorageStatics.cpp
+++ b/dom/devicestorage/DeviceStorageStatics.cpp
@@ -266,25 +266,32 @@ DeviceStorageStatics::DumpDirs()
     "pictures",
     "videos",
     "music",
     "sdcard",
     "override",
     nullptr
   };
 
+  const char* ptStr;
+  if (XRE_IsParentProcess()) {
+    ptStr = "parent";
+  } else {
+    ptStr = "child";
+  }
+
   for (uint32_t i = 0; i < TYPE_COUNT; ++i) {
     MOZ_ASSERT(storageTypes[i]);
 
     nsString path;
     if (mDirs[i]) {
       mDirs[i]->GetPath(path);
     }
-    DS_LOG_INFO("%s: '%s'",
-      storageTypes[i], NS_LossyConvertUTF16toASCII(path).get());
+    DS_LOG_INFO("(%s) %s: '%s'",
+      ptStr, storageTypes[i], NS_LossyConvertUTF16toASCII(path).get());
   }
 #endif
 }
 
 void
 DeviceStorageStatics::Shutdown()
 {
   MOZ_ASSERT(NS_IsMainThread());
@@ -292,16 +299,57 @@ DeviceStorageStatics::Shutdown()
   DS_LOG_INFO("");
 
   Preferences::RemoveObserver(this, kPrefOverrideRootDir);
   Preferences::RemoveObserver(this, kPrefTesting);
   Preferences::RemoveObserver(this, kPrefPromptTesting);
   Preferences::RemoveObserver(this, kPrefWritableName);
 }
 
+/* static */ void
+DeviceStorageStatics::GetDeviceStorageAreasForIPC(
+  DeviceStorageAreaInfo& aAreaInfo)
+{
+  MOZ_ASSERT(XRE_IsParentProcess());
+  MOZ_ASSERT(NS_IsMainThread());
+
+  InitializeDirs();
+
+  GetDirPath(TYPE_APPS,     aAreaInfo.apps());
+  GetDirPath(TYPE_CRASHES,  aAreaInfo.crashes());
+  GetDirPath(TYPE_PICTURES, aAreaInfo.pictures());
+  GetDirPath(TYPE_VIDEOS,   aAreaInfo.videos());
+  GetDirPath(TYPE_MUSIC,    aAreaInfo.music());
+  GetDirPath(TYPE_SDCARD,   aAreaInfo.sdcard());
+}
+
+/* static */ void
+DeviceStorageStatics::RecvDeviceStorageAreasFromParent(
+  const DeviceStorageAreaInfo& aAreaInfo)
+{
+  if (XRE_IsParentProcess()) {
+    // We are the parent. Therefore our info is already correct.
+    return;
+  }
+
+  StaticMutexAutoLock lock(sMutex);
+  if (NS_WARN_IF(!sInstance)) {
+    return;
+  }
+
+  NS_NewLocalFile(aAreaInfo.apps(),     true, getter_AddRefs(sInstance->mDirs[TYPE_APPS]));
+  NS_NewLocalFile(aAreaInfo.crashes(),  true, getter_AddRefs(sInstance->mDirs[TYPE_CRASHES]));
+  NS_NewLocalFile(aAreaInfo.pictures(), true, getter_AddRefs(sInstance->mDirs[TYPE_PICTURES]));
+  NS_NewLocalFile(aAreaInfo.videos(),   true, getter_AddRefs(sInstance->mDirs[TYPE_VIDEOS]));
+  NS_NewLocalFile(aAreaInfo.music(),    true, getter_AddRefs(sInstance->mDirs[TYPE_MUSIC]));
+  NS_NewLocalFile(aAreaInfo.sdcard(),   true, getter_AddRefs(sInstance->mDirs[TYPE_SDCARD]));
+
+  sInstance->mInitialized = true;
+}
+
 /* static */ already_AddRefed<nsIFile>
 DeviceStorageStatics::GetDir(DeviceStorageType aType)
 {
   MOZ_ASSERT(aType < TYPE_COUNT);
 
   StaticMutexAutoLock lock(sMutex);
   if (NS_WARN_IF(!sInstance)) {
     return nullptr;
@@ -327,16 +375,26 @@ DeviceStorageStatics::GetDir(DeviceStora
 #ifdef MOZ_WIDGET_GONK
     /* We should use volume mount points on B2G. */
     MOZ_ASSERT(!file);
 #endif
   }
   return file.forget();
 }
 
+/* static */ void
+DeviceStorageStatics::GetDirPath(DeviceStorageType aType, nsString& aDirPath)
+{
+  aDirPath.Truncate();
+  nsCOMPtr<nsIFile> file = GetDir(aType);
+  if (file) {
+    file->GetPath(aDirPath);
+  }
+}
+
 /* static */ bool
 DeviceStorageStatics::HasOverrideRootDir()
 {
   StaticMutexAutoLock lock(sMutex);
   if (NS_WARN_IF(!sInstance)) {
     return false;
   }
   return sInstance->mDirs[TYPE_OVERRIDE];
--- a/dom/devicestorage/DeviceStorageStatics.h
+++ b/dom/devicestorage/DeviceStorageStatics.h
@@ -3,17 +3,22 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_devicestorage_DeviceStorageStatics_h
 #define mozilla_dom_devicestorage_DeviceStorageStatics_h
 
 #include "mozilla/Mutex.h"
+#include "mozilla/RefPtr.h"
+#include "mozilla/StaticMutex.h"
+#include "mozilla/StaticPtr.h"
+#include "nsArrayUtils.h"
 
+class nsString;
 class nsDOMDeviceStorage;
 class DeviceStorageFile;
 #ifdef MOZ_WIDGET_GONK
 class nsIVolume;
 #endif
 
 namespace mozilla {
 namespace dom {
@@ -30,16 +35,19 @@ public:
   static void AddListener(nsDOMDeviceStorage* aListener);
   static void RemoveListener(nsDOMDeviceStorage* aListener);
 
   static bool LowDiskSpace();
   static bool IsPromptTesting();
   static void GetWritableName(nsString& aName);
   static void SetWritableName(const nsAString& aName);
 
+  static void GetDeviceStorageAreasForIPC(DeviceStorageAreaInfo& aAreaInfo);
+  static void RecvDeviceStorageAreasFromParent(const DeviceStorageAreaInfo& aAreaInfo);
+
   static bool HasOverrideRootDir();
   static already_AddRefed<nsIFile> GetAppsDir();
   static already_AddRefed<nsIFile> GetCrashesDir();
   static already_AddRefed<nsIFile> GetPicturesDir();
   static already_AddRefed<nsIFile> GetVideosDir();
   static already_AddRefed<nsIFile> GetMusicDir();
   static already_AddRefed<nsIFile> GetSdcardDir();
 
@@ -51,16 +59,17 @@ private:
     TYPE_VIDEOS,
     TYPE_MUSIC,
     TYPE_SDCARD,
     TYPE_OVERRIDE,
     TYPE_COUNT
   };
 
   static already_AddRefed<nsIFile> GetDir(DeviceStorageType aType);
+  static void GetDirPath(DeviceStorageType aType, nsString& aString);
 
   DeviceStorageStatics();
   virtual ~DeviceStorageStatics();
 
   void Init();
   void InitDirs();
   void DumpDirs();
   void Shutdown();
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -1878,16 +1878,21 @@ HTMLMediaElement::CaptureStreamInternal(
 
   if (!aGraph) {
     MediaStreamGraph::GraphDriverType graphDriverType =
       HasAudio() ? MediaStreamGraph::AUDIO_THREAD_DRIVER
                  : MediaStreamGraph::SYSTEM_THREAD_DRIVER;
     aGraph = MediaStreamGraph::GetInstance(graphDriverType, mAudioChannel);
   }
 
+  if (!mOutputStreams.IsEmpty() &&
+      aGraph != mOutputStreams[0].mStream->GetInputStream()->Graph()) {
+    return nullptr;
+  }
+
   OutputMediaStream* out = mOutputStreams.AppendElement();
   out->mStream = DOMMediaStream::CreateTrackUnionStream(window, aGraph);
   RefPtr<nsIPrincipal> principal = GetCurrentPrincipal();
   out->mStream->CombineWithPrincipal(principal);
   out->mStream->SetCORSMode(mCORSMode);
   out->mFinishWhenEnded = aFinishWhenEnded;
 
   mAudioCaptured = true;
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -12,16 +12,17 @@
 #include "nsQAppInstance.h"
 #endif
 
 #include "ContentChild.h"
 
 #include "BlobChild.h"
 #include "CrashReporterChild.h"
 #include "GeckoProfiler.h"
+#include "DeviceStorageStatics.h"
 #include "TabChild.h"
 #include "HandlerServiceChild.h"
 
 #include "mozilla/Attributes.h"
 #include "mozilla/LookAndFeel.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/ProcessHangMonitorIPC.h"
 #include "mozilla/devtools/HeapSnapshotTempFileHelperChild.h"
@@ -2590,16 +2591,25 @@ ContentChild::RecvVolumes(nsTArray<Volum
     if (vs) {
         vs->RecvVolumesFromParent(aVolumes);
     }
 #endif
     return true;
 }
 
 bool
+ContentChild::RecvDeviceStorageAreas(const DeviceStorageAreaInfo& areaInfo)
+{
+#if !defined(MOZ_WIDGET_GONK)
+    DeviceStorageStatics::RecvDeviceStorageAreasFromParent(areaInfo);
+#endif
+    return true;
+}
+
+bool
 ContentChild::RecvFilePathUpdate(const nsString& aStorageType,
                                  const nsString& aStorageName,
                                  const nsString& aPath,
                                  const nsCString& aReason)
 {
     if (nsDOMDeviceStorage::InstanceCount() == 0) {
         // No device storage instances in this process. Don't try and
         // and create a DeviceStorageFile since it will fail.
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -378,16 +378,17 @@ public:
     virtual bool RecvAppInfo(const nsCString& version, const nsCString& buildID,
                              const nsCString& name, const nsCString& UAName,
                              const nsCString& ID, const nsCString& vendor) override;
     virtual bool RecvAppInit() override;
 
     virtual bool RecvLastPrivateDocShellDestroyed() override;
 
     virtual bool RecvVolumes(InfallibleTArray<VolumeInfo>&& aVolumes) override;
+    virtual bool RecvDeviceStorageAreas(const DeviceStorageAreaInfo& areaInfo) override;
     virtual bool RecvFilePathUpdate(const nsString& aStorageType,
                                     const nsString& aStorageName,
                                     const nsString& aPath,
                                     const nsCString& aReason) override;
     virtual bool RecvFileSystemUpdate(const nsString& aFsName,
                                       const nsString& aVolumeName,
                                       const int32_t& aState,
                                       const int32_t& aMountGeneration,
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -25,16 +25,17 @@
 
 #include <set>
 
 #include "mozilla/a11y/PDocAccessible.h"
 #include "AppProcessChecker.h"
 #include "AudioChannelService.h"
 #include "BlobParent.h"
 #include "CrashReporterParent.h"
+#include "DeviceStorageStatics.h"
 #include "GMPServiceParent.h"
 #include "HandlerServiceParent.h"
 #include "IHistory.h"
 #include "imgIContainer.h"
 #include "mozIApplication.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/CSSStyleSheet.h"
 #include "mozilla/DataStorage.h"
@@ -1601,16 +1602,20 @@ ContentParent::ForwardKnownInfo()
     }
 #ifdef MOZ_WIDGET_GONK
     InfallibleTArray<VolumeInfo> volumeInfo;
     RefPtr<nsVolumeService> vs = nsVolumeService::GetSingleton();
     if (vs) {
         vs->GetVolumesForIPC(&volumeInfo);
         Unused << SendVolumes(volumeInfo);
     }
+#else
+    DeviceStorageAreaInfo areaInfo;
+    DeviceStorageStatics::GetDeviceStorageAreasForIPC(areaInfo);
+    Unused << SendDeviceStorageAreas(areaInfo);
 #endif /* MOZ_WIDGET_GONK */
 
     nsCOMPtr<nsISystemMessagesInternal> systemMessenger =
         do_GetService("@mozilla.org/system-message-internal;1");
     if (systemMessenger && !mIsForBrowser) {
         nsCOMPtr<nsIURI> manifestURI;
         nsresult rv = NS_NewURI(getter_AddRefs(manifestURI), mAppManifestURL);
         if (NS_SUCCEEDED(rv)) {
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -359,16 +359,25 @@ struct VolumeInfo {
   bool isSharing;
   bool isFormatting;
   bool isFake;
   bool isUnmounting;
   bool isRemovable;
   bool isHotSwappable;
 };
 
+struct DeviceStorageAreaInfo {
+  nsString music;
+  nsString pictures;
+  nsString videos;
+  nsString sdcard;
+  nsString apps;
+  nsString crashes;
+};
+
 struct ClipboardCapabilities {
   bool supportsSelectionClipboard;
   bool supportsFindClipboard;
 };
 
 union MaybeFileDesc {
     FileDescriptor;
     void_t;
@@ -590,16 +599,18 @@ child:
 
     // nsIPermissionManager messages
     AddPermission(Permission permission);
 
     ScreenSizeChanged(IntSize size);
 
     Volumes(VolumeInfo[] volumes);
 
+    DeviceStorageAreas(DeviceStorageAreaInfo areaInfo);
+
     FlushMemory(nsString reason);
 
     GarbageCollect();
     CycleCollect();
 
     /**
      * Start accessibility engine in content process.
      */
--- a/dom/media/GraphDriver.cpp
+++ b/dom/media/GraphDriver.cpp
@@ -52,54 +52,48 @@ GraphDriver::GraphDriver(MediaStreamGrap
     mPreviousDriver(nullptr),
     mNextDriver(nullptr)
 { }
 
 void GraphDriver::SetGraphTime(GraphDriver* aPreviousDriver,
                                GraphTime aLastSwitchNextIterationStart,
                                GraphTime aLastSwitchNextIterationEnd)
 {
+  GraphImpl()->GetMonitor().AssertCurrentThreadOwns();
   // We set mIterationEnd here, because the first thing a driver do when it
   // does an iteration is to update graph times, so we are in fact setting
   // mIterationStart of the next iteration by setting the end of the previous
   // iteration.
   mIterationStart = aLastSwitchNextIterationStart;
   mIterationEnd = aLastSwitchNextIterationEnd;
 
-  STREAM_LOG(LogLevel::Debug, ("Setting previous driver: %p (%s)", aPreviousDriver, aPreviousDriver->AsAudioCallbackDriver() ? "AudioCallbackDriver" : "SystemClockDriver"));
-  MOZ_ASSERT(!mPreviousDriver);
-  mPreviousDriver = aPreviousDriver;
+  STREAM_LOG(LogLevel::Debug, ("Setting previous driver: %p (%s)", PreviousDriver(), PreviousDriver()->AsAudioCallbackDriver() ? "AudioCallbackDriver" : "SystemClockDriver"));
+  MOZ_ASSERT(!PreviousDriver());
+  SetPreviousDriver(aPreviousDriver);
 }
 
 void GraphDriver::SwitchAtNextIteration(GraphDriver* aNextDriver)
 {
+  GraphImpl()->GetMonitor().AssertCurrentThreadOwns();
   // This is the situation where `mPreviousDriver` is an AudioCallbackDriver
   // that is switching device, and the graph has found the current driver is not
   // an AudioCallbackDriver, but tries to switch to a _new_ AudioCallbackDriver
   // because it found audio has to be output. In this case, simply ignore the
   // request to switch, since we know we will switch back to the old
   // AudioCallbackDriver when it has recovered from the device switching.
   if (aNextDriver->AsAudioCallbackDriver() &&
-      mPreviousDriver &&
-      mPreviousDriver->AsAudioCallbackDriver()->IsSwitchingDevice() &&
-      mPreviousDriver != aNextDriver) {
+      PreviousDriver() &&
+      PreviousDriver()->AsAudioCallbackDriver()->IsSwitchingDevice() &&
+      PreviousDriver() != aNextDriver) {
     return;
   }
   LIFECYCLE_LOG("Switching to new driver: %p (%s)",
       aNextDriver, aNextDriver->AsAudioCallbackDriver() ?
       "AudioCallbackDriver" : "SystemClockDriver");
-  mNextDriver = aNextDriver;
-}
-
-void GraphDriver::EnsureImmediateWakeUpLocked()
-{
-  mGraphImpl->GetMonitor().AssertCurrentThreadOwns();
-  mWaitState = WAITSTATE_WAKING_UP;
-  mGraphImpl->mGraphDriverAsleep = false; // atomic
-  mGraphImpl->GetMonitor().Notify();
+  SetNextDriver(aNextDriver);
 }
 
 GraphTime
 GraphDriver::StateComputedTime() const
 {
   return mGraphImpl->mStateComputedTime;
 }
 
@@ -146,16 +140,46 @@ void GraphDriver::Shutdown()
     RefPtr<AsyncCubebTask> releaseEvent =
       new AsyncCubebTask(AsAudioCallbackDriver(), AsyncCubebOperation::SHUTDOWN);
     releaseEvent->Dispatch();
   } else {
     Stop();
   }
 }
 
+bool GraphDriver::Switching()
+{
+  GraphImpl()->GetMonitor().AssertCurrentThreadOwns();
+  return mNextDriver || mPreviousDriver;
+}
+
+GraphDriver* GraphDriver::NextDriver()
+{
+  GraphImpl()->GetMonitor().AssertCurrentThreadOwns();
+  return mNextDriver;
+}
+
+GraphDriver* GraphDriver::PreviousDriver()
+{
+  GraphImpl()->GetMonitor().AssertCurrentThreadOwns();
+  return mPreviousDriver;
+}
+
+void GraphDriver::SetNextDriver(GraphDriver* aNextDriver)
+{
+  GraphImpl()->GetMonitor().AssertCurrentThreadOwns();
+  mNextDriver = aNextDriver;
+}
+
+void GraphDriver::SetPreviousDriver(GraphDriver* aPreviousDriver)
+{
+  GraphImpl()->GetMonitor().AssertCurrentThreadOwns();
+  mPreviousDriver = aPreviousDriver;
+}
+
 ThreadedDriver::ThreadedDriver(MediaStreamGraphImpl* aGraphImpl)
   : GraphDriver(aGraphImpl)
 { }
 
 ThreadedDriver::~ThreadedDriver()
 {
   if (mThread) {
     mThread->Shutdown();
@@ -169,30 +193,38 @@ public:
   }
   NS_IMETHOD Run()
   {
     char aLocal;
     STREAM_LOG(LogLevel::Debug, ("Starting system thread"));
     profiler_register_thread("MediaStreamGraph", &aLocal);
     LIFECYCLE_LOG("Starting a new system driver for graph %p\n",
                   mDriver->mGraphImpl);
-    if (mDriver->mPreviousDriver) {
+
+    GraphDriver* previousDriver = nullptr;
+    {
+      MonitorAutoLock mon(mDriver->mGraphImpl->GetMonitor());
+      previousDriver = mDriver->PreviousDriver();
+    }
+    if (previousDriver) {
       LIFECYCLE_LOG("%p releasing an AudioCallbackDriver(%p), for graph %p\n",
                     mDriver,
-                    mDriver->mPreviousDriver.get(),
+                    previousDriver,
                     mDriver->GraphImpl());
       MOZ_ASSERT(!mDriver->AsAudioCallbackDriver());
       // Stop and release the previous driver off-main-thread, but only if we're
       // not in the situation where we've fallen back to a system clock driver
       // because the osx audio stack is currently switching output device.
-      if (!mDriver->mPreviousDriver->AsAudioCallbackDriver()->IsSwitchingDevice()) {
+      if (!previousDriver->AsAudioCallbackDriver()->IsSwitchingDevice()) {
         RefPtr<AsyncCubebTask> releaseEvent =
-          new AsyncCubebTask(mDriver->mPreviousDriver->AsAudioCallbackDriver(), AsyncCubebOperation::SHUTDOWN);
-        mDriver->mPreviousDriver = nullptr;
+          new AsyncCubebTask(previousDriver->AsAudioCallbackDriver(), AsyncCubebOperation::SHUTDOWN);
         releaseEvent->Dispatch();
+
+        MonitorAutoLock mon(mDriver->mGraphImpl->GetMonitor());
+        mDriver->SetPreviousDriver(nullptr);
       }
     } else {
       MonitorAutoLock mon(mDriver->mGraphImpl->GetMonitor());
       MOZ_ASSERT(mDriver->mGraphImpl->MessagesQueued(), "Don't start a graph without messages queued.");
       mDriver->mGraphImpl->SwapMessageQueues();
     }
     mDriver->RunThread();
     return NS_OK;
@@ -223,20 +255,20 @@ void
 ThreadedDriver::Revive()
 {
   // Note: only called on MainThread, without monitor
   // We know were weren't in a running state
   STREAM_LOG(LogLevel::Debug, ("AudioCallbackDriver reviving."));
   // If we were switching, switch now. Otherwise, tell thread to run the main
   // loop again.
   MonitorAutoLock mon(mGraphImpl->GetMonitor());
-  if (mNextDriver) {
-    mNextDriver->SetGraphTime(this, mIterationStart, mIterationEnd);
-    mGraphImpl->SetCurrentDriver(mNextDriver);
-    mNextDriver->Start();
+  if (NextDriver()) {
+    NextDriver()->SetGraphTime(this, mIterationStart, mIterationEnd);
+    mGraphImpl->SetCurrentDriver(NextDriver());
+    NextDriver()->Start();
   } else {
     nsCOMPtr<nsIRunnable> event = new MediaStreamGraphInitThreadRunnable(this);
     mThread->Dispatch(event, NS_DISPATCH_NORMAL);
   }
 }
 
 void
 ThreadedDriver::Stop()
@@ -297,21 +329,22 @@ ThreadedDriver::RunThread()
     }
     STREAM_LOG(LogLevel::Debug,
                ("interval[%ld; %ld] state[%ld; %ld]",
                (long)mIterationStart, (long)mIterationEnd,
                (long)stateComputedTime, (long)nextStateComputedTime));
 
     stillProcessing = mGraphImpl->OneIteration(nextStateComputedTime);
 
-    if (mNextDriver && stillProcessing) {
+    MonitorAutoLock lock(GraphImpl()->GetMonitor());
+    if (NextDriver() && stillProcessing) {
       STREAM_LOG(LogLevel::Debug, ("Switching to AudioCallbackDriver"));
-      mNextDriver->SetGraphTime(this, mIterationStart, mIterationEnd);
-      mGraphImpl->SetCurrentDriver(mNextDriver);
-      mNextDriver->Start();
+      NextDriver()->SetGraphTime(this, mIterationStart, mIterationEnd);
+      mGraphImpl->SetCurrentDriver(NextDriver());
+      NextDriver()->Start();
       return;
     }
   }
 }
 
 MediaTime
 SystemClockDriver::GetIntervalForIteration()
 {
@@ -368,18 +401,17 @@ SystemClockDriver::WaitForNextIteration(
 
   if (mWaitState == WAITSTATE_WAITING_INDEFINITELY) {
     mGraphImpl->mGraphDriverAsleep = false; // atomic
   }
   mWaitState = WAITSTATE_RUNNING;
   mGraphImpl->mNeedAnotherIteration = false;
 }
 
-void
-SystemClockDriver::WakeUp()
+void SystemClockDriver::WakeUp()
 {
   mGraphImpl->GetMonitor().AssertCurrentThreadOwns();
   mWaitState = WAITSTATE_WAKING_UP;
   mGraphImpl->mGraphDriverAsleep = false; // atomic
   mGraphImpl->GetMonitor().Notify();
 }
 
 OfflineClockDriver::OfflineClockDriver(MediaStreamGraphImpl* aGraphImpl, GraphTime aSlice)
@@ -504,17 +536,16 @@ StreamAndPromiseForOperation::StreamAndP
 
 AudioCallbackDriver::AudioCallbackDriver(MediaStreamGraphImpl* aGraphImpl)
   : GraphDriver(aGraphImpl)
   , mSampleRate(0)
   , mIterationDurationMS(MEDIA_GRAPH_TARGET_PERIOD_MS)
   , mStarted(false)
   , mAudioChannel(aGraphImpl->AudioChannel())
   , mInCallback(false)
-  , mPauseRequested(false)
   , mMicrophoneActive(false)
 #ifdef XP_MACOSX
   , mCallbackReceivedWhileSwitching(0)
 #endif
 {
   STREAM_LOG(LogLevel::Debug, ("AudioCallbackDriver ctor for graph %p", aGraphImpl));
 }
 
@@ -563,22 +594,23 @@ AudioCallbackDriver::Init()
   cubeb_stream* stream;
   if (cubeb_stream_init(CubebUtils::GetCubebContext(), &stream,
                         "AudioCallbackDriver", params, latency,
                         DataCallback_s, StateCallback_s, this) == CUBEB_OK) {
     mAudioStream.own(stream);
   } else {
     NS_WARNING("Could not create a cubeb stream for MediaStreamGraph, falling back to a SystemClockDriver");
     // Fall back to a driver using a normal thread.
-    mNextDriver = new SystemClockDriver(GraphImpl());
-    mNextDriver->SetGraphTime(this, mIterationStart, mIterationEnd);
-    mGraphImpl->SetCurrentDriver(mNextDriver);
+    MonitorAutoLock lock(GraphImpl()->GetMonitor());
+    SetNextDriver(new SystemClockDriver(GraphImpl()));
+    NextDriver()->SetGraphTime(this, mIterationStart, mIterationEnd);
+    mGraphImpl->SetCurrentDriver(NextDriver());
     DebugOnly<bool> found = mGraphImpl->RemoveMixerCallback(this);
     NS_WARN_IF_FALSE(!found, "Mixer callback not added when switching?");
-    mNextDriver->Start();
+    NextDriver()->Start();
     return;
   }
 
   cubeb_stream_register_device_changed_callback(mAudioStream,
                                                 AudioCallbackDriver::DeviceChangedCallback_s);
 
   StartStream();
 
@@ -609,28 +641,33 @@ AudioCallbackDriver::Start()
   // because it is a blocking operation.
   if (NS_IsMainThread()) {
     STREAM_LOG(LogLevel::Debug, ("Starting audio threads for MediaStreamGraph %p from a new thread.", mGraphImpl));
     RefPtr<AsyncCubebTask> initEvent =
       new AsyncCubebTask(this, AsyncCubebOperation::INIT);
     initEvent->Dispatch();
   } else {
     STREAM_LOG(LogLevel::Debug, ("Starting audio threads for MediaStreamGraph %p from the previous driver's thread", mGraphImpl));
-    Init();
+    {
+      MonitorAutoUnlock mon(GraphImpl()->GetMonitor());
+      Init();
+    }
 
     // Check if we need to resolve promises because the driver just got switched
     // because of a resuming AudioContext
     if (!mPromisesForOperation.IsEmpty()) {
+      // CompleteAudioContextOperations takes the lock as needed
+      MonitorAutoUnlock mon(GraphImpl()->GetMonitor());
       CompleteAudioContextOperations(AsyncCubebOperation::INIT);
     }
 
-    if (mPreviousDriver) {
+    if (PreviousDriver()) {
       nsCOMPtr<nsIRunnable> event =
-        new MediaStreamGraphShutdownThreadRunnable(mPreviousDriver);
-      mPreviousDriver = nullptr;
+        new MediaStreamGraphShutdownThreadRunnable(PreviousDriver());
+      SetPreviousDriver(nullptr);
       NS_DispatchToMainThread(event);
     }
   }
 }
 
 void
 AudioCallbackDriver::StartStream()
 {
@@ -656,20 +693,20 @@ AudioCallbackDriver::Stop()
 void
 AudioCallbackDriver::Revive()
 {
   // Note: only called on MainThread, without monitor
   // We know were weren't in a running state
   STREAM_LOG(LogLevel::Debug, ("AudioCallbackDriver reviving."));
   // If we were switching, switch now. Otherwise, start the audio thread again.
   MonitorAutoLock mon(mGraphImpl->GetMonitor());
-  if (mNextDriver) {
-    mNextDriver->SetGraphTime(this, mIterationStart, mIterationEnd);
-    mGraphImpl->SetCurrentDriver(mNextDriver);
-    mNextDriver->Start();
+  if (NextDriver()) {
+    NextDriver()->SetGraphTime(this, mIterationStart, mIterationEnd);
+    mGraphImpl->SetCurrentDriver(NextDriver());
+    NextDriver()->Start();
   } else {
     STREAM_LOG(LogLevel::Debug, ("Starting audio threads for MediaStreamGraph %p from a new thread.", mGraphImpl));
     RefPtr<AsyncCubebTask> initEvent =
       new AsyncCubebTask(this, AsyncCubebOperation::INIT);
     initEvent->Dispatch();
   }
 }
 
@@ -738,17 +775,17 @@ AudioCallbackDriver::OSXDeviceSwitchingW
       // If we have a self reference, we have fallen back temporarily on a
       // system clock driver, but we just got called back, that means the osx
       // audio backend has switched to the new device.
       // Ask the graph to switch back to the previous AudioCallbackDriver
       // (`this`), and when the graph has effectively switched, we can drop
       // the self reference and unref the SystemClockDriver we fallen back on.
       if (GraphImpl()->CurrentDriver() == this) {
         mSelfReference.Drop(this);
-        mNextDriver = nullptr;
+        SetNextDriver(nullptr);
       } else {
         GraphImpl()->CurrentDriver()->SwitchAtNextIteration(this);
       }
 
     }
     return true;
   }
 
@@ -756,21 +793,16 @@ AudioCallbackDriver::OSXDeviceSwitchingW
 }
 #endif // XP_MACOSX
 
 long
 AudioCallbackDriver::DataCallback(AudioDataValue* aBuffer, long aFrames)
 {
   bool stillProcessing;
 
-  if (mPauseRequested) {
-    PodZero(aBuffer, aFrames * mGraphImpl->AudioChannelCount());
-    return aFrames;
-  }
-
 #ifdef XP_MACOSX
   if (OSXDeviceSwitchingWorkaround()) {
     PodZero(aBuffer, aFrames * mGraphImpl->AudioChannelCount());
     return aFrames;
   }
 #endif
 
 #ifdef DEBUG
@@ -848,29 +880,33 @@ AudioCallbackDriver::DataCallback(AudioD
     stillProcessing = mGraphImpl->OneIteration(nextStateComputedTime);
   } else {
     NS_WARNING("DataCallback buffer filled entirely from scratch buffer, skipping iteration.");
     stillProcessing = true;
   }
 
   mBuffer.BufferFilled();
 
-  if (mNextDriver && stillProcessing) {
-    {
-      // If the audio stream has not been started by the previous driver or
-      // the graph itself, keep it alive.
-      MonitorAutoLock mon(mGraphImpl->GetMonitor());
-      if (!IsStarted()) {
-        return aFrames;
-      }
+  bool switching = false;
+  {
+    MonitorAutoLock mon(mGraphImpl->GetMonitor());
+    switching = !!NextDriver();
+  }
+
+  if (switching && stillProcessing) {
+    // If the audio stream has not been started by the previous driver or
+    // the graph itself, keep it alive.
+    MonitorAutoLock mon(mGraphImpl->GetMonitor());
+    if (!IsStarted()) {
+      return aFrames;
     }
     STREAM_LOG(LogLevel::Debug, ("Switching to system driver."));
-    mNextDriver->SetGraphTime(this, mIterationStart, mIterationEnd);
-    mGraphImpl->SetCurrentDriver(mNextDriver);
-    mNextDriver->Start();
+    NextDriver()->SetGraphTime(this, mIterationStart, mIterationEnd);
+    mGraphImpl->SetCurrentDriver(NextDriver());
+    NextDriver()->Start();
     // Returning less than aFrames starts the draining and eventually stops the
     // audio thread. This function will never get called again.
     return aFrames - 1;
   }
 
   if (!stillProcessing) {
     LIFECYCLE_LOG("Stopping audio thread for MediaStreamGraph %p", this);
     return aFrames - 1;
@@ -963,17 +999,17 @@ AudioCallbackDriver::DeviceChangedCallba
   }
 
   if (mSelfReference) {
     return;
   }
   STREAM_LOG(LogLevel::Error, ("Switching to SystemClockDriver during output switch"));
   mSelfReference.Take(this);
   mCallbackReceivedWhileSwitching = 0;
-  mNextDriver = new SystemClockDriver(GraphImpl());
+  SetNextDriver(new SystemClockDriver(GraphImpl()));
   mNextDriver->SetGraphTime(this, mIterationStart, mIterationEnd);
   mGraphImpl->SetCurrentDriver(mNextDriver);
   mNextDriver->Start();
 #endif
 }
 
 void
 AudioCallbackDriver::SetMicrophoneActive(bool aActive)
--- a/dom/media/GraphDriver.h
+++ b/dom/media/GraphDriver.h
@@ -56,16 +56,56 @@ class OfflineClockDriver;
 
 /**
  * A driver is responsible for the scheduling of the processing, the thread
  * management, and give the different clocks to a MediaStreamGraph. This is an
  * abstract base class. A MediaStreamGraph can be driven by an
  * OfflineClockDriver, if the graph is offline, or a SystemClockDriver, if the
  * graph is real time.
  * A MediaStreamGraph holds an owning reference to its driver.
+ *
+ * The lifetime of drivers is a complicated affair. Here are the different
+ * scenarii that can happen:
+ *
+ * Starting a MediaStreamGraph with an AudioCallbackDriver
+ * - A new thread T is created, from the main thread.
+ * - On this thread T, cubeb is initialized if needed, and a cubeb_stream is
+ *   created and started
+ * - The thread T posts a message to the main thread to terminate itself.
+ * - The graph runs off the audio thread
+ *
+ * Starting a MediaStreamGraph with a SystemClockDriver:
+ * - A new thread T is created from the main thread.
+ * - The graph runs off this thread.
+ *
+ * Switching from a SystemClockDriver to an AudioCallbackDriver:
+ * - A new AudioCallabackDriver is created and initialized on the graph thread
+ * - At the end of the MSG iteration, the SystemClockDriver transfers its timing
+ *   info and a reference to itself to the AudioCallbackDriver. It then starts
+ *   the AudioCallbackDriver.
+ * - When the AudioCallbackDriver starts, it checks if it has been switched from
+ *   a SystemClockDriver, and if that is the case, sends a message to the main
+ *   thread to shut the SystemClockDriver thread down.
+ * - The graph now runs off an audio callback
+ *
+ * Switching from an AudioCallbackDriver to a SystemClockDriver:
+ * - A new SystemClockDriver is created, and set as mNextDriver.
+ * - At the end of the MSG iteration, the AudioCallbackDriver transfers its
+ *   timing info and a reference to itself to the SystemClockDriver. A new
+ *   SystemClockDriver is started from the current audio thread.
+ * - When starting, the SystemClockDriver checks if it has been switched from an
+ *   AudioCallbackDriver. If yes, it creates a new temporary thread to release
+ *   the cubeb_streams. This temporary thread closes the cubeb_stream, and
+ *   then dispatches a message to the main thread to be terminated.
+ * - The graph now runs off a normal thread.
+ *
+ * Two drivers cannot run at the same time for the same graph. The thread safety
+ * of the different attributes of drivers, and they access pattern is documented
+ * next to the members themselves.
+ *
  */
 class GraphDriver
 {
 public:
   explicit GraphDriver(MediaStreamGraphImpl* aGraphImpl);
 
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GraphDriver);
   /* For real-time graphs, this waits until it's time to process more data. For
@@ -87,46 +127,33 @@ public:
    * controlled (because we are using a {System,Offline}ClockDriver, and decide
    * how often we want to wakeup/how much we want to process per iteration), or
    * it can be indirectly set by the latency of the audio backend, and the
    * number of buffers of this audio backend: say we have four buffers, and 40ms
    * latency, we will get a callback approximately every 10ms. */
   virtual uint32_t IterationDuration() = 0;
 
   /* Return whether we are switching or not. */
-  bool Switching() {
-    return mNextDriver || mPreviousDriver;
-  }
+  bool Switching();
 
-  GraphDriver* NextDriver()
-  {
-    return mNextDriver;
-  }
+  // Those are simply or setting the associated pointer, but assert that the
+  // lock is held.
+  GraphDriver* NextDriver();
+  GraphDriver* PreviousDriver();
+  void SetNextDriver(GraphDriver* aNextDriver);
+  void SetPreviousDriver(GraphDriver* aPreviousDriver);
 
   /**
    * If we are running a real time graph, get the current time stamp to schedule
    * video frames. This has to be reimplemented by real time drivers.
    */
   virtual TimeStamp GetCurrentTimeStamp() {
     return mCurrentTimeStamp;
   }
 
-  bool IsWaiting() {
-    return mWaitState == WAITSTATE_WAITING_INDEFINITELY ||
-           mWaitState == WAITSTATE_WAITING_FOR_NEXT_ITERATION;
-  }
-
-  bool IsWaitingIndefinitly() {
-    return mWaitState == WAITSTATE_WAITING_INDEFINITELY;
-  }
-
-  GraphTime IterationStart() {
-    return mIterationStart;
-  }
-
   GraphTime IterationEnd() {
     return mIterationEnd;
   }
 
   virtual void GetAudioBuffer(float** aBuffer, long& aFrames) {
     MOZ_CRASH("This is not an Audio GraphDriver!");
   }
 
@@ -146,23 +173,16 @@ public:
 
   /**
    * Set the time for a graph, on a driver. This is used so a new driver just
    * created can start at the right point in time.
    */
   void SetGraphTime(GraphDriver* aPreviousDriver,
                     GraphTime aLastSwitchNextIterationStart,
                     GraphTime aLastSwitchNextIterationEnd);
-
-  /**
-   * Call this to indicate that another iteration of the control loop is
-   * required immediately. The monitor must already be held.
-   */
-  void EnsureImmediateWakeUpLocked();
-
   /**
    * Call this to indicate that another iteration of the control loop is
    * required on its regular schedule. The monitor must not be held.
    * This function has to be idempotent.
    */
   void EnsureNextIteration();
 
   /**
@@ -174,46 +194,60 @@ public:
     return mGraphImpl;
   }
 
   virtual bool OnThread() = 0;
 
 protected:
   GraphTime StateComputedTime() const;
 
-  // Time of the start of this graph iteration.
+  // Time of the start of this graph iteration. This must be accessed while
+  // having the monitor.
   GraphTime mIterationStart;
-  // Time of the end of this graph iteration.
+  // Time of the end of this graph iteration. This must be accessed while having
+  // the monitor.
   GraphTime mIterationEnd;
   // The MediaStreamGraphImpl that owns this driver. This has a lifetime longer
-  // than the driver, and will never be null.
+  // than the driver, and will never be null. Hence, it can be accesed without
+  // monitor.
   MediaStreamGraphImpl* mGraphImpl;
 
   // This enum specifies the wait state of the driver.
   enum WaitState {
     // RunThread() is running normally
     WAITSTATE_RUNNING,
     // RunThread() is paused waiting for its next iteration, which will
     // happen soon
     WAITSTATE_WAITING_FOR_NEXT_ITERATION,
     // RunThread() is paused indefinitely waiting for something to change
     WAITSTATE_WAITING_INDEFINITELY,
     // Something has signaled RunThread() to wake up immediately,
     // but it hasn't done so yet
     WAITSTATE_WAKING_UP
   };
+  // This must be access with the monitor.
   WaitState mWaitState;
 
+  // This is used on the main thread (during initialization), and the graph
+  // thread. No monitor needed because we know the graph thread does not run
+  // during the initialization.
   TimeStamp mCurrentTimeStamp;
   // This is non-null only when this driver has recently switched from an other
   // driver, and has not cleaned it up yet (for example because the audio stream
   // is currently calling the callback during initialization).
+  //
+  // This is written to when changing driver, from the previous driver's thread,
+  // or a thread created for the occasion. This is read each time we need to
+  // check whether we're changing driver (in Switching()), from the graph
+  // thread.
+  // This must be accessed using the {Set,Get}PreviousDriver methods.
   RefPtr<GraphDriver> mPreviousDriver;
   // This is non-null only when this driver is going to switch to an other
   // driver at the end of this iteration.
+  // This must be accessed using the {Set,Get}NextDriver methods.
   RefPtr<GraphDriver> mNextDriver;
   virtual ~GraphDriver()
   { }
 };
 
 class MediaStreamGraphInitThreadRunnable;
 
 /**
@@ -259,16 +293,18 @@ public:
   explicit SystemClockDriver(MediaStreamGraphImpl* aGraphImpl);
   virtual ~SystemClockDriver();
   virtual MediaTime GetIntervalForIteration() override;
   virtual void WaitForNextIteration() override;
   virtual void WakeUp() override;
 
 
 private:
+  // Those are only modified (after initialization) on the graph thread. The
+  // graph thread does not run during the initialization.
   TimeStamp mInitialTimeStamp;
   TimeStamp mLastTimeStamp;
 };
 
 /**
  * An OfflineClockDriver runs the graph as fast as possible, without waiting
  * between iteration.
  */
@@ -415,28 +451,32 @@ private:
   void StartStream();
   friend class AsyncCubebTask;
   void Init();
   /* MediaStreamGraphs are always down/up mixed to stereo for now. */
   static const uint32_t ChannelCount = 2;
   /* The size of this buffer comes from the fact that some audio backends can
    * call back with a number of frames lower than one block (128 frames), so we
    * need to keep at most two block in the SpillBuffer, because we always round
-   * up to block boundaries during an iteration. */
+   * up to block boundaries during an iteration.
+   * This is only ever accessed on the audio callback thread. */
   SpillBuffer<AudioDataValue, WEBAUDIO_BLOCK_SIZE * 2, ChannelCount> mScratchBuffer;
   /* Wrapper to ensure we write exactly the number of frames we need in the
-   * audio buffer cubeb passes us. */
+   * audio buffer cubeb passes us. This is only ever accessed on the audio
+   * callback thread. */
   AudioCallbackBufferWrapper<AudioDataValue, ChannelCount> mBuffer;
   /* cubeb stream for this graph. This is guaranteed to be non-null after Init()
-   * has been called. */
+   * has been called, and is synchronized internaly. */
   nsAutoRef<cubeb_stream> mAudioStream;
-  /* The sample rate for the aforementionned cubeb stream. */
+  /* The sample rate for the aforementionned cubeb stream. This is set on
+   * initialization and can be read safely afterwards. */
   uint32_t mSampleRate;
   /* Approximation of the time between two callbacks. This is used to schedule
-   * video frames. This is in milliseconds. */
+   * video frames. This is in milliseconds. Only even used (after
+   * inizatialization) on the audio callback thread. */
   uint32_t mIterationDurationMS;
   /* cubeb_stream_init calls the audio callback to prefill the buffers. The
    * previous driver has to be kept alive until the audio stream has been
    * started, because it is responsible to call cubeb_stream_start, so we delay
    * the cleanup of the previous driver until it has started the audio stream.
    * Otherwise, there is a race where we kill the previous driver thread
    * between cubeb_stream_init and cubeb_stream_start,
    * and callbacks after the prefill never get called.
@@ -454,23 +494,23 @@ private:
     explicit AutoInCallback(AudioCallbackDriver* aDriver);
     ~AutoInCallback();
     AudioCallbackDriver* mDriver;
   };
 
   /* Thread for off-main-thread initialization and
    * shutdown of the audio stream. */
   nsCOMPtr<nsIThread> mInitShutdownThread;
+  /* This must be accessed with the graph monitor held. */
   nsAutoTArray<StreamAndPromiseForOperation, 1> mPromisesForOperation;
+  /* This is set during initialization, and ca be read safely afterwards. */
   dom::AudioChannel mAudioChannel;
+  /* This is atomic and is set by the audio callback thread. It can be read by
+   * any thread safely. */
   Atomic<bool> mInCallback;
-  /* A thread has been created to be able to pause and restart the audio thread,
-   * but has not done so yet. This indicates that the callback should return
-   * early */
-  bool mPauseRequested;
   /**
    * True if microphone is being used by this process. This is synchronized by
    * the graph's monitor. */
   bool mMicrophoneActive;
 
 #ifdef XP_MACOSX
   /* Implements the workaround for the osx audio stack when changing output
    * devices. See comments in .cpp */
--- a/dom/media/MediaStreamGraph.cpp
+++ b/dom/media/MediaStreamGraph.cpp
@@ -356,19 +356,25 @@ MediaStreamGraphImpl::UpdateStreamOrder(
       if (mLifecycleState == LIFECYCLE_RUNNING) {
         SystemClockDriver* driver = new SystemClockDriver(this);
         mMixer.RemoveCallback(CurrentDriver()->AsAudioCallbackDriver());
         CurrentDriver()->SwitchAtNextIteration(driver);
       }
     }
   }
 
+  bool switching = false;
+  {
+    MonitorAutoLock mon(mMonitor);
+    switching = CurrentDriver()->Switching();
+  }
+
   if (audioTrackPresent && mRealtime &&
       !CurrentDriver()->AsAudioCallbackDriver() &&
-      !CurrentDriver()->Switching()) {
+      !switching) {
     MonitorAutoLock mon(mMonitor);
     if (mLifecycleState == LIFECYCLE_RUNNING) {
       AudioCallbackDriver* driver = new AudioCallbackDriver(this);
       mMixer.AddCallback(driver);
       CurrentDriver()->SwitchAtNextIteration(driver);
     }
   }
 
@@ -616,18 +622,25 @@ MediaStreamGraphImpl::CreateOrDestroyAud
     } else {
       MediaStream::AudioOutputStream* audioOutputStream =
         aStream->mAudioOutputStreams.AppendElement();
       audioOutputStream->mAudioPlaybackStartTime = mProcessedTime;
       audioOutputStream->mBlockedAudioTime = 0;
       audioOutputStream->mLastTickWritten = 0;
       audioOutputStream->mTrackID = tracks->GetID();
 
+      bool switching = false;
+
+      {
+        MonitorAutoLock lock(mMonitor);
+        switching = CurrentDriver()->Switching();
+      }
+
       if (!CurrentDriver()->AsAudioCallbackDriver() &&
-          !CurrentDriver()->Switching()) {
+          !switching) {
         MonitorAutoLock mon(mMonitor);
         if (mLifecycleState == LIFECYCLE_RUNNING) {
           AudioCallbackDriver* driver = new AudioCallbackDriver(this);
           mMixer.AddCallback(driver);
           CurrentDriver()->SwitchAtNextIteration(driver);
         }
       }
     }
@@ -1159,18 +1172,23 @@ MediaStreamGraphImpl::Process()
   }
 
   if (CurrentDriver()->AsAudioCallbackDriver() && ticksPlayed) {
     mMixer.FinishMixing();
   }
 
   // If we are switching away from an AudioCallbackDriver, we don't need the
   // mixer anymore.
+  bool switching = false;
+  {
+    MonitorAutoLock lock(mMonitor);
+    switching = CurrentDriver()->Switching();
+  }
   if (CurrentDriver()->AsAudioCallbackDriver() &&
-      CurrentDriver()->Switching()) {
+      switching) {
     bool isStarted;
     {
       MonitorAutoLock mon(mMonitor);
       isStarted = CurrentDriver()->AsAudioCallbackDriver()->IsStarted();
     }
     if (isStarted) {
       mMixer.RemoveCallback(CurrentDriver()->AsAudioCallbackDriver());
     }
@@ -3018,31 +3036,42 @@ void
 MediaStreamGraphImpl::ApplyAudioContextOperationImpl(
     MediaStream* aDestinationStream, const nsTArray<MediaStream*>& aStreams,
     AudioContextOperation aOperation, void* aPromise)
 {
   MOZ_ASSERT(CurrentDriver()->OnThread());
 
   SuspendOrResumeStreams(aOperation, aStreams);
 
+  bool switching = false;
+  GraphDriver* nextDriver = nullptr;
+  {
+    MonitorAutoLock lock(mMonitor);
+    switching = CurrentDriver()->Switching();
+    if (switching) {
+      nextDriver = CurrentDriver()->NextDriver();
+    }
+  }
+
   // If we have suspended the last AudioContext, and we don't have other
   // streams that have audio, this graph will automatically switch to a
   // SystemCallbackDriver, because it can't find a MediaStream that has an audio
   // track. When resuming, force switching to an AudioCallbackDriver (if we're
   // not already switching). It would have happened at the next iteration
   // anyways, but doing this now save some time.
   if (aOperation == AudioContextOperation::Resume) {
     if (!CurrentDriver()->AsAudioCallbackDriver()) {
       AudioCallbackDriver* driver;
-      if (CurrentDriver()->Switching()) {
-        MOZ_ASSERT(CurrentDriver()->NextDriver()->AsAudioCallbackDriver());
-        driver = CurrentDriver()->NextDriver()->AsAudioCallbackDriver();
+      if (switching) {
+        MOZ_ASSERT(nextDriver->AsAudioCallbackDriver());
+        driver = nextDriver->AsAudioCallbackDriver();
       } else {
         driver = new AudioCallbackDriver(this);
         mMixer.AddCallback(driver);
+        MonitorAutoLock lock(mMonitor);
         CurrentDriver()->SwitchAtNextIteration(driver);
       }
       driver->EnqueueStreamAndPromiseForOperation(aDestinationStream,
           aPromise, aOperation);
     } else {
       // We are resuming a context, but we are already using an
       // AudioCallbackDriver, we can resolve the promise now.
       AudioContextOperationCompleted(aDestinationStream, aPromise, aOperation);
@@ -3066,29 +3095,30 @@ MediaStreamGraphImpl::ApplyAudioContextO
       }
     }
     if (!audioTrackPresent && CurrentDriver()->AsAudioCallbackDriver()) {
       CurrentDriver()->AsAudioCallbackDriver()->
         EnqueueStreamAndPromiseForOperation(aDestinationStream, aPromise,
                                             aOperation);
 
       SystemClockDriver* driver;
-      if (CurrentDriver()->NextDriver()) {
-        MOZ_ASSERT(!CurrentDriver()->NextDriver()->AsAudioCallbackDriver());
+      if (nextDriver) {
+        MOZ_ASSERT(!nextDriver->AsAudioCallbackDriver());
       } else {
         driver = new SystemClockDriver(this);
         mMixer.RemoveCallback(CurrentDriver()->AsAudioCallbackDriver());
+        MonitorAutoLock lock(mMonitor);
         CurrentDriver()->SwitchAtNextIteration(driver);
       }
       // We are closing or suspending an AudioContext, but we just got resumed.
       // Queue the operation on the next driver so that the ordering is
       // preserved.
-    } else if (!audioTrackPresent && CurrentDriver()->Switching()) {
-      MOZ_ASSERT(CurrentDriver()->NextDriver()->AsAudioCallbackDriver());
-      CurrentDriver()->NextDriver()->AsAudioCallbackDriver()->
+    } else if (!audioTrackPresent && switching) {
+      MOZ_ASSERT(nextDriver->AsAudioCallbackDriver());
+      nextDriver->AsAudioCallbackDriver()->
         EnqueueStreamAndPromiseForOperation(aDestinationStream, aPromise,
                                             aOperation);
     } else {
       // We are closing or suspending an AudioContext, but something else is
       // using the audio stream, we can resolve the promise now.
       AudioContextOperationCompleted(aDestinationStream, aPromise, aOperation);
     }
   }
--- a/dom/media/platforms/ffmpeg/FFmpegDataDecoder.cpp
+++ b/dom/media/platforms/ffmpeg/FFmpegDataDecoder.cpp
@@ -52,17 +52,17 @@ FFmpegDataDecoder<LIBAV_VER>::~FFmpegDat
  * For now, we just look for YUV420P as it is the only non-HW accelerated format
  * supported by FFmpeg's H264 decoder.
  */
 static PixelFormat
 ChoosePixelFormat(AVCodecContext* aCodecContext, const PixelFormat* aFormats)
 {
   FFMPEG_LOG("Choosing FFmpeg pixel format for video decoding.");
   for (; *aFormats > -1; aFormats++) {
-    if (*aFormats == PIX_FMT_YUV420P) {
+    if (*aFormats == PIX_FMT_YUV420P || *aFormats == PIX_FMT_YUVJ420P) {
       FFMPEG_LOG("Requesting pixel format YUV420P.");
       return PIX_FMT_YUV420P;
     }
   }
 
   NS_WARNING("FFmpeg does not share any supported pixel formats.");
   return PIX_FMT_NONE;
 }
new file mode 100644
--- /dev/null
+++ b/dom/media/test/crashtests/1228484.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+
+var htmlAudio = new Audio(URL.createObjectURL(new window.MediaSource()));
+
+(new window.AudioContext("ringer")).createMediaElementSource(htmlAudio);
+(new window.AudioContext("alarm")).createMediaElementSource(htmlAudio);
+
+</script>
+</head>
+</html>
--- a/dom/media/test/crashtests/crashtests.list
+++ b/dom/media/test/crashtests/crashtests.list
@@ -76,16 +76,17 @@ load 1041466.html
 load 1045650.html
 load 1080986.html
 load 1122218.html
 load 1127188.html
 load 1157994.html
 load 1158427.html
 load 1185176.html
 load 1185192.html
+load 1228484.html
 load analyser-channels-1.html
 load audiocontext-double-suspend.html
 load buffer-source-duration-1.html
 load buffer-source-ended-1.html
 load buffer-source-resampling-start-1.html
 load doppler-1.html
 HTTP load media-element-source-seek-1.html
 load offline-buffer-source-ended-1.html
--- a/dom/permission/PermissionUtils.cpp
+++ b/dom/permission/PermissionUtils.cpp
@@ -8,18 +8,17 @@
 
 namespace mozilla {
 namespace dom {
 
 const char* kPermissionTypes[] = {
   "geo",
   "desktop-notification",
   // Alias `push` to `desktop-notification`.
-  "desktop-notification",
-  "midi"
+  "desktop-notification"
 };
 
 // `-1` for the last null entry.
 const size_t kPermissionNameCount =
   MOZ_ARRAY_LENGTH(PermissionNameValues::strings) - 1;
 
 static_assert(MOZ_ARRAY_LENGTH(kPermissionTypes) == kPermissionNameCount,
               "kPermissionTypes and PermissionName count should match");
--- a/dom/permission/Permissions.cpp
+++ b/dom/permission/Permissions.cpp
@@ -51,17 +51,17 @@ CreatePushPermissionStatus(JSContext* aC
   PushPermissionDescriptor permission;
   JS::Rooted<JS::Value> value(aCx, JS::ObjectOrNullValue(aPermission));
   if (NS_WARN_IF(!permission.Init(aCx, value))) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return nullptr;
   }
 
   if (permission.mUserVisible) {
-    aRv.Throw(NS_ERROR_UNEXPECTED);
+    aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
     return nullptr;
   }
 
   return PermissionStatus::Create(aWindow, permission.mName, aRv);
 }
 
 already_AddRefed<PermissionStatus>
 CreatePermissionStatus(JSContext* aCx,
@@ -79,18 +79,18 @@ CreatePermissionStatus(JSContext* aCx,
   switch (permission.mName) {
     case PermissionName::Geolocation:
     case PermissionName::Notifications:
       return PermissionStatus::Create(aWindow, permission.mName, aRv);
 
     case PermissionName::Push:
       return CreatePushPermissionStatus(aCx, aPermission, aWindow, aRv);
 
-    case PermissionName::Midi:
     default:
+      MOZ_ASSERT_UNREACHABLE("Unhandled type");
       aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
       return nullptr;
   }
 }
 
 } // namespace
 
 already_AddRefed<Promise>
--- a/dom/permission/tests/test_permissions_api.html
+++ b/dom/permission/tests/test_permissions_api.html
@@ -22,17 +22,18 @@ SimpleTest.waitForExplicitFinish();
 
 const PERMISSIONS = [
   { name: 'geolocation', perm: 'geo' },
   { name: 'notifications', perm: 'desktop-notification' },
   { name: 'push', perm: 'desktop-notification' },
 ];
 
 const UNSUPPORTED_PERMISSIONS = [
-  'midi',
+  'foobarbaz',  // Not in spec, for testing only.
+  'midi'
 ];
 
 function setup() {
   return new Promise((resolve, reject) => {
     SpecialPowers.pushPrefEnv({'set': [
       ['dom.permissions.enabled', true],
     ]}, resolve);
   });
@@ -56,17 +57,20 @@ function checkPermissions(state) {
       error => ok(false, `query should not have rejected for '${x.name}'`));
   }));
 }
 
 function checkUnsupportedPermissions() {
   return Promise.all(UNSUPPORTED_PERMISSIONS.map(name => {
     return navigator.permissions.query({ name }).then(
       result => ok(false, `query should not have resolved for '${name}'`),
-      error => ok(true, `query should have rejected for '${name}'`));
+      error => {
+        is(error.name, 'TypeError',
+           `query should have thrown TypeError for '${name}'`);
+      });
   }));
 }
 
 function checkUserVisiblePushPermission() {
   return navigator.permissions.query({ name: 'push', userVisible: true }).then(
     result => ok(false, `query should not have resolved for userVisible push`),
     error => ok(true, `query should have rejected for userVisible push`));
 }
--- a/dom/push/PushManager.cpp
+++ b/dom/push/PushManager.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/PushManager.h"
 
+#include "mozilla/Base64.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Services.h"
 #include "mozilla/unused.h"
 #include "mozilla/dom/PushManagerBinding.h"
 #include "mozilla/dom/PushSubscriptionBinding.h"
 #include "mozilla/dom/ServiceWorkerGlobalScopeBinding.h"
 
 #include "mozilla/dom/Promise.h"
@@ -60,16 +61,36 @@ GetPermissionState(nsIPrincipal* aPrinci
   } else if (permission == nsIPermissionManager::DENY_ACTION) {
     aState = PushPermissionState::Denied;
   } else {
     aState = PushPermissionState::Prompt;
   }
   return NS_OK;
 }
 
+void
+SubscriptionToJSON(PushSubscriptionJSON& aJSON, const nsString& aEndpoint,
+                   const nsTArray<uint8_t>& aRawP256dhKey,
+                   const nsTArray<uint8_t>& aAuthSecret)
+{
+  aJSON.mEndpoint.Construct();
+  aJSON.mEndpoint.Value() = aEndpoint;
+
+  aJSON.mKeys.mP256dh.Construct();
+  nsresult rv = Base64URLEncode(aRawP256dhKey.Length(),
+                                aRawP256dhKey.Elements(),
+                                aJSON.mKeys.mP256dh.Value());
+  Unused << NS_WARN_IF(NS_FAILED(rv));
+
+  aJSON.mKeys.mAuth.Construct();
+  rv = Base64URLEncode(aAuthSecret.Length(), aAuthSecret.Elements(),
+                       aJSON.mKeys.mAuth.Value());
+  Unused << NS_WARN_IF(NS_FAILED(rv));
+}
+
 } // anonymous namespace
 
 class UnsubscribeResultCallback final : public nsIUnsubscribeResultCallback
 {
 public:
   NS_DECL_ISUPPORTS
 
   explicit UnsubscribeResultCallback(Promise* aPromise)
@@ -118,16 +139,22 @@ PushSubscription::Unsubscribe(ErrorResul
 
   RefPtr<UnsubscribeResultCallback> callback =
     new UnsubscribeResultCallback(p);
   Unused << NS_WARN_IF(NS_FAILED(
     service->Unsubscribe(mScope, mPrincipal, callback)));
   return p.forget();
 }
 
+void
+PushSubscription::ToJSON(PushSubscriptionJSON& aJSON)
+{
+  SubscriptionToJSON(aJSON, mEndpoint, mRawP256dhKey, mAuthSecret);
+}
+
 PushSubscription::PushSubscription(nsIGlobalObject* aGlobal,
                                    const nsAString& aEndpoint,
                                    const nsAString& aScope,
                                    const nsTArray<uint8_t>& aRawP256dhKey,
                                    const nsTArray<uint8_t>& aAuthSecret)
   : mGlobal(aGlobal)
   , mEndpoint(aEndpoint)
   , mScope(aScope)
@@ -502,16 +529,22 @@ WorkerPushSubscription::Unsubscribe(Erro
 
   RefPtr<UnsubscribeRunnable> r =
     new UnsubscribeRunnable(proxy, mScope);
   MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(r)));
 
   return p.forget();
 }
 
+void
+WorkerPushSubscription::ToJSON(PushSubscriptionJSON& aJSON)
+{
+  SubscriptionToJSON(aJSON, mEndpoint, mRawP256dhKey, mAuthSecret);
+}
+
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WorkerPushSubscription)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(WorkerPushSubscription)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(WorkerPushSubscription)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WorkerPushSubscription)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
--- a/dom/push/PushManager.h
+++ b/dom/push/PushManager.h
@@ -99,16 +99,19 @@ public:
               ErrorResult& aRv);
 
   void
   SetPrincipal(nsIPrincipal* aPrincipal);
 
   already_AddRefed<Promise>
   Unsubscribe(ErrorResult& aRv);
 
+  void
+  ToJSON(PushSubscriptionJSON& aJSON);
+
 protected:
   ~PushSubscription();
 
 private:
   nsCOMPtr<nsIGlobalObject> mGlobal;
   nsCOMPtr<nsIPrincipal> mPrincipal;
   nsString mEndpoint;
   nsString mScope;
@@ -192,16 +195,19 @@ public:
 
   void
   GetKey(JSContext* cx, PushEncryptionKeyName aType,
          JS::MutableHandle<JSObject*> aP256dhKey);
 
   already_AddRefed<Promise>
   Unsubscribe(ErrorResult& aRv);
 
+  void
+  ToJSON(PushSubscriptionJSON& aJSON);
+
 protected:
   ~WorkerPushSubscription();
 
 private:
   nsString mEndpoint;
   nsString mScope;
   nsTArray<uint8_t> mRawP256dhKey;
   nsTArray<uint8_t> mAuthSecret;
--- a/dom/push/test/test_data.html
+++ b/dom/push/test/test_data.html
@@ -72,16 +72,57 @@ http://creativecommons.org/licenses/publ
       var channel = new MessageChannel();
       channel.port1.onmessage = e => {
         (e.data.error ? reject : resolve)(e.data);
       };
       registration.active.postMessage(request, [channel.port2]);
     });
   }
 
+  function base64UrlDecode(s) {
+    s = s.replace(/-/g, '+').replace(/_/g, '/');
+
+    // Replace padding if it was stripped by the sender.
+    // See http://tools.ietf.org/html/rfc4648#section-4
+    switch (s.length % 4) {
+      case 0:
+        break; // No pad chars in this case
+      case 2:
+        s += '==';
+        break; // Two pad chars
+      case 3:
+        s += '=';
+        break; // One pad char
+      default:
+        throw new Error('Illegal base64url string!');
+    }
+
+    // With correct padding restored, apply the standard base64 decoder
+    var decoded = atob(s);
+
+    var array = new Uint8Array(new ArrayBuffer(decoded.length));
+    for (var i = 0; i < decoded.length; i++) {
+      array[i] = decoded.charCodeAt(i);
+    }
+    return array;
+  }
+
+  add_task(function* compareJSONSubscription() {
+    var json = pushSubscription.toJSON();
+    is(json.endpoint, pushSubscription.endpoint, "Wrong endpoint");
+
+    ["p256dh", "auth"].forEach(keyName => {
+      isDeeply(
+        base64UrlDecode(json.keys[keyName]),
+        new Uint8Array(pushSubscription.getKey(keyName)),
+        "Mismatched Base64-encoded key: " + keyName
+      );
+    });
+  });
+
   add_task(function* comparePublicKey() {
     var data = yield sendRequestToWorker({ type: "publicKey" });
     var p256dhKey = new Uint8Array(pushSubscription.getKey("p256dh"));
     ok(p256dhKey.length > 0, "Missing key share");
     isDeeply(
       p256dhKey,
       new Uint8Array(data.p256dh),
       "Mismatched key share"
--- a/dom/webidl/HeapSnapshot.webidl
+++ b/dom/webidl/HeapSnapshot.webidl
@@ -53,15 +53,26 @@ interface HeapSnapshot {
    *
    * See the `takeCensus` section of the `js/src/doc/Debugger/Debugger.Memory.md`
    * file for detailed documentation.
    */
   [Throws]
   any takeCensus(object? options);
 
   /**
+   * Describe `node` with the specified `breakdown`. See the comment above
+   * `takeCensus` or `js/src/doc/Debugger/Debugger.Memory.md` for detailed
+   * documentation on breakdowns.
+   *
+   * Throws an error when `node` is not the id of a node in the heap snapshot,
+   * or if the breakdown is invalid.
+   */
+  [Throws]
+  any describeNode(object breakdown, NodeId node);
+
+  /**
    * Compute the dominator tree for this heap snapshot.
    *
    * @see DominatorTree.webidl
    */
   [Throws]
   DominatorTree computeDominatorTree();
 };
--- a/dom/webidl/Permissions.webidl
+++ b/dom/webidl/Permissions.webidl
@@ -5,18 +5,18 @@
  *
  * The origin of this IDL file is
  * https://w3c.github.io/permissions/#permissions-interface
  */
 
 enum PermissionName {
   "geolocation",
   "notifications",
-  "push",
-  "midi"
+  "push"
+  // Unsupported: "midi"
 };
 
 dictionary PermissionDescriptor {
   required PermissionName name;
 };
 
 dictionary PushPermissionDescriptor : PermissionDescriptor {
   boolean userVisible = false;
--- a/dom/webidl/PushSubscription.webidl
+++ b/dom/webidl/PushSubscription.webidl
@@ -10,23 +10,37 @@
 interface Principal;
 
 enum PushEncryptionKeyName
 {
   "p256dh",
   "auth"
 };
 
+dictionary PushSubscriptionKeys
+{
+  ByteString p256dh;
+  ByteString auth;
+};
+
+dictionary PushSubscriptionJSON
+{
+  USVString endpoint;
+  PushSubscriptionKeys keys;
+};
+
 [Exposed=(Window,Worker), Func="nsContentUtils::PushEnabled",
  ChromeConstructor(DOMString pushEndpoint, DOMString scope,
                    ArrayBuffer? key, ArrayBuffer? authSecret)]
 interface PushSubscription
 {
     readonly attribute USVString endpoint;
     ArrayBuffer? getKey(PushEncryptionKeyName name);
     [Throws, UseCounter]
     Promise<boolean> unsubscribe();
-    jsonifier;
+
+    // Implements the custom serializer specified in Push API, section 9.
+    PushSubscriptionJSON toJSON();
 
     // Used to set the principal from the JS implemented PushManager.
     [Exposed=Window,ChromeOnly]
     void setPrincipal(Principal principal);
 };
--- a/dom/workers/ServiceWorkerManager.cpp
+++ b/dom/workers/ServiceWorkerManager.cpp
@@ -941,89 +941,103 @@ private:
 
 } // namespace
 
 class ServiceWorkerJobBase : public ServiceWorkerJob
 {
 public:
   ServiceWorkerJobBase(ServiceWorkerJobQueue* aQueue,
                        ServiceWorkerJob::Type aJobType,
-                       ServiceWorkerUpdateFinishCallback* aCallback)
-    : ServiceWorkerJobBase(aQueue, aJobType, aCallback, nullptr, nullptr)
-  { }
-
-  ServiceWorkerJobBase(ServiceWorkerJobQueue* aQueue,
-                       ServiceWorkerJob::Type aJobType,
+                       nsIPrincipal* aPrincipal,
+                       const nsACString& aScope,
+                       const nsACString& aScriptSpec,
                        ServiceWorkerUpdateFinishCallback* aCallback,
-                       ServiceWorkerRegistrationInfo* aRegistration,
                        ServiceWorkerInfo* aServiceWorkerInfo)
     : ServiceWorkerJob(aQueue, aJobType)
+    , mPrincipal(aPrincipal)
+    , mScope(aScope)
+    , mScriptSpec(aScriptSpec)
     , mCallback(aCallback)
+    , mUpdateAndInstallInfo(aServiceWorkerInfo)
     , mCanceled(false)
-    , mRegistration(aRegistration)
-    , mUpdateAndInstallInfo(aServiceWorkerInfo)
   {
     AssertIsOnMainThread();
+    MOZ_ASSERT(aPrincipal);
   }
 
   void
   Cancel()
   {
     mQueue = nullptr;
     mCanceled = true;
   }
 
 protected:
+  nsCOMPtr<nsIPrincipal> mPrincipal;
+  const nsCString mScope;
+  const nsCString mScriptSpec;
   RefPtr<ServiceWorkerUpdateFinishCallback> mCallback;
-  bool mCanceled;
   RefPtr<ServiceWorkerRegistrationInfo> mRegistration;
   RefPtr<ServiceWorkerInfo> mUpdateAndInstallInfo;
+  bool mCanceled;
 
   ~ServiceWorkerJobBase()
   { }
 
+  // Ensure that mRegistration is set for the job.  Also, if mRegistration was
+  // already set, ensure that a new registration object has not replaced it in
+  // the ServiceWorkerManager.  This can happen when jobs race such that the
+  // registration is cleared and recreated while an update job is executing.
+  nsresult
+  EnsureAndVerifyRegistration()
+  {
+    AssertIsOnMainThread();
+
+    RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
+    if (NS_WARN_IF(!swm)) {
+      mRegistration = nullptr;
+      return NS_ERROR_NOT_AVAILABLE;
+    }
+
+    RefPtr<ServiceWorkerRegistrationInfo> registration =
+      swm->GetRegistration(mPrincipal, mScope);
+
+    if (NS_WARN_IF(!registration)) {
+      mRegistration = nullptr;
+      return NS_ERROR_NOT_AVAILABLE;
+    }
+
+    if (NS_WARN_IF(mRegistration && registration != mRegistration)) {
+      mRegistration = nullptr;
+      return NS_ERROR_NOT_AVAILABLE;
+    }
+
+    mRegistration = registration.forget();
+    return NS_OK;
+  }
+
   void
   Succeed()
   {
     AssertIsOnMainThread();
     // We don't have a callback for soft updates.
     if (mCallback) {
       mCallback->UpdateSucceeded(mRegistration);
       mCallback = nullptr;
     }
   }
-};
-
-// Base type for jobs that work with a specific service worker script.
-class ServiceWorkerScriptJobBase : public ServiceWorkerJobBase
-{
-protected:
-  const nsCString mScriptSpec;
-
-  ServiceWorkerScriptJobBase(ServiceWorkerJobQueue* aQueue,
-                             ServiceWorkerJob::Type aJobType,
-                             ServiceWorkerUpdateFinishCallback* aCallback,
-                             ServiceWorkerRegistrationInfo* aRegistration,
-                             ServiceWorkerInfo* aServiceWorkerInfo,
-                             const nsACString& aScriptSpec)
-    : ServiceWorkerJobBase(aQueue, aJobType, aCallback, aRegistration,
-                           aServiceWorkerInfo)
-    , mScriptSpec(aScriptSpec)
-  {
-  }
 
   // This MUST only be called when the job is still performing actions related
   // to registration or update. After the spec resolves the update promise, use
   // Done() with the failure code instead.
   // Callers MUST hold a strong ref before calling this!
   void
   FailWithErrorResult(ErrorResult& aRv)
   {
     AssertIsOnMainThread();
-    MOZ_ASSERT(mRegistration);
 
     // With cancellation support, we may only be running with one reference
     // from another object like a stream loader or something.
     RefPtr<ServiceWorkerJob> kungFuDeathGrip = this;
 
     // Save off the plain error code to pass to Done() where its logged to
     // stderr as a warning.
     nsresult origStatus = static_cast<nsresult>(aRv.ErrorCodeAsInt());
@@ -1031,32 +1045,38 @@ protected:
     // Ensure that we only surface SecurityErr or TypeErr to script.
     if (aRv.Failed() && !aRv.ErrorCodeIs(NS_ERROR_DOM_SECURITY_ERR) &&
                         !aRv.ErrorCodeIs(NS_ERROR_DOM_TYPE_ERR)) {
 
       // Remove the old error code so we can replace it with a TypeError.
       aRv.SuppressException();
 
       NS_ConvertUTF8toUTF16 scriptSpec(mScriptSpec);
-      NS_ConvertUTF8toUTF16 scope(mRegistration->mScope);
+      NS_ConvertUTF8toUTF16 scope(mScope);
 
       // Throw the type error with a generic error message.
       aRv.ThrowTypeError<MSG_SW_INSTALL_ERROR>(scriptSpec, scope);
     }
 
     if (mCallback) {
       mCallback->UpdateFailed(aRv);
       mCallback = nullptr;
     }
     // In case the callback does not consume the exception
     aRv.SuppressException();
 
     mUpdateAndInstallInfo = nullptr;
+
+    if (!mRegistration) {
+      Done(origStatus);
+      return;
+    }
+
     if (mRegistration->mInstallingWorker) {
-      nsresult rv = serviceWorkerScriptCache::PurgeCache(mRegistration->mPrincipal,
+      nsresult rv = serviceWorkerScriptCache::PurgeCache(mPrincipal,
                                                          mRegistration->mInstallingWorker->CacheName());
       if (NS_FAILED(rv)) {
         NS_WARNING("Failed to purge the installing worker cache.");
       }
     }
 
     RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
     swm->MaybeRemoveRegistration(mRegistration);
@@ -1068,50 +1088,71 @@ protected:
   void
   Fail(nsresult aRv)
   {
     ErrorResult rv(aRv);
     FailWithErrorResult(rv);
   }
 };
 
-class ServiceWorkerInstallJob final : public ServiceWorkerScriptJobBase
+class ServiceWorkerInstallJob final : public ServiceWorkerJobBase
 {
   friend class ContinueInstallTask;
 
 public:
+  enum InstallType {
+    UpdateSameScript,
+    OverwriteScript
+  };
+
   ServiceWorkerInstallJob(ServiceWorkerJobQueue* aQueue,
+                          nsIPrincipal* aPrincipal,
+                          const nsACString& aScope,
+                          const nsACString& aScriptSpec,
                           ServiceWorkerUpdateFinishCallback* aCallback,
-                          ServiceWorkerRegistrationInfo* aRegistration,
                           ServiceWorkerInfo* aServiceWorkerInfo,
-                          const nsACString& aScriptSpec)
-    : ServiceWorkerScriptJobBase(aQueue, Type::InstallJob, aCallback,
-                                 aRegistration, aServiceWorkerInfo,
-                                 aScriptSpec)
+                          InstallType aType)
+    : ServiceWorkerJobBase(aQueue, Type::InstallJob, aPrincipal, aScope,
+                           aScriptSpec, aCallback, aServiceWorkerInfo)
+    , mType(aType)
   {
-    MOZ_ASSERT(aRegistration);
   }
 
   void
   Start()
   {
     AssertIsOnMainThread();
     nsCOMPtr<nsIRunnable> r =
       NS_NewRunnableMethod(this, &ServiceWorkerInstallJob::Install);
     MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(r)));
   }
 
   void
   Install()
   {
     RefPtr<ServiceWorkerJob> kungFuDeathGrip = this;
+
     if (mCanceled) {
       return Fail(NS_ERROR_DOM_ABORT_ERR);
     }
-    MOZ_ASSERT(mRegistration);
+
+    nsresult rv = EnsureAndVerifyRegistration();
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return Fail(NS_ERROR_DOM_ABORT_ERR);
+    }
+
+    // If we are trying to install an update for an existing script, then
+    // make sure we don't overwrite a recent script change or resurrect a
+    // dead registration.
+    if (mType == UpdateSameScript) {
+      RefPtr<ServiceWorkerInfo> newest = mRegistration->Newest();
+      if (!newest || !mScriptSpec.Equals(newest->ScriptSpec())) {
+        return Fail(NS_ERROR_DOM_ABORT_ERR);
+      }
+    }
 
     // Begin [[Install]] atomic step 3.
     if (mRegistration->mInstallingWorker) {
       mRegistration->mInstallingWorker->UpdateState(ServiceWorkerState::Redundant);
       mRegistration->mInstallingWorker->WorkerPrivate()->TerminateWorker();
     }
 
     RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
@@ -1143,31 +1184,36 @@ public:
     nsMainThreadPtrHandle<ContinueLifecycleTask> installTask(
       new nsMainThreadPtrHolder<ContinueLifecycleTask>(new ContinueInstallTask(this)));
     RefPtr<LifeCycleEventCallback> callback = new ContinueLifecycleRunnable(installTask);
 
     // This triggers Step 4.7 "Queue a task to run the following substeps..."
     // which sends the install event to the worker.
     ServiceWorkerPrivate* workerPrivate =
       mRegistration->mInstallingWorker->WorkerPrivate();
-    nsresult rv = workerPrivate->SendLifeCycleEvent(NS_LITERAL_STRING("install"),
-                                                    callback, failRunnable);
+    rv = workerPrivate->SendLifeCycleEvent(NS_LITERAL_STRING("install"),
+                                           callback, failRunnable);
 
     if (NS_WARN_IF(NS_FAILED(rv))) {
       ContinueAfterInstallEvent(false /* aSuccess */);
     }
   }
 
   void
   ContinueAfterInstallEvent(bool aInstallEventSuccess)
   {
     if (mCanceled) {
       return Done(NS_ERROR_DOM_ABORT_ERR);
     }
 
+    nsresult rv = EnsureAndVerifyRegistration();
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return Fail(NS_ERROR_DOM_ABORT_ERR);
+    }
+
     if (!mRegistration->mInstallingWorker) {
       NS_WARNING("mInstallingWorker was null.");
       return Done(NS_ERROR_DOM_ABORT_ERR);
     }
 
     RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
 
     // "If installFailed is true"
@@ -1191,70 +1237,71 @@ public:
       if (NS_FAILED(rv)) {
         NS_WARNING("Failed to purge the old waiting cache.");
       }
     }
 
     mRegistration->mWaitingWorker = mRegistration->mInstallingWorker.forget();
     mRegistration->mWaitingWorker->UpdateState(ServiceWorkerState::Installed);
     mRegistration->NotifyListenersOnChange();
+    swm->StoreRegistration(mPrincipal, mRegistration);
     swm->InvalidateServiceWorkerRegistrationWorker(mRegistration,
                                                    WhichServiceWorker::INSTALLING_WORKER | WhichServiceWorker::WAITING_WORKER);
 
     // "If registration's waiting worker's skip waiting flag is set"
     if (mRegistration->mWaitingWorker->SkipWaitingFlag()) {
       mRegistration->PurgeActiveWorker();
     }
 
     Done(NS_OK);
     // Activate() is invoked out of band of atomic.
     mRegistration->TryToActivate();
   }
+
+private:
+  const InstallType mType;
 };
 
-class ServiceWorkerRegisterJob final : public ServiceWorkerScriptJobBase,
+class ServiceWorkerRegisterJob final : public ServiceWorkerJobBase,
                                        public serviceWorkerScriptCache::CompareCallback
 {
   friend class ContinueUpdateRunnable;
 
-  nsCString mScope;
-  nsCOMPtr<nsIPrincipal> mPrincipal;
   nsCOMPtr<nsILoadGroup> mLoadGroup;
 
   ~ServiceWorkerRegisterJob()
   { }
 
 public:
   NS_DECL_ISUPPORTS_INHERITED
 
   // [[Register]]
   ServiceWorkerRegisterJob(ServiceWorkerJobQueue* aQueue,
-                           const nsCString& aScope,
-                           const nsCString& aScriptSpec,
+                           nsIPrincipal* aPrincipal,
+                           const nsACString& aScope,
+                           const nsACString& aScriptSpec,
                            ServiceWorkerUpdateFinishCallback* aCallback,
-                           nsIPrincipal* aPrincipal,
                            nsILoadGroup* aLoadGroup)
-    : ServiceWorkerScriptJobBase(aQueue, Type::RegisterJob, aCallback, nullptr,
-                                 nullptr, aScriptSpec)
-    , mScope(aScope)
-    , mPrincipal(aPrincipal)
+    : ServiceWorkerJobBase(aQueue, Type::RegisterJob, aPrincipal, aScope,
+                           aScriptSpec, aCallback, nullptr)
     , mLoadGroup(aLoadGroup)
   {
     AssertIsOnMainThread();
     MOZ_ASSERT(mLoadGroup);
     MOZ_ASSERT(aCallback);
   }
 
   // [[Update]]
   ServiceWorkerRegisterJob(ServiceWorkerJobQueue* aQueue,
-                           ServiceWorkerRegistrationInfo* aRegistration,
-                           ServiceWorkerUpdateFinishCallback* aCallback,
-                           const nsACString& aScriptSpec)
-    : ServiceWorkerScriptJobBase(aQueue, Type::UpdateJob, aCallback,
-                                 aRegistration, nullptr, aScriptSpec)
+                           nsIPrincipal* aPrincipal,
+                           const nsACString& aScope,
+                           const nsACString& aScriptSpec,
+                           ServiceWorkerUpdateFinishCallback* aCallback)
+    : ServiceWorkerJobBase(aQueue, Type::UpdateJob, aPrincipal, aScope,
+                           aScriptSpec, aCallback, nullptr)
   {
     AssertIsOnMainThread();
   }
 
   void
   Start() override
   {
     AssertIsOnMainThread();
@@ -1264,47 +1311,54 @@ public:
     if (!swm->HasBackgroundActor()) {
       nsCOMPtr<nsIRunnable> runnable =
         NS_NewRunnableMethod(this, &ServiceWorkerRegisterJob::Start);
       swm->AppendPendingOperation(runnable);
       return;
     }
 
     if (mJobType == RegisterJob) {
+      MOZ_ASSERT(!mRegistration);
       mRegistration = swm->GetRegistration(mPrincipal, mScope);
 
       if (mRegistration) {
         mRegistration->mPendingUninstall = false;
         RefPtr<ServiceWorkerInfo> newest = mRegistration->Newest();
         if (newest && mScriptSpec.Equals(newest->ScriptSpec())) {
-          swm->StoreRegistration(mPrincipal, mRegistration);
           Succeed();
 
           // Done() must always be called async from Start()
           nsCOMPtr<nsIRunnable> runnable =
             NS_NewRunnableMethodWithArg<nsresult>(
               this,
               &ServiceWorkerRegisterJob::Done,
               NS_OK);
           MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToCurrentThread(runnable)));
 
           return;
         }
       } else {
         mRegistration = swm->CreateNewRegistration(mScope, mPrincipal);
       }
-
-      swm->StoreRegistration(mPrincipal, mRegistration);
     } else {
       MOZ_ASSERT(mJobType == UpdateJob);
 
+      nsresult rv = EnsureAndVerifyRegistration();
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        // Do nothing here, but since mRegistration is nullptr we will
+        // trigger the async Fail() call below.
+        MOZ_ASSERT(!mRegistration);
+      }
+
       // If a different script spec has been registered between when this update
       // was scheduled and it running now, then simply abort.
-      RefPtr<ServiceWorkerInfo> newest = mRegistration->Newest();
-      if (newest && !mScriptSpec.Equals(newest->ScriptSpec())) {
+      RefPtr<ServiceWorkerInfo> newest = mRegistration ? mRegistration->Newest()
+                                                       : nullptr;
+      if (!mRegistration ||
+          (newest && !mScriptSpec.Equals(newest->ScriptSpec()))) {
 
         // Done() must always be called async from Start()
         nsCOMPtr<nsIRunnable> runnable =
           NS_NewRunnableMethodWithArg<nsresult>(
             this,
             &ServiceWorkerRegisterJob::Fail,
             NS_ERROR_DOM_ABORT_ERR);
           MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToCurrentThread(runnable)));
@@ -1317,39 +1371,45 @@ public:
   }
 
   void
   ComparisonResult(nsresult aStatus, bool aInCacheAndEqual,
                    const nsAString& aNewCacheName,
                    const nsACString& aMaxScope) override
   {
     RefPtr<ServiceWorkerRegisterJob> kungFuDeathGrip = this;
+
     if (NS_WARN_IF(mCanceled)) {
       Fail(NS_ERROR_DOM_ABORT_ERR);
       return;
     }
 
     if (NS_WARN_IF(NS_FAILED(aStatus))) {
       Fail(aStatus);
       return;
     }
 
+    nsresult rv = EnsureAndVerifyRegistration();
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return Fail(NS_ERROR_DOM_ABORT_ERR);
+    }
+
     if (aInCacheAndEqual) {
       Succeed();
       Done(NS_OK);
       return;
     }
 
     AssertIsOnMainThread();
     Telemetry::Accumulate(Telemetry::SERVICE_WORKER_UPDATED, 1);
 
     RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
 
     nsCOMPtr<nsIURI> scriptURI;
-    nsresult rv = NS_NewURI(getter_AddRefs(scriptURI), mScriptSpec);
+    rv = NS_NewURI(getter_AddRefs(scriptURI), mScriptSpec);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       Fail(NS_ERROR_DOM_SECURITY_ERR);
       return;
     }
     nsCOMPtr<nsIURI> maxScopeURI;
     if (!aMaxScope.IsEmpty()) {
       rv = NS_NewURI(getter_AddRefs(maxScopeURI), aMaxScope,
                      nullptr, scriptURI);
@@ -1412,36 +1472,54 @@ public:
 
 private:
   // This will perform steps 27 and 28 from [[Update]]
   // Remove the job from the registration queue and invoke [[Install]]
   void
   ContinueInstall(bool aScriptEvaluationResult)
   {
     AssertIsOnMainThread();
-    MOZ_ASSERT(mRegistration);
+
+    nsresult rv = EnsureAndVerifyRegistration();
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return Fail(NS_ERROR_DOM_ABORT_ERR);
+    }
+
     mRegistration->mUpdating = false;
 
     RefPtr<ServiceWorkerRegisterJob> kungFuDeathGrip = this;
     if (mCanceled) {
       return Fail(NS_ERROR_DOM_ABORT_ERR);
     }
 
     if (NS_WARN_IF(!aScriptEvaluationResult)) {
       ErrorResult error;
 
       NS_ConvertUTF8toUTF16 scriptSpec(mScriptSpec);
       NS_ConvertUTF8toUTF16 scope(mRegistration->mScope);
       error.ThrowTypeError<MSG_SW_SCRIPT_THREW>(scriptSpec, scope);
       return FailWithErrorResult(error);
     }
 
+    // For updates we want to make sure our install job does not end up
+    // changing the script for the registration.  Since a registration
+    // script change can be queued in an install job, we can not
+    // conclusively verify that the update install should proceed here.
+    // Instead, we have to pass a flag into our install job indicating
+    // if a script change is allowed or not.  This can then be used to
+    // check the current script after all previous install jobs have been
+    // flushed.
+    ServiceWorkerInstallJob::InstallType installType =
+      mJobType == UpdateJob ? ServiceWorkerInstallJob::UpdateSameScript
+                            : ServiceWorkerInstallJob::OverwriteScript;
+
     RefPtr<ServiceWorkerInstallJob> job =
-      new ServiceWorkerInstallJob(mQueue, mCallback, mRegistration,
-                                  mUpdateAndInstallInfo, mScriptSpec);
+      new ServiceWorkerInstallJob(mQueue, mPrincipal, mScope, mScriptSpec,
+                                  mCallback, mUpdateAndInstallInfo,
+                                  installType);
     mQueue->Append(job);
     Done(NS_OK);
   }
 
   void
   Update()
   {
     AssertIsOnMainThread();
@@ -1458,40 +1536,45 @@ private:
 
   // Aspects of (actually the whole algorithm) of [[Update]] after
   // "Run the following steps in parallel."
   void
   ContinueUpdate()
   {
     AssertIsOnMainThread();
     RefPtr<ServiceWorkerRegisterJob> kungFuDeathGrip = this;
+
     if (mCanceled) {
       return Fail(NS_ERROR_DOM_ABORT_ERR);
     }
 
+    nsresult rv = EnsureAndVerifyRegistration();
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return Fail(NS_ERROR_DOM_ABORT_ERR);
+    }
+
     if (mRegistration->mInstallingWorker) {
       mRegistration->mInstallingWorker->UpdateState(ServiceWorkerState::Redundant);
       mRegistration->mInstallingWorker->WorkerPrivate()->TerminateWorker();
       mRegistration->mInstallingWorker = nullptr;
     }
 
     RefPtr<ServiceWorkerInfo> workerInfo = mRegistration->Newest();
     nsAutoString cacheName;
 
     // 9.2.20 If newestWorker is not null, and newestWorker's script url is
     // equal to registration's registering script url and response is a
     // byte-for-byte match with the script resource of newestWorker...
     if (workerInfo && workerInfo->ScriptSpec().Equals(mScriptSpec)) {
       cacheName = workerInfo->CacheName();
     }
 
-    nsresult rv =
-      serviceWorkerScriptCache::Compare(mRegistration, mRegistration->mPrincipal, cacheName,
-                                        NS_ConvertUTF8toUTF16(mScriptSpec), this,
-                                        mLoadGroup);
+    rv = serviceWorkerScriptCache::Compare(mRegistration, mPrincipal, cacheName,
+                                           NS_ConvertUTF8toUTF16(mScriptSpec),
+                                           this, mLoadGroup);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return Fail(rv);
     }
   }
 
   void
   Done(nsresult aStatus)
   {
@@ -1730,17 +1813,18 @@ ServiceWorkerManager::Register(nsIDOMWin
   // Create a load group that is separate from, yet related to, the document's load group.
   // This allows checks for interfaces like nsILoadContext to yield the values used by the
   // the document, yet will not cancel the update job if the document's load group is cancelled.
   nsCOMPtr<nsILoadGroup> loadGroup = do_CreateInstance(NS_LOADGROUP_CONTRACTID);
   rv = loadGroup->SetNotificationCallbacks(ir);
   MOZ_ALWAYS_TRUE(NS_SUCCEEDED(rv));
 
   RefPtr<ServiceWorkerRegisterJob> job =
-    new ServiceWorkerRegisterJob(queue, cleanedScope, spec, cb, documentPrincipal, loadGroup);
+    new ServiceWorkerRegisterJob(queue, documentPrincipal, cleanedScope, spec,
+                                 cb, loadGroup);
   queue->Append(job);
 
   AssertIsOnMainThread();
   Telemetry::Accumulate(Telemetry::SERVICE_WORKER_REGISTRATIONS, 1);
 
   promise.forget(aPromise);
   return NS_OK;
 }
@@ -3707,20 +3791,33 @@ ServiceWorkerManager::NotifyServiceWorke
 
     if (utf8Scope.Equals(aRegistration->mScope)) {
       target->RegistrationRemoved();
     }
   }
 }
 
 void
-ServiceWorkerManager::SoftUpdate(const OriginAttributes& aOriginAttributes,
+ServiceWorkerManager::SoftUpdate(const PrincipalOriginAttributes& aOriginAttributes,
                                  const nsACString& aScope)
 {
   AssertIsOnMainThread();
+
+  nsCOMPtr<nsIURI> scopeURI;
+  nsresult rv = NS_NewURI(getter_AddRefs(scopeURI), aScope);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return;
+  }
+
+  nsCOMPtr<nsIPrincipal> principal =
+    BasePrincipal::CreateCodebasePrincipal(scopeURI, aOriginAttributes);
+  if (NS_WARN_IF(!principal)) {
+    return;
+  }
+
   nsAutoCString scopeKey;
   aOriginAttributes.CreateSuffix(scopeKey);
 
   RefPtr<ServiceWorkerRegistrationInfo> registration =
     GetRegistration(scopeKey, aScope);
   if (NS_WARN_IF(!registration)) {
     return;
   }
@@ -3747,18 +3844,18 @@ ServiceWorkerManager::SoftUpdate(const O
   // or its equivalent, with client, registration as its argument."
   // TODO(catalinb): We don't implement the force bypass cache flag.
   // See: https://github.com/slightlyoff/ServiceWorker/issues/759
   if (!registration->mUpdating) {
     ServiceWorkerJobQueue* queue = GetOrCreateJobQueue(scopeKey, aScope);
     MOZ_ASSERT(queue);
 
     RefPtr<ServiceWorkerRegisterJob> job =
-      new ServiceWorkerRegisterJob(queue, registration, nullptr,
-                                   newest->ScriptSpec());
+      new ServiceWorkerRegisterJob(queue, principal, registration->mScope,
+                                   newest->ScriptSpec(), nullptr);
     queue->Append(job);
   }
 }
 
 void
 ServiceWorkerManager::Update(nsIPrincipal* aPrincipal,
                              const nsACString& aScope,
                              ServiceWorkerUpdateFinishCallback* aCallback)
@@ -3799,18 +3896,18 @@ ServiceWorkerManager::Update(nsIPrincipa
 
   ServiceWorkerJobQueue* queue =
     GetOrCreateJobQueue(scopeKey, aScope);
   MOZ_ASSERT(queue);
 
   // "Invoke Update algorithm, or its equivalent, with client, registration as
   // its argument."
   RefPtr<ServiceWorkerRegisterJob> job =
-    new ServiceWorkerRegisterJob(queue, registration, aCallback,
-                                 newest->ScriptSpec());
+    new ServiceWorkerRegisterJob(queue, aPrincipal, registration->mScope,
+                                 newest->ScriptSpec(), aCallback);
   queue->Append(job);
 }
 
 namespace {
 
 static void
 FireControllerChangeOnDocument(nsIDocument* aDocument)
 {
--- a/dom/workers/ServiceWorkerManager.h
+++ b/dom/workers/ServiceWorkerManager.h
@@ -388,17 +388,17 @@ public:
                              ErrorResult& aRv);
 
   void
   Update(nsIPrincipal* aPrincipal,
          const nsACString& aScope,
          ServiceWorkerUpdateFinishCallback* aCallback);
 
   void
-  SoftUpdate(const OriginAttributes& aOriginAttributes,
+  SoftUpdate(const PrincipalOriginAttributes& aOriginAttributes,
              const nsACString& aScope);
 
   void
   PropagateSoftUpdate(const PrincipalOriginAttributes& aOriginAttributes,
                       const nsAString& aScope);
 
   void
   PropagateRemove(const nsACString& aHost);
--- a/gfx/2d/DrawTargetSkia.cpp
+++ b/gfx/2d/DrawTargetSkia.cpp
@@ -7,21 +7,17 @@
 #include "SourceSurfaceCairo.h"
 #include "SourceSurfaceSkia.h"
 #include "ScaledFontBase.h"
 #include "ScaledFontCairo.h"
 #include "skia/include/core/SkBitmapDevice.h"
 #include "FilterNodeSoftware.h"
 #include "HelpersSkia.h"
 
-#ifdef USE_SKIA_GPU
-#include "skia/include/gpu/SkGpuDevice.h"
-#include "skia/include/gpu/gl/GrGLInterface.h"
-#endif
-
+#include "skia/include/core/SkSurface.h"
 #include "skia/include/core/SkTypeface.h"
 #include "skia/include/effects/SkGradientShader.h"
 #include "skia/include/core/SkColorFilter.h"
 #include "skia/include/effects/SkBlurImageFilter.h"
 #include "skia/include/effects/SkLayerRasterizer.h"
 #include "Logging.h"
 #include "Tools.h"
 #include "DataSurfaceHelpers.h"
@@ -144,39 +140,42 @@ DrawTargetSkia::Snapshot()
 
   return snapshot.forget();
 }
 
 bool
 DrawTargetSkia::LockBits(uint8_t** aData, IntSize* aSize,
                           int32_t* aStride, SurfaceFormat* aFormat)
 {
-  const SkBitmap &bitmap = mCanvas->getDevice()->accessBitmap(false);
-  if (!bitmap.lockPixelsAreWritable()) {
+  /* Test if the canvas' device has accessible pixels first, as actually
+   * accessing the pixels may trigger side-effects, even if it fails.
+   */
+  if (!mCanvas->peekPixels(nullptr, nullptr)) {
+    return false;
+  }
+
+  SkImageInfo info;
+  size_t rowBytes;
+  void* pixels = mCanvas->accessTopLayerPixels(&info, &rowBytes);
+  if (!pixels) {
     return false;
   }
 
   MarkChanged();
 
-  bitmap.lockPixels();
-  *aData = reinterpret_cast<uint8_t*>(bitmap.getPixels());
-  *aSize = IntSize(bitmap.width(), bitmap.height());
-  *aStride = int32_t(bitmap.rowBytes());
-  *aFormat = SkiaColorTypeToGfxFormat(bitmap.colorType());
+  *aData = reinterpret_cast<uint8_t*>(pixels);
+  *aSize = IntSize(info.width(), info.height());
+  *aStride = int32_t(rowBytes);
+  *aFormat = SkiaColorTypeToGfxFormat(info.colorType());
   return true;
 }
 
 void
 DrawTargetSkia::ReleaseBits(uint8_t* aData)
 {
-  const SkBitmap &bitmap = mCanvas->getDevice()->accessBitmap(false);
-  MOZ_ASSERT(bitmap.lockPixelsAreWritable());
-
-  bitmap.unlockPixels();
-  bitmap.notifyPixelsChanged();
 }
 
 static void
 SetPaintPattern(SkPaint& aPaint, const Pattern& aPattern, TempBitmap& aTmpBitmap,
                 Float aAlpha = 1.0)
 {
   switch (aPattern.GetType()) {
     case PatternType::COLOR: {
@@ -261,17 +260,17 @@ SetPaintPattern(SkPaint& aPaint, const P
       SkShader::TileMode xTileMode = ExtendModeToTileMode(pat.mExtendMode, Axis::X_AXIS);
       SkShader::TileMode yTileMode = ExtendModeToTileMode(pat.mExtendMode, Axis::Y_AXIS);
 
       SkShader* shader = SkShader::CreateBitmapShader(bitmap, xTileMode, yTileMode);
       SkShader* matrixShader = SkShader::CreateLocalMatrixShader(shader, mat);
       SkSafeUnref(shader);
       SkSafeUnref(aPaint.setShader(matrixShader));
       if (pat.mFilter == Filter::POINT) {
-        aPaint.setFilterLevel(SkPaint::kNone_FilterLevel);
+        aPaint.setFilterQuality(kNone_SkFilterQuality);
       }
       break;
     }
   }
 }
 
 static inline Rect
 GetClipBounds(SkCanvas *aCanvas)
@@ -328,17 +327,17 @@ struct AutoPaintSetup {
       temp.setAlpha(ColorFloatToByte(aOptions.mAlpha));
       //TODO: Get a rect here
       mCanvas->saveLayer(nullptr, &temp);
       mNeedsRestore = true;
     } else {
       mPaint.setAlpha(ColorFloatToByte(aOptions.mAlpha));
       mAlpha = aOptions.mAlpha;
     }
-    mPaint.setFilterLevel(SkPaint::kLow_FilterLevel);
+    mPaint.setFilterQuality(kLow_SkFilterQuality);
   }
 
   // TODO: Maybe add an operator overload to access this easier?
   SkPaint mPaint;
   TempBitmap mTmpBitmap;
   bool mNeedsRestore;
   SkCanvas* mCanvas;
   Float mAlpha;
@@ -376,20 +375,20 @@ DrawTargetSkia::DrawSurface(SourceSurfac
 
   SkRect destRect = RectToSkRect(aDest);
   SkRect sourceRect = RectToSkRect(aSource);
 
   TempBitmap bitmap = GetBitmapForSurface(aSurface);
 
   AutoPaintSetup paint(mCanvas.get(), aOptions, &aDest);
   if (aSurfOptions.mFilter == Filter::POINT) {
-    paint.mPaint.setFilterLevel(SkPaint::kNone_FilterLevel);
+    paint.mPaint.setFilterQuality(kNone_SkFilterQuality);
   }
 
-  mCanvas->drawBitmapRectToRect(bitmap.mBitmap, &sourceRect, destRect, &paint.mPaint);
+  mCanvas->drawBitmapRect(bitmap.mBitmap, sourceRect, destRect, &paint.mPaint);
 }
 
 DrawTargetType
 DrawTargetSkia::GetType() const
 {
 #ifdef USE_SKIA_GPU
   if (mGrContext) {
     return DrawTargetType::HARDWARE_RASTER;
@@ -792,19 +791,17 @@ DrawTargetSkia::CopySurface(SourceSurfac
 
   TempBitmap bitmap = GetBitmapForSurface(aSurface);
 
   // This is a fast path that is disabled for now to mimimize risk
   if (false && !bitmap.mBitmap.getTexture() && mCanvas->imageInfo() == bitmap.mBitmap.info()) {
     SkBitmap bm(bitmap.mBitmap);
     bm.lockPixels();
     if (bm.getPixels()) {
-      SkImageInfo info = bm.info();
-      info.fWidth = aSourceRect.width;
-      info.fHeight = aSourceRect.height;
+      SkImageInfo info = bm.info().makeWH(aSourceRect.width, aSourceRect.height);
       uint8_t* pixels = static_cast<uint8_t*>(bm.getPixels());
       // adjust pixels for the source offset
       pixels += aSourceRect.x + aSourceRect.y*bm.rowBytes();
       mCanvas->writePixels(info, pixels, bm.rowBytes(), aDestination.x, aDestination.y);
       return;
     }
   }
 
@@ -826,17 +823,17 @@ DrawTargetSkia::CopySurface(SourceSurfac
   // drawBitmapRect with A8 bitmaps ends up doing a mask operation
   // so we need to clear before
   if (bitmap.mBitmap.colorType() == kAlpha_8_SkColorType) {
     SkPaint clearPaint;
     clearPaint.setColor(SkColorSetARGB(0, 0, 0, 0));
     clearPaint.setXfermodeMode(SkXfermode::kSrc_Mode);
     mCanvas->drawPaint(clearPaint);
   }
-  mCanvas->drawBitmapRect(bitmap.mBitmap, &source, dest, &paint);
+  mCanvas->drawBitmapRect(bitmap.mBitmap, source, dest, &paint);
   mCanvas->restore();
 }
 
 bool
 DrawTargetSkia::Init(const IntSize &aSize, SurfaceFormat aFormat)
 {
   if (size_t(std::max(aSize.width, aSize.height)) > GetMaxSurfaceSize()) {
     return false;
@@ -849,17 +846,17 @@ DrawTargetSkia::Init(const IntSize &aSiz
         aSize.width, aSize.height,
         GfxFormatToSkiaColorType(aFormat),
         alphaType);
   // we need to have surfaces that have a stride aligned to 4 for interop with cairo
   int stride = (BytesPerPixel(aFormat)*aSize.width + (4-1)) & -4;
 
   SkBitmap bitmap;
   bitmap.setInfo(skiInfo, stride);
-  if (!bitmap.allocPixels()) {
+  if (!bitmap.tryAllocPixels()) {
     return false;
   }
 
   bitmap.eraseARGB(0, 0, 0, 0);
 
   mCanvas.adopt(new SkCanvas(bitmap));
   mSize = aSize;
 
@@ -878,34 +875,38 @@ DrawTargetSkia::InitWithGrContext(GrCont
   if (size_t(std::max(aSize.width, aSize.height)) > GetMaxSurfaceSize()) {
     return false;
   }
 
   mGrContext = aGrContext;
   mSize = aSize;
   mFormat = aFormat;
 
-  GrTextureDesc targetDescriptor;
+  GrSurfaceDesc targetDescriptor;
 
-  targetDescriptor.fFlags = kRenderTarget_GrTextureFlagBit;
+  targetDescriptor.fFlags = kRenderTarget_GrSurfaceFlag;
   targetDescriptor.fWidth = mSize.width;
   targetDescriptor.fHeight = mSize.height;
   targetDescriptor.fConfig = GfxFormatToGrConfig(mFormat);
   targetDescriptor.fOrigin = kBottomLeft_GrSurfaceOrigin;
   targetDescriptor.fSampleCnt = 0;
 
-  SkAutoTUnref<GrTexture> skiaTexture(mGrContext->createUncachedTexture(targetDescriptor, NULL, 0));
+  SkAutoTUnref<GrTexture> skiaTexture(mGrContext->textureProvider()->createTexture(targetDescriptor, SkSurface::kNo_Budgeted, nullptr, 0));
   if (!skiaTexture) {
     return false;
   }
 
-  mTexture = (uint32_t)skiaTexture->getTextureHandle();
+  SkAutoTUnref<SkSurface> gpuSurface(SkSurface::NewRenderTargetDirect(skiaTexture->asRenderTarget()));
+  if (!gpuSurface) {
+    return false;
+  }
 
-  SkAutoTUnref<SkBaseDevice> device(new SkGpuDevice(mGrContext.get(), skiaTexture->asRenderTarget()));
-  mCanvas.adopt(new SkCanvas(device.get()));
+  mTexture = reinterpret_cast<GrGLTextureInfo *>(skiaTexture->getTextureHandle())->fID;
+
+  mCanvas = gpuSurface->getCanvas();
 
   return true;
 }
 
 #endif
 
 void
 DrawTargetSkia::Init(unsigned char* aData, const IntSize &aSize, int32_t aStride, SurfaceFormat aFormat)
--- a/gfx/2d/DrawTargetSkia.h
+++ b/gfx/2d/DrawTargetSkia.h
@@ -137,17 +137,17 @@ private:
   bool ShouldLCDRenderText(FontType aFontType, AntialiasMode aAntialiasMode);
 
   SkRect SkRectCoveringWholeSurface() const;
 
   bool UsingSkiaGPU() const;
 
 #ifdef USE_SKIA_GPU
   RefPtrSkia<GrContext> mGrContext;
-  uint32_t mTexture;
+  GrGLuint mTexture;
 #endif
 
   IntSize mSize;
   RefPtrSkia<SkCanvas> mCanvas;
   SourceSurfaceSkia* mSnapshot;
 };
 
 } // namespace gfx
--- a/gfx/2d/ScaledFontCairo.cpp
+++ b/gfx/2d/ScaledFontCairo.cpp
@@ -36,30 +36,30 @@ ScaledFontCairo::ScaledFontCairo(cairo_s
   SetCairoScaledFont(aScaledFont);
 }
 
 #if defined(USE_SKIA) && defined(MOZ_ENABLE_FREETYPE)
 SkTypeface* ScaledFontCairo::GetSkTypeface()
 {
   if (!mTypeface) {
     cairo_font_face_t* fontFace = cairo_scaled_font_get_font_face(mScaledFont);
+    MOZ_ASSERT(cairo_font_face_status(fontFace) == CAIRO_STATUS_SUCCESS);
+
     FT_Face face = cairo_ft_scaled_font_lock_face(mScaledFont);
 
-    int style = SkTypeface::kNormal;
-
-    if (face->style_flags & FT_STYLE_FLAG_ITALIC)
-    style |= SkTypeface::kItalic;
-
-    if (face->style_flags & FT_STYLE_FLAG_BOLD)
-      style |= SkTypeface::kBold;
+    SkFontStyle style(face->style_flags & FT_STYLE_FLAG_BOLD ?
+                        SkFontStyle::kBold_Weight : SkFontStyle::kNormal_Weight,
+                      SkFontStyle::kNormal_Width,
+                      face->style_flags & FT_STYLE_FLAG_ITALIC ?
+                        SkFontStyle::kItalic_Slant : SkFontStyle::kUpright_Slant);
 
     bool isFixedWidth = face->face_flags & FT_FACE_FLAG_FIXED_WIDTH;
     cairo_ft_scaled_font_unlock_face(mScaledFont);
 
-    mTypeface = SkCreateTypefaceFromCairoFont(fontFace, (SkTypeface::Style)style, isFixedWidth);
+    mTypeface = SkCreateTypefaceFromCairoFont(fontFace, style, isFixedWidth);
   }
 
   return mTypeface;
 }
 #endif
 
 } // namespace gfx
 } // namespace mozilla
--- a/gfx/2d/SourceSurfaceSkia.cpp
+++ b/gfx/2d/SourceSurfaceSkia.cpp
@@ -8,16 +8,17 @@
 #include "SourceSurfaceSkia.h"
 #include "skia/include/core/SkBitmap.h"
 #include "skia/include/core/SkDevice.h"
 #include "HelpersSkia.h"
 #include "DrawTargetSkia.h"
 #include "DataSurfaceHelpers.h"
 
 #ifdef USE_SKIA_GPU
+#include "GLDefs.h"
 #include "skia/include/gpu/SkGrPixelRef.h"
 #endif
 
 namespace mozilla {
 namespace gfx {
 
 SourceSurfaceSkia::SourceSurfaceSkia()
   : mDrawTarget(nullptr), mLocked(false)
@@ -45,23 +46,21 @@ SourceSurfaceSkia::GetFormat() const
   return mFormat;
 }
 
 bool
 SourceSurfaceSkia::InitFromCanvas(SkCanvas* aCanvas,
                                   SurfaceFormat aFormat,
                                   DrawTargetSkia* aOwner)
 {
-  SkISize size = aCanvas->getDeviceSize();
-
-  mBitmap = (SkBitmap)aCanvas->getDevice()->accessBitmap(false);
+  mBitmap = aCanvas->getDevice()->accessBitmap(false);
 
   mFormat = aFormat;
 
-  mSize = IntSize(size.fWidth, size.fHeight);
+  mSize = IntSize(mBitmap.width(), mBitmap.height());
   mStride = mBitmap.rowBytes();
   mDrawTarget = aOwner;
 
   return true;
 }
 
 bool 
 SourceSurfaceSkia::InitFromData(unsigned char* aData,
@@ -79,20 +78,16 @@ SourceSurfaceSkia::InitFromData(unsigned
                                        alphaType);
   temp.setInfo(info, aStride);
   temp.setPixels(aData);
 
   if (!temp.copyTo(&mBitmap, GfxFormatToSkiaColorType(aFormat))) {
     return false;
   }
 
-  if (aFormat == SurfaceFormat::B8G8R8X8) {
-    mBitmap.setAlphaType(kIgnore_SkAlphaType);
-  }
-
   mSize = aSize;
   mFormat = aFormat;
   mStride = mBitmap.rowBytes();
   return true;
 }
 
 bool
 SourceSurfaceSkia::InitFromTexture(DrawTargetSkia* aOwner,
@@ -104,21 +99,25 @@ SourceSurfaceSkia::InitFromTexture(DrawT
 #ifdef USE_SKIA_GPU
   GrBackendTextureDesc skiaTexGlue;
   mSize.width = skiaTexGlue.fWidth = aSize.width;
   mSize.height = skiaTexGlue.fHeight = aSize.height;
   skiaTexGlue.fFlags = kNone_GrBackendTextureFlag;
   skiaTexGlue.fOrigin = kTopLeft_GrSurfaceOrigin;
   skiaTexGlue.fConfig = GfxFormatToGrConfig(aFormat);
   skiaTexGlue.fSampleCnt = 0;
-  skiaTexGlue.fTextureHandle = aTexture;
 
-  GrTexture *skiaTexture = aOwner->mGrContext->wrapBackendTexture(skiaTexGlue);
+  GrGLTextureInfo texInfo;
+  texInfo.fTarget = LOCAL_GL_TEXTURE_2D;
+  texInfo.fID = aTexture;
+  skiaTexGlue.fTextureHandle = reinterpret_cast<GrBackendObject>(&texInfo);
+
+  GrTexture *skiaTexture = aOwner->mGrContext->textureProvider()->wrapBackendTexture(skiaTexGlue);
   SkImageInfo imgInfo = SkImageInfo::Make(aSize.width, aSize.height, GfxFormatToSkiaColorType(aFormat), kOpaque_SkAlphaType);
-  SkGrPixelRef *texRef = new SkGrPixelRef(imgInfo, skiaTexture, false);
+  SkGrPixelRef *texRef = new SkGrPixelRef(imgInfo, skiaTexture);
   mBitmap.setInfo(imgInfo);
   mBitmap.setPixelRef(texRef);
   mFormat = aFormat;
   mStride = mBitmap.rowBytes();
 #endif
 
   mDrawTarget = aOwner;
   return true;
--- a/gfx/gl/SkiaGLGlue.cpp
+++ b/gfx/gl/SkiaGLGlue.cpp
@@ -84,16 +84,21 @@ GrGLvoid glBindTexture_mozilla(GrGLenum 
     return sGLContext.get()->fBindTexture(target, texture);
 }
 
 GrGLvoid glBlendColor_mozilla(GrGLclampf red, GrGLclampf green, GrGLclampf blue, GrGLclampf alpha)
 {
     return sGLContext.get()->fBlendColor(red, green, blue, alpha);
 }
 
+GrGLvoid glBlendEquation_mozilla(GrGLenum mode)
+{
+    return sGLContext.get()->fBlendEquation(mode);
+}
+
 GrGLvoid glBlendFunc_mozilla(GrGLenum sfactor, GrGLenum dfactor)
 {
     return sGLContext.get()->fBlendFunc(sfactor, dfactor);
 }
 
 GrGLvoid glBufferData_mozilla(GrGLenum target, GrGLsizeiptr size, const void* data, GrGLenum usage)
 {
     return sGLContext.get()->fBufferData(target, size, data, usage);
@@ -310,16 +315,21 @@ GrGLvoid glGetShaderInfoLog_mozilla(GrGL
     return sGLContext.get()->fGetShaderInfoLog(shader, bufsize, length, infolog);
 }
 
 GrGLvoid glGetShaderiv_mozilla(GrGLuint shader, GrGLenum pname, GrGLint* params)
 {
     return sGLContext.get()->fGetShaderiv(shader, pname, params);
 }
 
+GrGLvoid glGetShaderPrecisionFormat_mozilla(GrGLenum shadertype, GrGLenum precisiontype, GLint *range, GLint *precision)
+{
+    return sGLContext.get()->fGetShaderPrecisionFormat(shadertype, precisiontype, range, precision);
+}
+
 const GLubyte* glGetString_mozilla(GrGLenum name)
 {
     // GLContext only exposes a OpenGL 2.0 style API, so we have to intercept a bunch
     // of checks that Ganesh makes to determine which capabilities are present
     // on the GL implementation and change them to match what GLContext actually exposes.
 
     if (name == LOCAL_GL_VERSION) {
         if (sGLContext.get()->IsGLES()) {
@@ -352,16 +362,22 @@ const GLubyte* glGetString_mozilla(GrGLe
 
                 if (sGLContext.get()->IsExtensionSupported(GLContext::OES_vertex_array_object)) {
                     strcat(extensionsString, "GL_OES_vertex_array_object ");
                 }
 
                 if (sGLContext.get()->IsSupported(GLFeature::standard_derivatives)) {
                     strcat(extensionsString, "GL_OES_standard_derivatives ");
                 }
+            } else {
+                if (sGLContext.get()->IsSupported(GLFeature::framebuffer_object)) {
+                    strcat(extensionsString, "GL_ARB_framebuffer_object ");
+                } else if (sGLContext.get()->IsExtensionSupported(GLContext::EXT_framebuffer_object)) {
+                    strcat(extensionsString, "GL_EXT_framebuffer_object ");
+                }
             }
 
             if (sGLContext.get()->IsExtensionSupported(GLContext::EXT_texture_format_BGRA8888)) {
                 strcat(extensionsString, "GL_EXT_texture_format_BGRA8888 ");
             }
 
             if (sGLContext.get()->IsExtensionSupported(GLContext::EXT_packed_depth_stencil)) {
                 strcat(extensionsString, "GL_EXT_packed_depth_stencil ");
@@ -576,16 +592,31 @@ GrGLvoid glUniformMatrix4fv_mozilla(GrGL
     return sGLContext.get()->fUniformMatrix4fv(location, count, transpose, value);
 }
 
 GrGLvoid glUseProgram_mozilla(GrGLuint program)
 {
     return sGLContext.get()->fUseProgram(program);
 }
 
+GrGLvoid glVertexAttrib1f_mozilla(GrGLuint index, GrGLfloat value)
+{
+    return sGLContext.get()->fVertexAttrib1f(index, value);
+}
+
+GrGLvoid glVertexAttrib2fv_mozilla(GrGLuint index, const GrGLfloat* values)
+{
+    return sGLContext.get()->fVertexAttrib2fv(index, values);
+}
+
+GrGLvoid glVertexAttrib3fv_mozilla(GrGLuint index, const GrGLfloat* values)
+{
+    return sGLContext.get()->fVertexAttrib3fv(index, values);
+}
+
 GrGLvoid glVertexAttrib4fv_mozilla(GrGLuint index, const GrGLfloat* values)
 {
     return sGLContext.get()->fVertexAttrib4fv(index, values);
 }
 
 GrGLvoid glVertexAttribPointer_mozilla(GrGLuint index, GrGLint size, GrGLenum type, GrGLboolean normalized, GrGLsizei stride, const void* ptr)
 {
     return sGLContext.get()->fVertexAttribPointer(index, size, type, normalized, stride, ptr);
@@ -762,16 +793,17 @@ static GrGLInterface* CreateGrGLInterfac
     i->fFunctions.fAttachShader = glAttachShader_mozilla;
     i->fFunctions.fBindAttribLocation = glBindAttribLocation_mozilla;
     i->fFunctions.fBindBuffer = glBindBuffer_mozilla;
     i->fFunctions.fBindFramebuffer = glBindFramebuffer_mozilla;
     i->fFunctions.fBindRenderbuffer = glBindRenderbuffer_mozilla;
     i->fFunctions.fBindTexture = glBindTexture_mozilla;
     i->fFunctions.fBlendFunc = glBlendFunc_mozilla;
     i->fFunctions.fBlendColor = glBlendColor_mozilla;
+    i->fFunctions.fBlendEquation = glBlendEquation_mozilla;
     i->fFunctions.fBufferData = glBufferData_mozilla;
     i->fFunctions.fBufferSubData = glBufferSubData_mozilla;
     i->fFunctions.fCheckFramebufferStatus = glCheckFramebufferStatus_mozilla;
     i->fFunctions.fClear = glClear_mozilla;
     i->fFunctions.fClearColor = glClearColor_mozilla;
     i->fFunctions.fClearStencil = glClearStencil_mozilla;
     i->fFunctions.fColorMask = glColorMask_mozilla;
     i->fFunctions.fCompileShader = glCompileShader_mozilla;
@@ -806,16 +838,17 @@ static GrGLInterface* CreateGrGLInterfac
     i->fFunctions.fGetBufferParameteriv = glGetBufferParameteriv_mozilla;
     i->fFunctions.fGetError = glGetError_mozilla;
     i->fFunctions.fGetIntegerv = glGetIntegerv_mozilla;
     i->fFunctions.fGetProgramInfoLog = glGetProgramInfoLog_mozilla;
     i->fFunctions.fGetProgramiv = glGetProgramiv_mozilla;
     i->fFunctions.fGetRenderbufferParameteriv = glGetRenderbufferParameteriv_mozilla;
     i->fFunctions.fGetShaderInfoLog = glGetShaderInfoLog_mozilla;
     i->fFunctions.fGetShaderiv = glGetShaderiv_mozilla;
+    i->fFunctions.fGetShaderPrecisionFormat = glGetShaderPrecisionFormat_mozilla;
     i->fFunctions.fGetString = glGetString_mozilla;
     i->fFunctions.fGetUniformLocation = glGetUniformLocation_mozilla;
     i->fFunctions.fLineWidth = glLineWidth_mozilla;
     i->fFunctions.fLinkProgram = glLinkProgram_mozilla;
     i->fFunctions.fPixelStorei = glPixelStorei_mozilla;
     i->fFunctions.fReadPixels = glReadPixels_mozilla;
     i->fFunctions.fRenderbufferStorage = glRenderbufferStorage_mozilla;
     i->fFunctions.fScissor = glScissor_mozilla;
@@ -842,16 +875,19 @@ static GrGLInterface* CreateGrGLInterfac
     i->fFunctions.fUniform4f = glUniform4f_mozilla;
     i->fFunctions.fUniform4i = glUniform4i_mozilla;
     i->fFunctions.fUniform4fv = glUniform4fv_mozilla;
     i->fFunctions.fUniform4iv = glUniform4iv_mozilla;
     i->fFunctions.fUniformMatrix2fv = glUniformMatrix2fv_mozilla;
     i->fFunctions.fUniformMatrix3fv = glUniformMatrix3fv_mozilla;
     i->fFunctions.fUniformMatrix4fv = glUniformMatrix4fv_mozilla;
     i->fFunctions.fUseProgram = glUseProgram_mozilla;
+    i->fFunctions.fVertexAttrib1f = glVertexAttrib1f_mozilla;
+    i->fFunctions.fVertexAttrib2fv = glVertexAttrib2fv_mozilla;
+    i->fFunctions.fVertexAttrib3fv = glVertexAttrib3fv_mozilla;
     i->fFunctions.fVertexAttrib4fv = glVertexAttrib4fv_mozilla;
     i->fFunctions.fVertexAttribPointer = glVertexAttribPointer_mozilla;
     i->fFunctions.fViewport = glViewport_mozilla;
 
     // Required for either desktop OpenGL 2.0 or OpenGL ES 2.0
     i->fFunctions.fStencilFuncSeparate = glStencilFuncSeparate_mozilla;
     i->fFunctions.fStencilMaskSeparate = glStencilMaskSeparate_mozilla;
     i->fFunctions.fStencilOpSeparate = glStencilOpSeparate_mozilla;
--- a/gfx/layers/basic/BasicCompositor.cpp
+++ b/gfx/layers/basic/BasicCompositor.cpp
@@ -249,19 +249,19 @@ Transform(DataSourceSurface* aDest,
 
   Matrix4x4 transform = aTransform;
   transform.PostTranslate(Point3D(-aDestOffset.x, -aDestOffset.y, 0));
   destCanvas.setMatrix(Matrix3DToSkia(transform));
 
   SkPaint paint;
   paint.setXfermodeMode(SkXfermode::kSrc_Mode);
   paint.setAntiAlias(true);
-  paint.setFilterLevel(SkPaint::kLow_FilterLevel);
+  paint.setFilterQuality(kLow_SkFilterQuality);
   SkRect destRect = SkRect::MakeXYWH(0, 0, srcSize.width, srcSize.height);
-  destCanvas.drawBitmapRectToRect(src, nullptr, destRect, &paint);
+  destCanvas.drawBitmapRect(src, destRect, &paint);
 }
 #else
 static pixman_transform
 Matrix3DToPixman(const Matrix4x4& aMatrix)
 {
   pixman_f_transform transform;
 
   transform.m[0][0] = aMatrix._11;
--- a/gfx/layers/basic/BasicLayerManager.cpp
+++ b/gfx/layers/basic/BasicLayerManager.cpp
@@ -737,19 +737,19 @@ Transform(const gfxImageSurface* aDest,
 
   Matrix4x4 transform = aTransform;
   transform.PostTranslate(Point3D(-aDestOffset.x, -aDestOffset.y, 0));
   destCanvas.setMatrix(BasicLayerManager_Matrix3DToSkia(transform));
 
   SkPaint paint;
   paint.setXfermodeMode(SkXfermode::kSrc_Mode);
   paint.setAntiAlias(true);
-  paint.setFilterLevel(SkPaint::kLow_FilterLevel);
+  paint.setFilterQuality(kLow_SkFilterQuality);
   SkRect destRect = SkRect::MakeXYWH(0, 0, srcSize.width, srcSize.height);
-  destCanvas.drawBitmapRectToRect(src, nullptr, destRect, &paint);
+  destCanvas.drawBitmapRect(src, destRect, &paint);
 }
 #else
 static pixman_transform
 BasicLayerManager_Matrix3DToPixman(const Matrix4x4& aMatrix)
 {
   pixman_f_transform transform;
 
   transform.m[0][0] = aMatrix._11;
--- a/gfx/skia/generate_mozbuild.py
+++ b/gfx/skia/generate_mozbuild.py
@@ -20,52 +20,31 @@ header = """
 # debugging generate_mozbuild.py.
 #
 # DO NOT MODIFY THIS FILE IT IS AUTOGENERATED.
 #
 """
 
 footer = """
 
-# can we find a better way of dealing with asm sources?
-
-# left out of UNIFIED_SOURCES for now; that's not C++ anyway, nothing else to unify it with
-#XXX: doesn't build with Apple's assembler
-if not CONFIG['INTEL_ARCHITECTURE'] and CONFIG['CPU_ARCH'] == 'arm' and CONFIG['GNU_CC'] and CONFIG['OS_TARGET'] != 'Darwin':
-    SOURCES += [
-        'skia/src/opts/memset.arm.S',
-    ]
-    if CONFIG['BUILD_ARM_NEON']:
-        SOURCES += [
-            'skia/src/opts/memset16_neon.S',
-            'skia/src/opts/memset32_neon.S',
-        ]
-
-if CONFIG['INTEL_ARCHITECTURE'] and CONFIG['GNU_CC'] and CONFIG['OS_ARCH'] != 'WINNT':
-    if CONFIG['CPU_ARCH'] == 'x86_64':
-        SOURCES += [
-            'skia/src/opts/SkBlitRow_opts_SSE4_x64_asm.S',
-        ]
-    else:
-        SOURCES += [
-            'skia/src/opts/SkBlitRow_opts_SSE4_asm.S',
-        ]
-
+# We allow warnings for third-party code that can be updated from upstream.
 ALLOW_COMPILER_WARNINGS = True
 
 FINAL_LIBRARY = 'gkmedias'
 LOCAL_INCLUDES += [
+    'skia/include/c',
     'skia/include/config',
     'skia/include/core',
     'skia/include/effects',
     'skia/include/gpu',
     'skia/include/images',
     'skia/include/pathops',
     'skia/include/pipe',
     'skia/include/ports',
+    'skia/include/private',
     'skia/include/utils',
     'skia/include/utils/mac',
     'skia/include/utils/win',
     'skia/include/views',
     'skia/src/core',
     'skia/src/gpu',
     'skia/src/gpu/effects',
     'skia/src/gpu/gl',
@@ -73,22 +52,16 @@ LOCAL_INCLUDES += [
     'skia/src/lazy',
     'skia/src/opts',
     'skia/src/sfnt',
     'skia/src/utils',
     'skia/src/utils/mac',
     'skia/src/utils/win',
 ]
 
-if CONFIG['MOZ_WIDGET_TOOLKIT'] in {'android', 'gtk2', 'gtk3', 'qt', 'gonk', 'cocoa', 'uikit'}:
-    DEFINES['SK_USE_POSIX_THREADS'] = 1
-
-if CONFIG['INTEL_ARCHITECTURE'] and CONFIG['HAVE_TOOLCHAIN_SUPPORT_MSSSE3']:
-    DEFINES['SK_BUILD_SSSE3'] = 1
-
 if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('android', 'gonk'):
     DEFINES['SK_FONTHOST_CAIRO_STANDALONE'] = 0
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] in {
     'android',
     'cocoa',
     'uikit',
     'gonk',
@@ -96,62 +69,60 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] in {
   } or CONFIG['MOZ_WIDGET_GTK']:
     DEFINES['SK_FONTHOST_DOES_NOT_USE_FONTMGR'] = 1
 
 # We should autogenerate these SSE related flags.
 
 if CONFIG['_MSC_VER']:
     # MSVC doesn't need special compiler flags, but Skia needs to be told that these files should
     # be built with the required SSE level or it will simply compile in stubs and cause runtime crashes
-    SOURCES['skia/src/opts/SkBitmapFilter_opts_SSE2.cpp'].flags += ['-DSK_CPU_SSE_LEVEL=20']
-    SOURCES['skia/src/opts/SkBitmapProcState_opts_SSE2.cpp'].flags += ['-DSK_CPU_SSE_LEVEL=20']
-    SOURCES['skia/src/opts/SkBitmapProcState_opts_SSSE3.cpp'].flags += ['-DSK_CPU_SSE_LEVEL=31']
-    SOURCES['skia/src/opts/SkBlitRect_opts_SSE2.cpp'].flags += ['-DSK_CPU_SSE_LEVEL=20']
-    SOURCES['skia/src/opts/SkBlitRow_opts_SSE2.cpp'].flags += ['-DSK_CPU_SSE_LEVEL=20']
-    SOURCES['skia/src/opts/SkBlurImage_opts_SSE2.cpp'].flags += ['-DSK_CPU_SSE_LEVEL=20']
-    SOURCES['skia/src/opts/SkBlurImage_opts_SSE4.cpp'].flags += ['-DSK_CPU_SSE_LEVEL=41']
-    SOURCES['skia/src/opts/SkMorphology_opts_SSE2.cpp'].flags += ['-DSK_CPU_SSE_LEVEL=20']
-    SOURCES['skia/src/opts/SkUtils_opts_SSE2.cpp'].flags += ['-DSK_CPU_SSE_LEVEL=20']
-    SOURCES['skia/src/opts/SkXfermode_opts_SSE2.cpp'].flags += ['-DSK_CPU_SSE_LEVEL=20']
-
+    SOURCES['skia/src/opts/SkBitmapFilter_opts_SSE2.cpp'].flags += ['/arch:SSE2 -DSK_CPU_SSE_LEVEL=20']
+    SOURCES['skia/src/opts/SkBitmapProcState_opts_SSE2.cpp'].flags += ['/arch:SSE2 -DSK_CPU_SSE_LEVEL=20']
+    SOURCES['skia/src/opts/SkBitmapProcState_opts_SSSE3.cpp'].flags += ['/arch:SSE2 -DSK_CPU_SSE_LEVEL=31']
+    SOURCES['skia/src/opts/SkBlitRow_opts_SSE2.cpp'].flags += ['/arch:SSE2 -DSK_CPU_SSE_LEVEL=20']
+    SOURCES['skia/src/opts/SkBlitRow_opts_SSE4.cpp'].flags += ['/arch:SSE2 -DSK_CPU_SSE_LEVEL=41']
+    SOURCES['skia/src/opts/SkOpts_ssse3.cpp'].flags += ['/arch:SSE2 -DSK_CPU_SSE_LEVEL=31']
+    SOURCES['skia/src/opts/SkOpts_sse41.cpp'].flags += ['/arch:SSE2 -DSK_CPU_SSE_LEVEL=41']
+    SOURCES['skia/src/opts/SkOpts_avx.cpp'].flags += ['/arch:AVX -DSK_CPU_SSE_LEVEL=51']
 if CONFIG['INTEL_ARCHITECTURE'] and CONFIG['GNU_CC']:
     SOURCES['skia/src/opts/SkBitmapFilter_opts_SSE2.cpp'].flags += CONFIG['SSE2_FLAGS']
     SOURCES['skia/src/opts/SkBitmapProcState_opts_SSE2.cpp'].flags += CONFIG['SSE2_FLAGS']
     SOURCES['skia/src/opts/SkBitmapProcState_opts_SSSE3.cpp'].flags += ['-mssse3']
-    SOURCES['skia/src/opts/SkBlitRect_opts_SSE2.cpp'].flags += CONFIG['SSE2_FLAGS']
     SOURCES['skia/src/opts/SkBlitRow_opts_SSE2.cpp'].flags += CONFIG['SSE2_FLAGS']
-    SOURCES['skia/src/opts/SkBlurImage_opts_SSE2.cpp'].flags += CONFIG['SSE2_FLAGS']
-    SOURCES['skia/src/opts/SkBlurImage_opts_SSE4.cpp'].flags += ['-msse4.1']
-    SOURCES['skia/src/opts/SkMorphology_opts_SSE2.cpp'].flags += CONFIG['SSE2_FLAGS']
-    SOURCES['skia/src/opts/SkUtils_opts_SSE2.cpp'].flags += CONFIG['SSE2_FLAGS']
-    SOURCES['skia/src/opts/SkXfermode_opts_SSE2.cpp'].flags += CONFIG['SSE2_FLAGS']
+    SOURCES['skia/src/opts/SkBlitRow_opts_SSE4.cpp'].flags += ['-msse4.1']
+    SOURCES['skia/src/opts/SkOpts_ssse3.cpp'].flags += ['-mssse3']
+    SOURCES['skia/src/opts/SkOpts_sse41.cpp'].flags += ['-msse4.1']
+    SOURCES['skia/src/opts/SkOpts_avx.cpp'].flags += ['-mavx']
 elif CONFIG['CPU_ARCH'] == 'arm' and CONFIG['GNU_CC'] and CONFIG['BUILD_ARM_NEON']:
-    DEFINES['__ARM_HAVE_OPTIONAL_NEON_SUPPORT'] = 1
-    DEFINES['USE_ANDROID_NDK_CPU_FEATURES'] = 0
+    DEFINES['SK_ARM_HAS_OPTIONAL_NEON'] = 1
 elif CONFIG['CLANG_CL']:
     SOURCES['skia/src/opts/SkBitmapProcState_opts_SSSE3.cpp'].flags += ['-mssse3']
-    SOURCES['skia/src/opts/SkBlurImage_opts_SSE4.cpp'].flags += ['-msse4.1']
+    SOURCES['skia/src/opts/SkBlitRow_opts_SSE4.cpp'].flags += ['-msse4.1']
+    SOURCES['skia/src/opts/SkOpts_ssse3.cpp'].flags += ['-mssse3']
+    SOURCES['skia/src/opts/SkOpts_sse41.cpp'].flags += ['-msse4.1']
+    SOURCES['skia/src/opts/SkOpts_avx.cpp'].flags += ['-mavx']
 
 DEFINES['SKIA_IMPLEMENTATION'] = 1
-DEFINES['GR_IMPLEMENTATION'] = 1
 
 if CONFIG['GNU_CXX']:
     CXXFLAGS += [
         '-Wno-deprecated-declarations',
         '-Wno-overloaded-virtual',
         '-Wno-sign-compare',
         '-Wno-unused-function',
     ]
     if CONFIG['CLANG_CXX']:
         CXXFLAGS += [
             '-Wno-implicit-fallthrough',
             '-Wno-inconsistent-missing-override',
             '-Wno-macro-redefined',
             '-Wno-unused-private-field',
         ]
+        # work around inline function linking bug with template arguments
+        SOURCES['skia/src/gpu/GrResourceCache.cpp'].flags += ['-fkeep-inline-functions']
     else:
         CXXFLAGS += [
             '-Wno-logical-op',
             '-Wno-maybe-uninitialized',
         ]
     if CONFIG['CPU_ARCH'] == 'arm':
         SOURCES['skia/src/opts/SkBlitRow_opts_arm.cpp'].flags += ['-fomit-frame-pointer']
 
@@ -175,112 +146,95 @@ def generate_opt_sources():
         opt_sources['opts'].add(os.path.join(root, name))
 
   return opt_sources
 
 def generate_platform_sources():
   sources = {}
 
   for plat in platforms:
-    if os.system("cd skia && GYP_GENERATORS=dump_mozbuild ./gyp_skia -D OS=%s gyp/skia_lib.gyp" % plat) != 0:
+    if os.system("cd skia && GYP_GENERATORS=dump_mozbuild ./gyp_skia -D OS=%s -D host_os=linux gyp/skia_lib.gyp" % plat) != 0:
       print 'Failed to generate sources for ' + plat
       continue
 
 
     f = open('skia/sources.json');
     sources[plat] = set(v.replace('../', 'skia/') for v in json.load(f));
     f.close()
 
   return dict(sources.items() + generate_opt_sources().items())
 
 
 def generate_separated_sources(platform_sources):
   blacklist = [
     'ChromeUtils',
-    'SkImageDecoder_',
-    '_gif',
-    'SkFontConfigParser_android',
     'SkJpeg',
     'SkXML',
-    'SkCity',
     'GrGLCreateNativeInterface',
+    'SkCreatePlatformGLContext',
     'fontconfig',
-    'SkCondVar',
     'SkThreadUtils_pthread_',
-    'SkImage_Codec',
-    'SkBitmapChecksummer',
-    'SkNativeGLContext',
     'SkFontConfig',
-    'SkFontHost_win_dw',
     'SkFontMgr_android',
+    'SkFontMgr_custom',
+    'SkFontHost_FreeType.cpp',
     'SkForceLinking',
     'SkMovie',
     'SkImageDecoder',
     'SkImageEncoder',
     'SkBitmapHasher',
+    'SkBitmapRegion',
+    'codec',
     'SkWGL',
-    'SkImages',
-    'SkDiscardableMemory_ashmem',
     'SkMemory_malloc',
+    'SkOpts_',
     'opts_check_x86',
     'third_party',
   ]
 
   def isblacklisted(value):
     for item in blacklist:
       if value.find(item) >= 0:
         return True
 
     return False
 
   separated = defaultdict(set, {
     'common': {
-      #'skia/src/effects/gradients/SkGradientTileProc.cpp',
       'skia/src/gpu/gl/GrGLCreateNativeInterface_none.cpp',
       'skia/src/ports/SkDiscardableMemory_none.cpp',
       'skia/src/ports/SkImageDecoder_empty.cpp',
       'skia/src/ports/SkMemory_mozalloc.cpp',
-      # 'skia/src/images/SkImages.cpp',
-      # 'skia/src/images/SkImageRef.cpp',
-      # 'skia/src/images/SkImageRef_GlobalPool.cpp',
-      # 'skia/src/images/SkImageRefPool.cpp',
-      # 'skia/src/images/SkImageDecoder.cpp',
-      # 'skia/src/images/SkImageDecoder_Factory.cpp',
     },
     'android': {
       # 'skia/src/ports/SkDebug_android.cpp',
-      'skia/src/ports/SkFontHost_android_old.cpp',
       'skia/src/ports/SkFontHost_cairo.cpp',
       # 'skia/src/ports/SkFontHost_FreeType.cpp',
       # 'skia/src/ports/SkFontHost_FreeType_common.cpp',
-      # 'skia/src/ports/SkThread_pthread.cpp',
-      # 'skia/src/ports/SkPurgeableMemoryBlock_android.cpp',
       # 'skia/src/ports/SkTime_Unix.cpp',
       # 'skia/src/utils/SkThreadUtils_pthread.cpp',
-      # 'skia/src/images/SkImageRef_ashmem.cpp',
-      # 'skia/src/utils/android/ashmem.cpp',
     },
     'linux': {
       'skia/src/ports/SkFontHost_cairo.cpp',
     },
     'intel': {
       # There is currently no x86-specific opt for SkTextureCompression
       'skia/src/opts/opts_check_x86.cpp',
-      'skia/src/opts/SkTextureCompression_opts_none.cpp',
+      'skia/src/opts/SkOpts_ssse3.cpp',
+      'skia/src/opts/SkOpts_sse41.cpp',
+      'skia/src/opts/SkOpts_avx.cpp',
     },
     'arm': {
-      'skia/src/opts/SkUtils_opts_arm.cpp',
       'skia/src/core/SkUtilsArm.cpp',
     },
     'neon': {
+      'skia/src/opts/SkOpts_neon.cpp',
       'skia/src/opts/SkBitmapProcState_arm_neon.cpp',
     },
-    'none': {
-      'skia/src/opts/SkUtils_opts_none.cpp',
-    }
+    'none': set()
   })
 
   for plat in platform_sources.keys():
     for value in platform_sources[plat]:
       if isblacklisted(value):
         continue
 
       if value in separated['common']:
@@ -336,25 +290,32 @@ def write_sources(f, values, indent):
     'SkAdvancedTypefaceMetrics',
     'SkBitmapProcState_matrixProcs.cpp',
     'SkBlitter_A8.cpp',
     'SkBlitter_ARGB32.cpp',
     'SkBlitter_RGB16.cpp',
     'SkBlitter_Sprite.cpp',
     'SkBlitRow_opts_arm.cpp',
     'SkScan_Antihair.cpp',
-    'SkCondVar.cpp',
     'SkParse.cpp',
-    'GrAddPathRenderers_default.cpp',
-    'GrDistanceFieldTextContext.cpp',
     'SkSHA1.cpp',
     'SkMD5.cpp',
     'SkPictureData.cpp',
-    'SkScaledImageCache.cpp',
     'opts_check_x86.cpp',
+    'GrDrawContext',
+    'GrResourceCache',
+    'GrAA',
+    'GrGL',
+    'GrBatchAtlas.cpp',
+    'SkArithmeticMode_gpu.cpp',
+    'SkImage_Gpu.cpp',
+    'SkPathOpsDebug.cpp',
+    'SkParsePath.cpp',
+    'SkOpts',
+    'SkRecorder.cpp',
   ]
 
   def isblacklisted(value):
     for item in unified_blacklist:
       if value.find(item) >= 0:
         return True
 
     return False
--- a/gfx/skia/moz.build
+++ b/gfx/skia/moz.build
@@ -9,36 +9,41 @@
 # # #####   #######        #     #   ## ##   #     #     #      ###
 #
 # Seriously. You shouldn't even be looking at this file unless you're
 # debugging generate_mozbuild.py.
 #
 # DO NOT MODIFY THIS FILE IT IS AUTOGENERATED.
 #
 UNIFIED_SOURCES += [
+    'skia/src/c/sk_paint.cpp',
+    'skia/src/c/sk_surface.cpp',
     'skia/src/core/SkAAClip.cpp',
     'skia/src/core/SkAlphaRuns.cpp',
     'skia/src/core/SkAnnotation.cpp',
     'skia/src/core/SkBBHFactory.cpp',
-    'skia/src/core/SkBBoxHierarchyRecord.cpp',
-    'skia/src/core/SkBBoxRecord.cpp',
+    'skia/src/core/SkBigPicture.cpp',
     'skia/src/core/SkBitmap.cpp',
-    'skia/src/core/SkBitmap_scroll.cpp',
+    'skia/src/core/SkBitmapCache.cpp',
+    'skia/src/core/SkBitmapController.cpp',
     'skia/src/core/SkBitmapDevice.cpp',
     'skia/src/core/SkBitmapFilter.cpp',
     'skia/src/core/SkBitmapHeap.cpp',
     'skia/src/core/SkBitmapProcShader.cpp',
     'skia/src/core/SkBitmapProcState.cpp',
+    'skia/src/core/SkBitmapProvider.cpp',
     'skia/src/core/SkBitmapScaler.cpp',
     'skia/src/core/SkBlitMask_D32.cpp',
     'skia/src/core/SkBlitRow_D16.cpp',
     'skia/src/core/SkBlitRow_D32.cpp',
     'skia/src/core/SkBlitter.cpp',
     'skia/src/core/SkBuffer.cpp',
+    'skia/src/core/SkCachedData.cpp',
     'skia/src/core/SkCanvas.cpp',
+    'skia/src/core/SkChecksum.cpp',
     'skia/src/core/SkChunkAlloc.cpp',
     'skia/src/core/SkClipStack.cpp',
     'skia/src/core/SkColor.cpp',
     'skia/src/core/SkColorFilter.cpp',
     'skia/src/core/SkColorTable.cpp',
     'skia/src/core/SkComposeShader.cpp',
     'skia/src/core/SkConfig8888.cpp',
     'skia/src/core/SkConvolver.cpp',
@@ -48,559 +53,609 @@ UNIFIED_SOURCES += [
     'skia/src/core/SkDebug.cpp',
     'skia/src/core/SkDeque.cpp',
     'skia/src/core/SkDevice.cpp',
     'skia/src/core/SkDeviceLooper.cpp',
     'skia/src/core/SkDeviceProfile.cpp',
     'skia/src/core/SkDistanceFieldGen.cpp',
     'skia/src/core/SkDither.cpp',
     'skia/src/core/SkDraw.cpp',
+    'skia/src/core/SkDrawable.cpp',
     'skia/src/core/SkDrawLooper.cpp',
     'skia/src/core/SkEdge.cpp',
     'skia/src/core/SkEdgeBuilder.cpp',
     'skia/src/core/SkEdgeClipper.cpp',
     'skia/src/core/SkError.cpp',
     'skia/src/core/SkFilterProc.cpp',
     'skia/src/core/SkFilterShader.cpp',
     'skia/src/core/SkFlattenable.cpp',
     'skia/src/core/SkFlattenableSerialization.cpp',
-    'skia/src/core/SkFloat.cpp',
     'skia/src/core/SkFloatBits.cpp',
     'skia/src/core/SkFont.cpp',
     'skia/src/core/SkFontDescriptor.cpp',
+    'skia/src/core/SkFontMgr.cpp',
     'skia/src/core/SkFontStream.cpp',
+    'skia/src/core/SkFontStyle.cpp',
+    'skia/src/core/SkForceCPlusPlusLinking.cpp',
     'skia/src/core/SkGeometry.cpp',
     'skia/src/core/SkGlyphCache.cpp',
     'skia/src/core/SkGraphics.cpp',
+    'skia/src/core/SkHalf.cpp',
+    'skia/src/core/SkImageCacherator.cpp',
     'skia/src/core/SkImageFilter.cpp',
     'skia/src/core/SkImageGenerator.cpp',
     'skia/src/core/SkImageInfo.cpp',
-    'skia/src/core/SkInstCnt.cpp',
+    'skia/src/core/SkLightingShader.cpp',
     'skia/src/core/SkLineClipper.cpp',
+    'skia/src/core/SkLocalMatrixImageFilter.cpp',
     'skia/src/core/SkLocalMatrixShader.cpp',
     'skia/src/core/SkMallocPixelRef.cpp',
     'skia/src/core/SkMask.cpp',
+    'skia/src/core/SkMaskCache.cpp',
     'skia/src/core/SkMaskFilter.cpp',
     'skia/src/core/SkMaskGamma.cpp',
     'skia/src/core/SkMath.cpp',
     'skia/src/core/SkMatrix.cpp',
-    'skia/src/core/SkMatrixClipStateMgr.cpp',
+    'skia/src/core/SkMatrixImageFilter.cpp',
     'skia/src/core/SkMetaData.cpp',
+    'skia/src/core/SkMiniRecorder.cpp',
     'skia/src/core/SkMipMap.cpp',
+    'skia/src/core/SkMultiPictureDraw.cpp',
+    'skia/src/core/SkNinePatchIter.cpp',
     'skia/src/core/SkPackBits.cpp',
     'skia/src/core/SkPaint.cpp',
-    'skia/src/core/SkPaintOptionsAndroid.cpp',
     'skia/src/core/SkPaintPriv.cpp',
-    'skia/src/core/SkPatch.cpp',
     'skia/src/core/SkPath.cpp',
     'skia/src/core/SkPathEffect.cpp',
-    'skia/src/core/SkPathHeap.cpp',
     'skia/src/core/SkPathMeasure.cpp',
     'skia/src/core/SkPathRef.cpp',
     'skia/src/core/SkPicture.cpp',
+    'skia/src/core/SkPictureContentInfo.cpp',
     'skia/src/core/SkPictureFlat.cpp',
+    'skia/src/core/SkPictureImageGenerator.cpp',
     'skia/src/core/SkPicturePlayback.cpp',
-    'skia/src/core/SkPictureRangePlayback.cpp',
     'skia/src/core/SkPictureRecord.cpp',
     'skia/src/core/SkPictureRecorder.cpp',
-    'skia/src/core/SkPictureReplacementPlayback.cpp',
     'skia/src/core/SkPictureShader.cpp',
-    'skia/src/core/SkPictureStateTree.cpp',
     'skia/src/core/SkPixelRef.cpp',
+    'skia/src/core/SkPixmap.cpp',
     'skia/src/core/SkPoint.cpp',
-    'skia/src/core/SkProcSpriteBlitter.cpp',
+    'skia/src/core/SkPoint3.cpp',
     'skia/src/core/SkPtrRecorder.cpp',
     'skia/src/core/SkQuadClipper.cpp',
-    'skia/src/core/SkQuadTree.cpp',
     'skia/src/core/SkRasterClip.cpp',
     'skia/src/core/SkRasterizer.cpp',
     'skia/src/core/SkReadBuffer.cpp',
-    'skia/src/core/SkRecordAnalysis.cpp',
+    'skia/src/core/SkRecord.cpp',
     'skia/src/core/SkRecordDraw.cpp',
-    'skia/src/core/SkRecorder.cpp',
-    'skia/src/core/SkRecording.cpp',
     'skia/src/core/SkRecordOpts.cpp',
+    'skia/src/core/SkRecords.cpp',
     'skia/src/core/SkRect.cpp',
     'skia/src/core/SkRefDict.cpp',
     'skia/src/core/SkRegion.cpp',
     'skia/src/core/SkRegion_path.cpp',
+    'skia/src/core/SkRemote.cpp',
+    'skia/src/core/SkResourceCache.cpp',
     'skia/src/core/SkRRect.cpp',
     'skia/src/core/SkRTree.cpp',
+    'skia/src/core/SkRWBuffer.cpp',
     'skia/src/core/SkScalar.cpp',
     'skia/src/core/SkScalerContext.cpp',
     'skia/src/core/SkScan.cpp',
     'skia/src/core/SkScan_AntiPath.cpp',
     'skia/src/core/SkScan_Hairline.cpp',
     'skia/src/core/SkScan_Path.cpp',
+    'skia/src/core/SkSemaphore.cpp',
     'skia/src/core/SkShader.cpp',
+    'skia/src/core/SkSharedMutex.cpp',
+    'skia/src/core/SkSpinlock.cpp',
     'skia/src/core/SkSpriteBlitter_ARGB32.cpp',
     'skia/src/core/SkSpriteBlitter_RGB16.cpp',
     'skia/src/core/SkStream.cpp',
     'skia/src/core/SkString.cpp',
     'skia/src/core/SkStringUtils.cpp',
     'skia/src/core/SkStroke.cpp',
     'skia/src/core/SkStrokeRec.cpp',
     'skia/src/core/SkStrokerPriv.cpp',
-    'skia/src/core/SkTileGrid.cpp',
+    'skia/src/core/SkTaskGroup.cpp',
+    'skia/src/core/SkTextBlob.cpp',
+    'skia/src/core/SkThreadID.cpp',
+    'skia/src/core/SkTime.cpp',
     'skia/src/core/SkTLS.cpp',
     'skia/src/core/SkTSearch.cpp',
     'skia/src/core/SkTypeface.cpp',
     'skia/src/core/SkTypefaceCache.cpp',
     'skia/src/core/SkUnPreMultiply.cpp',
     'skia/src/core/SkUtils.cpp',
     'skia/src/core/SkValidatingReadBuffer.cpp',
+    'skia/src/core/SkVarAlloc.cpp',
     'skia/src/core/SkVertState.cpp',
     'skia/src/core/SkWriteBuffer.cpp',
     'skia/src/core/SkWriter32.cpp',
     'skia/src/core/SkXfermode.cpp',
+    'skia/src/core/SkXfermodeInterpretation.cpp',
+    'skia/src/core/SkYUVPlanesCache.cpp',
     'skia/src/doc/SkDocument.cpp',
-    'skia/src/effects/gradients/SkBitmapCache.cpp',
     'skia/src/effects/gradients/SkClampRange.cpp',
+    'skia/src/effects/gradients/SkGradientBitmapCache.cpp',
     'skia/src/effects/gradients/SkGradientShader.cpp',
     'skia/src/effects/gradients/SkLinearGradient.cpp',
     'skia/src/effects/gradients/SkRadialGradient.cpp',
     'skia/src/effects/gradients/SkSweepGradient.cpp',
     'skia/src/effects/gradients/SkTwoPointConicalGradient.cpp',
     'skia/src/effects/gradients/SkTwoPointConicalGradient_gpu.cpp',
-    'skia/src/effects/gradients/SkTwoPointRadialGradient.cpp',
+    'skia/src/effects/GrCircleBlurFragmentProcessor.cpp',
     'skia/src/effects/Sk1DPathEffect.cpp',
     'skia/src/effects/Sk2DPathEffect.cpp',
     'skia/src/effects/SkAlphaThresholdFilter.cpp',
+    'skia/src/effects/SkArcToPathEffect.cpp',
     'skia/src/effects/SkArithmeticMode.cpp',
-    'skia/src/effects/SkAvoidXfermode.cpp',
-    'skia/src/effects/SkBitmapSource.cpp',
     'skia/src/effects/SkBlurDrawLooper.cpp',
     'skia/src/effects/SkBlurImageFilter.cpp',
     'skia/src/effects/SkBlurMask.cpp',
     'skia/src/effects/SkBlurMaskFilter.cpp',
+    'skia/src/effects/SkColorCubeFilter.cpp',
     'skia/src/effects/SkColorFilterImageFilter.cpp',
     'skia/src/effects/SkColorFilters.cpp',
     'skia/src/effects/SkColorMatrix.cpp',
     'skia/src/effects/SkColorMatrixFilter.cpp',
     'skia/src/effects/SkComposeImageFilter.cpp',
     'skia/src/effects/SkCornerPathEffect.cpp',
     'skia/src/effects/SkDashPathEffect.cpp',
     'skia/src/effects/SkDiscretePathEffect.cpp',
     'skia/src/effects/SkDisplacementMapEffect.cpp',
     'skia/src/effects/SkDropShadowImageFilter.cpp',
     'skia/src/effects/SkEmbossMask.cpp',
     'skia/src/effects/SkEmbossMaskFilter.cpp',
     'skia/src/effects/SkGpuBlurUtils.cpp',
+    'skia/src/effects/SkImageSource.cpp',
     'skia/src/effects/SkLayerDrawLooper.cpp',
     'skia/src/effects/SkLayerRasterizer.cpp',
     'skia/src/effects/SkLerpXfermode.cpp',
     'skia/src/effects/SkLightingImageFilter.cpp',
     'skia/src/effects/SkLumaColorFilter.cpp',
     'skia/src/effects/SkMagnifierImageFilter.cpp',
     'skia/src/effects/SkMatrixConvolutionImageFilter.cpp',
-    'skia/src/effects/SkMatrixImageFilter.cpp',
     'skia/src/effects/SkMergeImageFilter.cpp',
     'skia/src/effects/SkMorphologyImageFilter.cpp',
     'skia/src/effects/SkOffsetImageFilter.cpp',
     'skia/src/effects/SkPaintFlagsDrawFilter.cpp',
     'skia/src/effects/SkPerlinNoiseShader.cpp',
     'skia/src/effects/SkPictureImageFilter.cpp',
     'skia/src/effects/SkPixelXorXfermode.cpp',
-    'skia/src/effects/SkPorterDuff.cpp',
     'skia/src/effects/SkRectShaderImageFilter.cpp',
-    'skia/src/effects/SkStippleMaskFilter.cpp',
     'skia/src/effects/SkTableColorFilter.cpp',
     'skia/src/effects/SkTableMaskFilter.cpp',
     'skia/src/effects/SkTestImageFilters.cpp',
     'skia/src/effects/SkTileImageFilter.cpp',
-    'skia/src/effects/SkTransparentShader.cpp',
     'skia/src/effects/SkXfermodeImageFilter.cpp',
     'skia/src/fonts/SkFontMgr_indirect.cpp',
     'skia/src/fonts/SkGScalerContext.cpp',
+    'skia/src/fonts/SkRandomScalerContext.cpp',
     'skia/src/fonts/SkRemotableFontMgr.cpp',
     'skia/src/fonts/SkTestScalerContext.cpp',
+    'skia/src/gpu/batches/GrAtlasTextBatch.cpp',
+    'skia/src/gpu/batches/GrBatch.cpp',
+    'skia/src/gpu/batches/GrCopySurfaceBatch.cpp',
+    'skia/src/gpu/batches/GrDashLinePathRenderer.cpp',
+    'skia/src/gpu/batches/GrDefaultPathRenderer.cpp',
+    'skia/src/gpu/batches/GrDrawAtlasBatch.cpp',
+    'skia/src/gpu/batches/GrDrawBatch.cpp',
+    'skia/src/gpu/batches/GrDrawPathBatch.cpp',
+    'skia/src/gpu/batches/GrDrawVerticesBatch.cpp',
+    'skia/src/gpu/batches/GrNinePatch.cpp',
+    'skia/src/gpu/batches/GrNonAAFillRectBatch.cpp',
+    'skia/src/gpu/batches/GrNonAAStrokeRectBatch.cpp',
+    'skia/src/gpu/batches/GrRectBatchFactory.cpp',
+    'skia/src/gpu/batches/GrStencilAndCoverPathRenderer.cpp',
+    'skia/src/gpu/batches/GrTessellatingPathRenderer.cpp',
+    'skia/src/gpu/batches/GrVertexBatch.cpp',
     'skia/src/gpu/effects/GrBezierEffect.cpp',
     'skia/src/gpu/effects/GrBicubicEffect.cpp',
+    'skia/src/gpu/effects/GrBitmapTextGeoProc.cpp',
     'skia/src/gpu/effects/GrConfigConversionEffect.cpp',
+    'skia/src/gpu/effects/GrConstColorProcessor.cpp',
     'skia/src/gpu/effects/GrConvexPolyEffect.cpp',
     'skia/src/gpu/effects/GrConvolutionEffect.cpp',
-    'skia/src/gpu/effects/GrCustomCoordsTextureEffect.cpp',
+    'skia/src/gpu/effects/GrCoverageSetOpXP.cpp',
+    'skia/src/gpu/effects/GrCustomXfermode.cpp',
     'skia/src/gpu/effects/GrDashingEffect.cpp',
-    'skia/src/gpu/effects/GrDistanceFieldTextureEffect.cpp',
+    'skia/src/gpu/effects/GrDisableColorXP.cpp',
+    'skia/src/gpu/effects/GrDistanceFieldGeoProc.cpp',
     'skia/src/gpu/effects/GrDitherEffect.cpp',
     'skia/src/gpu/effects/GrMatrixConvolutionEffect.cpp',
     'skia/src/gpu/effects/GrOvalEffect.cpp',
+    'skia/src/gpu/effects/GrPorterDuffXferProcessor.cpp',
     'skia/src/gpu/effects/GrRRectEffect.cpp',
     'skia/src/gpu/effects/GrSimpleTextureEffect.cpp',
     'skia/src/gpu/effects/GrSingleTextureEffect.cpp',
     'skia/src/gpu/effects/GrTextureDomain.cpp',
     'skia/src/gpu/effects/GrTextureStripAtlas.cpp',
+    'skia/src/gpu/effects/GrXfermodeFragmentProcessor.cpp',
     'skia/src/gpu/effects/GrYUVtoRGBEffect.cpp',
     'skia/src/gpu/gl/debug/GrBufferObj.cpp',
     'skia/src/gpu/gl/debug/GrDebugGL.cpp',
     'skia/src/gpu/gl/debug/GrFrameBufferObj.cpp',
-    'skia/src/gpu/gl/debug/GrGLCreateDebugInterface.cpp',
     'skia/src/gpu/gl/debug/GrProgramObj.cpp',
     'skia/src/gpu/gl/debug/GrShaderObj.cpp',
     'skia/src/gpu/gl/debug/GrTextureObj.cpp',
     'skia/src/gpu/gl/debug/GrTextureUnitObj.cpp',
     'skia/src/gpu/gl/debug/SkDebugGLContext.cpp',
-    'skia/src/gpu/gl/GrGLAssembleInterface.cpp',
-    'skia/src/gpu/gl/GrGLBufferImpl.cpp',
-    'skia/src/gpu/gl/GrGLCaps.cpp',
-    'skia/src/gpu/gl/GrGLContext.cpp',
-    'skia/src/gpu/gl/GrGLCreateNativeInterface_none.cpp',
-    'skia/src/gpu/gl/GrGLCreateNullInterface.cpp',
-    'skia/src/gpu/gl/GrGLDefaultInterface_native.cpp',
-    'skia/src/gpu/gl/GrGLExtensions.cpp',
-    'skia/src/gpu/gl/GrGLIndexBuffer.cpp',
-    'skia/src/gpu/gl/GrGLInterface.cpp',
-    'skia/src/gpu/gl/GrGLNameAllocator.cpp',
-    'skia/src/gpu/gl/GrGLNoOpInterface.cpp',
-    'skia/src/gpu/gl/GrGLPath.cpp',
-    'skia/src/gpu/gl/GrGLPathRange.cpp',
-    'skia/src/gpu/gl/GrGLProgram.cpp',
-    'skia/src/gpu/gl/GrGLProgramDesc.cpp',
-    'skia/src/gpu/gl/GrGLProgramEffects.cpp',
-    'skia/src/gpu/gl/GrGLRenderTarget.cpp',
-    'skia/src/gpu/gl/GrGLShaderBuilder.cpp',
-    'skia/src/gpu/gl/GrGLSL.cpp',
-    'skia/src/gpu/gl/GrGLStencilBuffer.cpp',
-    'skia/src/gpu/gl/GrGLTexture.cpp',
-    'skia/src/gpu/gl/GrGLUniformManager.cpp',
-    'skia/src/gpu/gl/GrGLUtil.cpp',
-    'skia/src/gpu/gl/GrGLVertexArray.cpp',
-    'skia/src/gpu/gl/GrGLVertexBuffer.cpp',
-    'skia/src/gpu/gl/GrGpuGL.cpp',
-    'skia/src/gpu/gl/GrGpuGL_program.cpp',
-    'skia/src/gpu/gl/SkGLContextHelper.cpp',
+    'skia/src/gpu/gl/SkGLContext.cpp',
     'skia/src/gpu/gl/SkNullGLContext.cpp',
-    'skia/src/gpu/GrAAConvexPathRenderer.cpp',
-    'skia/src/gpu/GrAAHairLinePathRenderer.cpp',
-    'skia/src/gpu/GrAARectRenderer.cpp',
-    'skia/src/gpu/GrAllocPool.cpp',
-    'skia/src/gpu/GrAtlas.cpp',
-    'skia/src/gpu/GrBitmapTextContext.cpp',
+    'skia/src/gpu/GrAtlasTextBlob.cpp',
+    'skia/src/gpu/GrAtlasTextContext.cpp',
+    'skia/src/gpu/GrBatchFlushState.cpp',
+    'skia/src/gpu/GrBatchFontCache.cpp',
+    'skia/src/gpu/GrBatchTest.cpp',
     'skia/src/gpu/GrBlend.cpp',
+    'skia/src/gpu/GrBlurUtils.cpp',
     'skia/src/gpu/GrBufferAllocPool.cpp',
-    'skia/src/gpu/GrCacheID.cpp',
-    'skia/src/gpu/GrClipData.cpp',
-    'skia/src/gpu/GrClipMaskCache.cpp',
+    'skia/src/gpu/GrCaps.cpp',
+    'skia/src/gpu/GrClip.cpp',
     'skia/src/gpu/GrClipMaskManager.cpp',
     'skia/src/gpu/GrContext.cpp',
-    'skia/src/gpu/GrDefaultPathRenderer.cpp',
-    'skia/src/gpu/GrDrawState.cpp',
+    'skia/src/gpu/GrCoordTransform.cpp',
+    'skia/src/gpu/GrDefaultGeoProcFactory.cpp',
+    'skia/src/gpu/GrDrawingManager.cpp',
     'skia/src/gpu/GrDrawTarget.cpp',
-    'skia/src/gpu/GrEffect.cpp',
     'skia/src/gpu/GrFontScaler.cpp',
+    'skia/src/gpu/GrFragmentProcessor.cpp',
     'skia/src/gpu/GrGpu.cpp',
     'skia/src/gpu/GrGpuFactory.cpp',
     'skia/src/gpu/GrGpuResource.cpp',
-    'skia/src/gpu/GrInOrderDrawBuffer.cpp',
+    'skia/src/gpu/GrGpuResourceRef.cpp',
+    'skia/src/gpu/GrImageIDTextureAdjuster.cpp',
+    'skia/src/gpu/GrInvariantOutput.cpp',
+    'skia/src/gpu/GrLayerAtlas.cpp',
     'skia/src/gpu/GrLayerCache.cpp',
+    'skia/src/gpu/GrLayerHoister.cpp',
     'skia/src/gpu/GrMemoryPool.cpp',
     'skia/src/gpu/GrOvalRenderer.cpp',
     'skia/src/gpu/GrPaint.cpp',
     'skia/src/gpu/GrPath.cpp',
+    'skia/src/gpu/GrPathProcessor.cpp',
+    'skia/src/gpu/GrPathRange.cpp',
     'skia/src/gpu/GrPathRenderer.cpp',
     'skia/src/gpu/GrPathRendererChain.cpp',
+    'skia/src/gpu/GrPathRendering.cpp',
     'skia/src/gpu/GrPathUtils.cpp',
-    'skia/src/gpu/GrPictureUtils.cpp',
+    'skia/src/gpu/GrPipeline.cpp',
+    'skia/src/gpu/GrPipelineBuilder.cpp',
+    'skia/src/gpu/GrPrimitiveProcessor.cpp',
+    'skia/src/gpu/GrProcessor.cpp',
+    'skia/src/gpu/GrProcessorUnitTest.cpp',
+    'skia/src/gpu/GrProcOptInfo.cpp',
+    'skia/src/gpu/GrProgramElement.cpp',
+    'skia/src/gpu/GrRecordReplaceDraw.cpp',
     'skia/src/gpu/GrRectanizer_pow2.cpp',
     'skia/src/gpu/GrRectanizer_skyline.cpp',
     'skia/src/gpu/GrReducedClip.cpp',
     'skia/src/gpu/GrRenderTarget.cpp',
-    'skia/src/gpu/GrResourceCache.cpp',
+    'skia/src/gpu/GrResourceProvider.cpp',
     'skia/src/gpu/GrSoftwarePathRenderer.cpp',
     'skia/src/gpu/GrStencil.cpp',
-    'skia/src/gpu/GrStencilAndCoverPathRenderer.cpp',
     'skia/src/gpu/GrStencilAndCoverTextContext.cpp',
-    'skia/src/gpu/GrStencilBuffer.cpp',
+    'skia/src/gpu/GrStencilAttachment.cpp',
+    'skia/src/gpu/GrStrokeInfo.cpp',
     'skia/src/gpu/GrSurface.cpp',
     'skia/src/gpu/GrSWMaskHelper.cpp',
+    'skia/src/gpu/GrTestUtils.cpp',
+    'skia/src/gpu/GrTextBlobCache.cpp',
     'skia/src/gpu/GrTextContext.cpp',
-    'skia/src/gpu/GrTextStrike.cpp',
     'skia/src/gpu/GrTexture.cpp',
     'skia/src/gpu/GrTextureAccess.cpp',
+    'skia/src/gpu/GrTextureParamsAdjuster.cpp',
+    'skia/src/gpu/GrTextureProvider.cpp',
     'skia/src/gpu/GrTraceMarker.cpp',
+    'skia/src/gpu/GrXferProcessor.cpp',
+    'skia/src/gpu/GrYUVProvider.cpp',
     'skia/src/gpu/SkGpuDevice.cpp',
+    'skia/src/gpu/SkGpuDevice_drawTexture.cpp',
     'skia/src/gpu/SkGr.cpp',
     'skia/src/gpu/SkGrPixelRef.cpp',
     'skia/src/gpu/SkGrTexturePixelRef.cpp',
     'skia/src/image/SkImage.cpp',
-    'skia/src/image/SkImage_Gpu.cpp',
+    'skia/src/image/SkImage_Generator.cpp',
     'skia/src/image/SkImage_Raster.cpp',
-    'skia/src/image/SkImagePriv.cpp',
+    'skia/src/image/SkImageShader.cpp',
     'skia/src/image/SkSurface.cpp',
     'skia/src/image/SkSurface_Gpu.cpp',
     'skia/src/image/SkSurface_Raster.cpp',
     'skia/src/images/bmpdecoderhelper.cpp',
     'skia/src/images/SkDecodingImageGenerator.cpp',
     'skia/src/images/SkPageFlipper.cpp',
     'skia/src/images/SkScaledBitmapSampler.cpp',
-    'skia/src/lazy/SkCachingPixelRef.cpp',
     'skia/src/lazy/SkDiscardableMemoryPool.cpp',
     'skia/src/lazy/SkDiscardablePixelRef.cpp',
     'skia/src/pathops/SkAddIntersections.cpp',
-    'skia/src/pathops/SkDCubicIntersection.cpp',
+    'skia/src/pathops/SkDConicLineIntersection.cpp',
     'skia/src/pathops/SkDCubicLineIntersection.cpp',
     'skia/src/pathops/SkDCubicToQuads.cpp',
     'skia/src/pathops/SkDLineIntersection.cpp',
-    'skia/src/pathops/SkDQuadImplicit.cpp',
-    'skia/src/pathops/SkDQuadIntersection.cpp',
     'skia/src/pathops/SkDQuadLineIntersection.cpp',
     'skia/src/pathops/SkIntersections.cpp',
     'skia/src/pathops/SkOpAngle.cpp',
+    'skia/src/pathops/SkOpBuilder.cpp',
+    'skia/src/pathops/SkOpCoincidence.cpp',
     'skia/src/pathops/SkOpContour.cpp',
+    'skia/src/pathops/SkOpCubicHull.cpp',
     'skia/src/pathops/SkOpEdgeBuilder.cpp',
     'skia/src/pathops/SkOpSegment.cpp',
-    'skia/src/pathops/SkPathOpsBounds.cpp',
+    'skia/src/pathops/SkOpSpan.cpp',
     'skia/src/pathops/SkPathOpsCommon.cpp',
+    'skia/src/pathops/SkPathOpsConic.cpp',
     'skia/src/pathops/SkPathOpsCubic.cpp',
-    'skia/src/pathops/SkPathOpsDebug.cpp',
+    'skia/src/pathops/SkPathOpsCurve.cpp',
     'skia/src/pathops/SkPathOpsLine.cpp',
     'skia/src/pathops/SkPathOpsOp.cpp',
     'skia/src/pathops/SkPathOpsPoint.cpp',
     'skia/src/pathops/SkPathOpsQuad.cpp',
     'skia/src/pathops/SkPathOpsRect.cpp',
     'skia/src/pathops/SkPathOpsSimplify.cpp',
     'skia/src/pathops/SkPathOpsTightBounds.cpp',
-    'skia/src/pathops/SkPathOpsTriangle.cpp',
+    'skia/src/pathops/SkPathOpsTSect.cpp',
     'skia/src/pathops/SkPathOpsTypes.cpp',
+    'skia/src/pathops/SkPathOpsWinding.cpp',
     'skia/src/pathops/SkPathWriter.cpp',
-    'skia/src/pathops/SkQuarticRoot.cpp',
     'skia/src/pathops/SkReduceOrder.cpp',
     'skia/src/pipe/SkGPipeRead.cpp',
     'skia/src/pipe/SkGPipeWrite.cpp',
     'skia/src/ports/SkDiscardableMemory_none.cpp',
     'skia/src/ports/SkGlobalInitialization_default.cpp',
     'skia/src/ports/SkImageDecoder_empty.cpp',
+    'skia/src/ports/SkImageGenerator_skia.cpp',
     'skia/src/ports/SkMemory_mozalloc.cpp',
     'skia/src/ports/SkOSFile_stdio.cpp',
     'skia/src/sfnt/SkOTTable_name.cpp',
     'skia/src/sfnt/SkOTUtils.cpp',
+    'skia/src/utils/android/SkAndroidSDKCanvas.cpp',
     'skia/src/utils/SkBase64.cpp',
+    'skia/src/utils/SkBitmapSourceDeserializer.cpp',
     'skia/src/utils/SkBitSet.cpp',
     'skia/src/utils/SkBoundaryPatch.cpp',
     'skia/src/utils/SkCamera.cpp',
     'skia/src/utils/SkCanvasStack.cpp',
     'skia/src/utils/SkCanvasStateUtils.cpp',
     'skia/src/utils/SkCubicInterval.cpp',
     'skia/src/utils/SkCullPoints.cpp',
     'skia/src/utils/SkDashPath.cpp',
-    'skia/src/utils/SkDeferredCanvas.cpp',
     'skia/src/utils/SkDumpCanvas.cpp',
     'skia/src/utils/SkEventTracer.cpp',
     'skia/src/utils/SkFrontBufferedStream.cpp',
-    'skia/src/utils/SkGatherPixelRefsAndRects.cpp',
+    'skia/src/utils/SkImageGeneratorUtils.cpp',
     'skia/src/utils/SkInterpolator.cpp',
     'skia/src/utils/SkLayer.cpp',
     'skia/src/utils/SkMatrix22.cpp',
     'skia/src/utils/SkMatrix44.cpp',
     'skia/src/utils/SkMeshUtils.cpp',
     'skia/src/utils/SkNinePatch.cpp',
     'skia/src/utils/SkNullCanvas.cpp',
     'skia/src/utils/SkNWayCanvas.cpp',
     'skia/src/utils/SkOSFile.cpp',
+    'skia/src/utils/SkPaintFilterCanvas.cpp',
     'skia/src/utils/SkParseColor.cpp',
-    'skia/src/utils/SkParsePath.cpp',
-    'skia/src/utils/SkPathUtils.cpp',
-    'skia/src/utils/SkPictureUtils.cpp',
-    'skia/src/utils/SkProxyCanvas.cpp',
+    'skia/src/utils/SkPatchGrid.cpp',
+    'skia/src/utils/SkPatchUtils.cpp',
     'skia/src/utils/SkRTConf.cpp',
+    'skia/src/utils/SkTextBox.cpp',
     'skia/src/utils/SkTextureCompressor.cpp',
     'skia/src/utils/SkTextureCompressor_ASTC.cpp',
     'skia/src/utils/SkTextureCompressor_LATC.cpp',
     'skia/src/utils/SkTextureCompressor_R11EAC.cpp',
+    'skia/src/utils/SkWhitelistTypefaces.cpp',
 ]
 SOURCES += [
     'skia/src/core/SkAdvancedTypefaceMetrics.cpp',
     'skia/src/core/SkBitmapProcState_matrixProcs.cpp',
     'skia/src/core/SkBlitter_A8.cpp',
     'skia/src/core/SkBlitter_ARGB32.cpp',
     'skia/src/core/SkBlitter_RGB16.cpp',
     'skia/src/core/SkBlitter_Sprite.cpp',
     'skia/src/core/SkFontHost.cpp',
+    'skia/src/core/SkOpts.cpp',
     'skia/src/core/SkPictureData.cpp',
-    'skia/src/core/SkScaledImageCache.cpp',
+    'skia/src/core/SkRecorder.cpp',
     'skia/src/core/SkScan_Antihair.cpp',
-    'skia/src/gpu/GrAddPathRenderers_default.cpp',
-    'skia/src/gpu/GrDistanceFieldTextContext.cpp',
+    'skia/src/effects/SkArithmeticMode_gpu.cpp',
+    'skia/src/gpu/batches/GrAAConvexPathRenderer.cpp',
+    'skia/src/gpu/batches/GrAAConvexTessellator.cpp',
+    'skia/src/gpu/batches/GrAADistanceFieldPathRenderer.cpp',
+    'skia/src/gpu/batches/GrAAFillRectBatch.cpp',
+    'skia/src/gpu/batches/GrAAHairLinePathRenderer.cpp',
+    'skia/src/gpu/batches/GrAALinearizingConvexPathRenderer.cpp',
+    'skia/src/gpu/batches/GrAAStrokeRectBatch.cpp',
+    'skia/src/gpu/gl/builders/GrGLProgramBuilder.cpp',
+    'skia/src/gpu/gl/builders/GrGLShaderStringBuilder.cpp',
+    'skia/src/gpu/gl/builders/GrGLSLPrettyPrint.cpp',
+    'skia/src/gpu/gl/debug/GrGLCreateDebugInterface.cpp',
+    'skia/src/gpu/gl/GrGLAssembleInterface.cpp',
+    'skia/src/gpu/gl/GrGLBufferImpl.cpp',
+    'skia/src/gpu/gl/GrGLCaps.cpp',
+    'skia/src/gpu/gl/GrGLContext.cpp',
+    'skia/src/gpu/gl/GrGLCreateNativeInterface_none.cpp',
+    'skia/src/gpu/gl/GrGLCreateNullInterface.cpp',
+    'skia/src/gpu/gl/GrGLDefaultInterface_native.cpp',
+    'skia/src/gpu/gl/GrGLExtensions.cpp',
+    'skia/src/gpu/gl/GrGLGLSL.cpp',
+    'skia/src/gpu/gl/GrGLGpu.cpp',
+    'skia/src/gpu/gl/GrGLGpuProgramCache.cpp',
+    'skia/src/gpu/gl/GrGLIndexBuffer.cpp',
+    'skia/src/gpu/gl/GrGLInterface.cpp',
+    'skia/src/gpu/gl/GrGLNameAllocator.cpp',
+    'skia/src/gpu/gl/GrGLNoOpInterface.cpp',
+    'skia/src/gpu/gl/GrGLPath.cpp',
+    'skia/src/gpu/gl/GrGLPathRange.cpp',
+    'skia/src/gpu/gl/GrGLPathRendering.cpp',
+    'skia/src/gpu/gl/GrGLProgram.cpp',
+    'skia/src/gpu/gl/GrGLProgramDataManager.cpp',
+    'skia/src/gpu/gl/GrGLProgramDesc.cpp',
+    'skia/src/gpu/gl/GrGLRenderTarget.cpp',
+    'skia/src/gpu/gl/GrGLStencilAttachment.cpp',
+    'skia/src/gpu/gl/GrGLTexture.cpp',
+    'skia/src/gpu/gl/GrGLTextureRenderTarget.cpp',
+    'skia/src/gpu/gl/GrGLUtil.cpp',
+    'skia/src/gpu/gl/GrGLVaryingHandler.cpp',
+    'skia/src/gpu/gl/GrGLVertexArray.cpp',
+    'skia/src/gpu/gl/GrGLVertexBuffer.cpp',
+    'skia/src/gpu/glsl/GrGLSL.cpp',
+    'skia/src/gpu/glsl/GrGLSLBlend.cpp',
+    'skia/src/gpu/glsl/GrGLSLCaps.cpp',
+    'skia/src/gpu/glsl/GrGLSLFragmentProcessor.cpp',
+    'skia/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp',
+    'skia/src/gpu/glsl/GrGLSLGeometryProcessor.cpp',
+    'skia/src/gpu/glsl/GrGLSLGeometryShaderBuilder.cpp',
+    'skia/src/gpu/glsl/GrGLSLPrimitiveProcessor.cpp',
+    'skia/src/gpu/glsl/GrGLSLProgramBuilder.cpp',
+    'skia/src/gpu/glsl/GrGLSLShaderBuilder.cpp',
+    'skia/src/gpu/glsl/GrGLSLUtil.cpp',
+    'skia/src/gpu/glsl/GrGLSLVarying.cpp',
+    'skia/src/gpu/glsl/GrGLSLVertexShaderBuilder.cpp',
+    'skia/src/gpu/glsl/GrGLSLXferProcessor.cpp',
+    'skia/src/gpu/GrBatchAtlas.cpp',
+    'skia/src/gpu/GrDrawContext.cpp',
+    'skia/src/gpu/GrResourceCache.cpp',
+    'skia/src/image/SkImage_Gpu.cpp',
+    'skia/src/pathops/SkPathOpsDebug.cpp',
     'skia/src/utils/SkMD5.cpp',
     'skia/src/utils/SkParse.cpp',
+    'skia/src/utils/SkParsePath.cpp',
     'skia/src/utils/SkSHA1.cpp',
 ]
 if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('android', 'gonk'):
     UNIFIED_SOURCES += [
         'skia/src/ports/SkDebug_android.cpp',
         'skia/src/ports/SkOSFile_posix.cpp',
+        'skia/src/ports/SkOSLibrary_posix.cpp',
         'skia/src/ports/SkTime_Unix.cpp',
         'skia/src/ports/SkTLS_pthread.cpp',
         'skia/src/utils/SkThreadUtils_pthread.cpp',
     ]
     SOURCES += [
-        'skia/src/ports/SkFontHost_android_old.cpp',
         'skia/src/ports/SkFontHost_cairo.cpp',
-        'skia/src/ports/SkFontHost_FreeType.cpp',
         'skia/src/ports/SkFontHost_FreeType_common.cpp',
     ]
 if CONFIG['MOZ_WIDGET_TOOLKIT'] in {'cocoa', 'uikit'}:
     UNIFIED_SOURCES += [
         'skia/src/ports/SkDebug_stdio.cpp',
         'skia/src/ports/SkOSFile_posix.cpp',
+        'skia/src/ports/SkOSLibrary_posix.cpp',
         'skia/src/ports/SkTime_Unix.cpp',
         'skia/src/ports/SkTLS_pthread.cpp',
         'skia/src/utils/mac/SkCreateCGImageRef.cpp',
         'skia/src/utils/mac/SkStream_mac.cpp',
         'skia/src/utils/SkThreadUtils_pthread.cpp',
     ]
     SOURCES += [
         'skia/src/ports/SkFontHost_mac.cpp',
     ]
 if CONFIG['MOZ_WIDGET_GTK']:
     UNIFIED_SOURCES += [
         'skia/src/ports/SkDebug_stdio.cpp',
         'skia/src/ports/SkOSFile_posix.cpp',
+        'skia/src/ports/SkOSLibrary_posix.cpp',
         'skia/src/ports/SkTime_Unix.cpp',
         'skia/src/ports/SkTLS_pthread.cpp',
         'skia/src/utils/SkThreadUtils_pthread.cpp',
     ]
     SOURCES += [
         'skia/src/ports/SkFontHost_cairo.cpp',
-        'skia/src/ports/SkFontHost_FreeType.cpp',
         'skia/src/ports/SkFontHost_FreeType_common.cpp',
     ]
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'qt':
     UNIFIED_SOURCES += [
         'skia/src/ports/SkDebug_stdio.cpp',
         'skia/src/ports/SkOSFile_posix.cpp',
+        'skia/src/ports/SkOSLibrary_posix.cpp',
         'skia/src/ports/SkTime_Unix.cpp',
         'skia/src/ports/SkTLS_pthread.cpp',
         'skia/src/utils/SkThreadUtils_pthread.cpp',
     ]
     SOURCES += [
         'skia/src/ports/SkFontHost_cairo.cpp',
-        'skia/src/ports/SkFontHost_FreeType.cpp',
         'skia/src/ports/SkFontHost_FreeType_common.cpp',
     ]
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
     SOURCES += [
         'skia/src/ports/SkDebug_win.cpp',
         'skia/src/ports/SkFontHost_win.cpp',
-        'skia/src/ports/SkFontMgr_default_dw.cpp',
         'skia/src/ports/SkFontMgr_win_dw.cpp',
+        'skia/src/ports/SkFontMgr_win_dw_factory.cpp',
         'skia/src/ports/SkOSFile_win.cpp',
+        'skia/src/ports/SkOSLibrary_win.cpp',
         'skia/src/ports/SkRemotableFontMgr_win_dw.cpp',
         'skia/src/ports/SkScalerContext_win_dw.cpp',
         'skia/src/ports/SkTime_win.cpp',
         'skia/src/ports/SkTLS_win.cpp',
         'skia/src/ports/SkTypeface_win_dw.cpp',
         'skia/src/utils/SkThreadUtils_win.cpp',
         'skia/src/utils/win/SkAutoCoInitialize.cpp',
         'skia/src/utils/win/SkDWrite.cpp',
         'skia/src/utils/win/SkDWriteFontFileStream.cpp',
         'skia/src/utils/win/SkDWriteGeometrySink.cpp',
         'skia/src/utils/win/SkHRESULT.cpp',
         'skia/src/utils/win/SkIStream.cpp',
     ]
 if CONFIG['INTEL_ARCHITECTURE']:
-    UNIFIED_SOURCES += [
-        'skia/src/opts/SkTextureCompression_opts_none.cpp',
-    ]
     SOURCES += [
         'skia/src/opts/opts_check_x86.cpp',
         'skia/src/opts/SkBitmapFilter_opts_SSE2.cpp',
         'skia/src/opts/SkBitmapProcState_opts_SSE2.cpp',
         'skia/src/opts/SkBitmapProcState_opts_SSSE3.cpp',
-        'skia/src/opts/SkBlitRect_opts_SSE2.cpp',
         'skia/src/opts/SkBlitRow_opts_SSE2.cpp',
-        'skia/src/opts/SkBlurImage_opts_SSE2.cpp',
-        'skia/src/opts/SkBlurImage_opts_SSE4.cpp',
-        'skia/src/opts/SkMorphology_opts_SSE2.cpp',
-        'skia/src/opts/SkUtils_opts_SSE2.cpp',
-        'skia/src/opts/SkXfermode_opts_SSE2.cpp',
+        'skia/src/opts/SkBlitRow_opts_SSE4.cpp',
+        'skia/src/opts/SkOpts_avx.cpp',
+        'skia/src/opts/SkOpts_sse41.cpp',
+        'skia/src/opts/SkOpts_ssse3.cpp',
     ]
 elif CONFIG['CPU_ARCH'] == 'arm' and CONFIG['GNU_CC']:
     UNIFIED_SOURCES += [
         'skia/src/core/SkUtilsArm.cpp',
         'skia/src/opts/SkBitmapProcState_opts_arm.cpp',
         'skia/src/opts/SkBlitMask_opts_arm.cpp',
-        'skia/src/opts/SkBlurImage_opts_arm.cpp',
-        'skia/src/opts/SkMorphology_opts_arm.cpp',
-        'skia/src/opts/SkTextureCompression_opts_arm.cpp',
-        'skia/src/opts/SkUtils_opts_arm.cpp',
-        'skia/src/opts/SkXfermode_opts_arm.cpp',
     ]
     SOURCES += [
         'skia/src/opts/SkBlitRow_opts_arm.cpp',
     ]
     if CONFIG['BUILD_ARM_NEON']:
         SOURCES += [
             'skia/src/opts/SkBitmapProcState_arm_neon.cpp',
             'skia/src/opts/SkBitmapProcState_matrixProcs_neon.cpp',
             'skia/src/opts/SkBlitMask_opts_arm_neon.cpp',
             'skia/src/opts/SkBlitRow_opts_arm_neon.cpp',
-            'skia/src/opts/SkBlurImage_opts_neon.cpp',
-            'skia/src/opts/SkMorphology_opts_neon.cpp',
-            'skia/src/opts/SkTextureCompression_opts_neon.cpp',
-            'skia/src/opts/SkXfermode_opts_arm_neon.cpp',
+            'skia/src/opts/SkOpts_neon.cpp',
         ]
         SOURCES['skia/src/opts/SkBitmapProcState_arm_neon.cpp'].flags += ['-mfpu=neon']
         SOURCES['skia/src/opts/SkBitmapProcState_matrixProcs_neon.cpp'].flags += ['-mfpu=neon']
         SOURCES['skia/src/opts/SkBlitMask_opts_arm_neon.cpp'].flags += ['-mfpu=neon']
         SOURCES['skia/src/opts/SkBlitRow_opts_arm_neon.cpp'].flags += ['-mfpu=neon']
-        SOURCES['skia/src/opts/SkBlurImage_opts_neon.cpp'].flags += ['-mfpu=neon']
-        SOURCES['skia/src/opts/SkMorphology_opts_neon.cpp'].flags += ['-mfpu=neon']
-        SOURCES['skia/src/opts/SkTextureCompression_opts_neon.cpp'].flags += ['-mfpu=neon']
-        SOURCES['skia/src/opts/SkXfermode_opts_arm_neon.cpp'].flags += ['-mfpu=neon']
+        SOURCES['skia/src/opts/SkOpts_neon.cpp'].flags += ['-mfpu=neon']
 else:
     UNIFIED_SOURCES += [
         'skia/src/opts/SkBitmapProcState_opts_none.cpp',
         'skia/src/opts/SkBlitMask_opts_none.cpp',
         'skia/src/opts/SkBlitRow_opts_none.cpp',
-        'skia/src/opts/SkBlurImage_opts_none.cpp',
-        'skia/src/opts/SkMorphology_opts_none.cpp',
-        'skia/src/opts/SkTextureCompression_opts_none.cpp',
-        'skia/src/opts/SkUtils_opts_none.cpp',
-        'skia/src/opts/SkXfermode_opts_none.cpp',
     ]
 
 
-# can we find a better way of dealing with asm sources?
-
-# left out of UNIFIED_SOURCES for now; that's not C++ anyway, nothing else to unify it with
-#XXX: doesn't build with Apple's assembler
-if not CONFIG['INTEL_ARCHITECTURE'] and CONFIG['CPU_ARCH'] == 'arm' and CONFIG['GNU_CC'] and CONFIG['OS_TARGET'] != 'Darwin':
-    SOURCES += [
-        'skia/src/opts/memset.arm.S',
-    ]
-    if CONFIG['BUILD_ARM_NEON']:
-        SOURCES += [
-            'skia/src/opts/memset16_neon.S',
-            'skia/src/opts/memset32_neon.S',
-        ]
-
-if CONFIG['INTEL_ARCHITECTURE'] and CONFIG['GNU_CC'] and CONFIG['OS_ARCH'] != 'WINNT':
-    if CONFIG['CPU_ARCH'] == 'x86_64':
-        SOURCES += [
-            'skia/src/opts/SkBlitRow_opts_SSE4_x64_asm.S',
-        ]
-    else:
-        SOURCES += [
-            'skia/src/opts/SkBlitRow_opts_SSE4_asm.S',
-        ]
-
 # We allow warnings for third-party code that can be updated from upstream.
 ALLOW_COMPILER_WARNINGS = True
 
 FINAL_LIBRARY = 'gkmedias'
 LOCAL_INCLUDES += [
+    'skia/include/c',
     'skia/include/config',
     'skia/include/core',
     'skia/include/effects',
     'skia/include/gpu',
     'skia/include/images',
     'skia/include/pathops',
     'skia/include/pipe',
     'skia/include/ports',
+    'skia/include/private',
     'skia/include/utils',
     'skia/include/utils/mac',
     'skia/include/utils/win',
     'skia/include/views',
     'skia/src/core',
     'skia/src/gpu',
     'skia/src/gpu/effects',
     'skia/src/gpu/gl',
@@ -608,79 +663,77 @@ LOCAL_INCLUDES += [
     'skia/src/lazy',
     'skia/src/opts',
     'skia/src/sfnt',
     'skia/src/utils',
     'skia/src/utils/mac',
     'skia/src/utils/win',
 ]
 
-if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('android', 'gtk2', 'gtk3', 'qt', 'gonk', 'cocoa', 'uikit'):
-    DEFINES['SK_USE_POSIX_THREADS'] = 1
-
-if CONFIG['INTEL_ARCHITECTURE'] and CONFIG['HAVE_TOOLCHAIN_SUPPORT_MSSSE3']:
-    DEFINES['SK_BUILD_SSSE3'] = 1
-
 if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('android', 'gonk'):
     DEFINES['SK_FONTHOST_CAIRO_STANDALONE'] = 0
 
-if (CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android') or    (CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa') or (CONFIG['MOZ_WIDGET_TOOLKIT'] == 'uikit') or    (CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk') or    (CONFIG['MOZ_WIDGET_TOOLKIT'] == 'qt') or    CONFIG['MOZ_WIDGET_GTK']:
+if CONFIG['MOZ_WIDGET_TOOLKIT'] in {
+    'android',
+    'cocoa',
+    'uikit',
+    'gonk',
+    'qt',
+  } or CONFIG['MOZ_WIDGET_GTK']:
     DEFINES['SK_FONTHOST_DOES_NOT_USE_FONTMGR'] = 1
 
 # We should autogenerate these SSE related flags.
 
 if CONFIG['_MSC_VER']:
     # MSVC doesn't need special compiler flags, but Skia needs to be told that these files should
     # be built with the required SSE level or it will simply compile in stubs and cause runtime crashes
-    SOURCES['skia/src/opts/SkBitmapFilter_opts_SSE2.cpp'].flags += ['-DSK_CPU_SSE_LEVEL=20']
-    SOURCES['skia/src/opts/SkBitmapProcState_opts_SSE2.cpp'].flags += ['-DSK_CPU_SSE_LEVEL=20']
-    SOURCES['skia/src/opts/SkBitmapProcState_opts_SSSE3.cpp'].flags += ['-DSK_CPU_SSE_LEVEL=31']
-    SOURCES['skia/src/opts/SkBlitRect_opts_SSE2.cpp'].flags += ['-DSK_CPU_SSE_LEVEL=20']
-    SOURCES['skia/src/opts/SkBlitRow_opts_SSE2.cpp'].flags += ['-DSK_CPU_SSE_LEVEL=20']
-    SOURCES['skia/src/opts/SkBlurImage_opts_SSE2.cpp'].flags += ['-DSK_CPU_SSE_LEVEL=20']
-    SOURCES['skia/src/opts/SkBlurImage_opts_SSE4.cpp'].flags += ['-DSK_CPU_SSE_LEVEL=41']
-    SOURCES['skia/src/opts/SkMorphology_opts_SSE2.cpp'].flags += ['-DSK_CPU_SSE_LEVEL=20']
-    SOURCES['skia/src/opts/SkUtils_opts_SSE2.cpp'].flags += ['-DSK_CPU_SSE_LEVEL=20']
-    SOURCES['skia/src/opts/SkXfermode_opts_SSE2.cpp'].flags += ['-DSK_CPU_SSE_LEVEL=20']
-
+    SOURCES['skia/src/opts/SkBitmapFilter_opts_SSE2.cpp'].flags += ['/arch:SSE2 -DSK_CPU_SSE_LEVEL=20']
+    SOURCES['skia/src/opts/SkBitmapProcState_opts_SSE2.cpp'].flags += ['/arch:SSE2 -DSK_CPU_SSE_LEVEL=20']
+    SOURCES['skia/src/opts/SkBitmapProcState_opts_SSSE3.cpp'].flags += ['/arch:SSE2 -DSK_CPU_SSE_LEVEL=31']
+    SOURCES['skia/src/opts/SkBlitRow_opts_SSE2.cpp'].flags += ['/arch:SSE2 -DSK_CPU_SSE_LEVEL=20']
+    SOURCES['skia/src/opts/SkBlitRow_opts_SSE4.cpp'].flags += ['/arch:SSE2 -DSK_CPU_SSE_LEVEL=41']
+    SOURCES['skia/src/opts/SkOpts_ssse3.cpp'].flags += ['/arch:SSE2 -DSK_CPU_SSE_LEVEL=31']
+    SOURCES['skia/src/opts/SkOpts_sse41.cpp'].flags += ['/arch:SSE2 -DSK_CPU_SSE_LEVEL=41']
+    SOURCES['skia/src/opts/SkOpts_avx.cpp'].flags += ['/arch:AVX -DSK_CPU_SSE_LEVEL=51']
 if CONFIG['INTEL_ARCHITECTURE'] and CONFIG['GNU_CC']:
     SOURCES['skia/src/opts/SkBitmapFilter_opts_SSE2.cpp'].flags += CONFIG['SSE2_FLAGS']
     SOURCES['skia/src/opts/SkBitmapProcState_opts_SSE2.cpp'].flags += CONFIG['SSE2_FLAGS']
     SOURCES['skia/src/opts/SkBitmapProcState_opts_SSSE3.cpp'].flags += ['-mssse3']
-    SOURCES['skia/src/opts/SkBlitRect_opts_SSE2.cpp'].flags += CONFIG['SSE2_FLAGS']
     SOURCES['skia/src/opts/SkBlitRow_opts_SSE2.cpp'].flags += CONFIG['SSE2_FLAGS']
-    SOURCES['skia/src/opts/SkBlurImage_opts_SSE2.cpp'].flags += CONFIG['SSE2_FLAGS']
-    SOURCES['skia/src/opts/SkBlurImage_opts_SSE4.cpp'].flags += ['-msse4.1']
-    SOURCES['skia/src/opts/SkMorphology_opts_SSE2.cpp'].flags += CONFIG['SSE2_FLAGS']
-    SOURCES['skia/src/opts/SkUtils_opts_SSE2.cpp'].flags += CONFIG['SSE2_FLAGS']
-    SOURCES['skia/src/opts/SkXfermode_opts_SSE2.cpp'].flags += CONFIG['SSE2_FLAGS']
+    SOURCES['skia/src/opts/SkBlitRow_opts_SSE4.cpp'].flags += ['-msse4.1']
+    SOURCES['skia/src/opts/SkOpts_ssse3.cpp'].flags += ['-mssse3']
+    SOURCES['skia/src/opts/SkOpts_sse41.cpp'].flags += ['-msse4.1']
+    SOURCES['skia/src/opts/SkOpts_avx.cpp'].flags += ['-mavx']
 elif CONFIG['CPU_ARCH'] == 'arm' and CONFIG['GNU_CC'] and CONFIG['BUILD_ARM_NEON']:
-    DEFINES['__ARM_HAVE_OPTIONAL_NEON_SUPPORT'] = 1
-    DEFINES['USE_ANDROID_NDK_CPU_FEATURES'] = 0
+    DEFINES['SK_ARM_HAS_OPTIONAL_NEON'] = 1
 elif CONFIG['CLANG_CL']:
     SOURCES['skia/src/opts/SkBitmapProcState_opts_SSSE3.cpp'].flags += ['-mssse3']
-    SOURCES['skia/src/opts/SkBlurImage_opts_SSE4.cpp'].flags += ['-msse4.1']
+    SOURCES['skia/src/opts/SkBlitRow_opts_SSE4.cpp'].flags += ['-msse4.1']
+    SOURCES['skia/src/opts/SkOpts_ssse3.cpp'].flags += ['-mssse3']
+    SOURCES['skia/src/opts/SkOpts_sse41.cpp'].flags += ['-msse4.1']
+    SOURCES['skia/src/opts/SkOpts_avx.cpp'].flags += ['-mavx']
 
 DEFINES['SKIA_IMPLEMENTATION'] = 1
-DEFINES['GR_IMPLEMENTATION'] = 1
 
 if CONFIG['GNU_CXX']:
     CXXFLAGS += [
         '-Wno-deprecated-declarations',
         '-Wno-overloaded-virtual',
         '-Wno-sign-compare',
         '-Wno-unused-function',
     ]
     if CONFIG['CLANG_CXX']:
         CXXFLAGS += [
             '-Wno-implicit-fallthrough',
             '-Wno-inconsistent-missing-override',
             '-Wno-macro-redefined',
             '-Wno-unused-private-field',
         ]
+        # work around inline function linking bug with template arguments
+        SOURCES['skia/src/gpu/GrResourceCache.cpp'].flags += ['-fkeep-inline-functions']
     else:
         CXXFLAGS += [
             '-Wno-logical-op',
             '-Wno-maybe-uninitialized',
         ]
     if CONFIG['CPU_ARCH'] == 'arm':
         SOURCES['skia/src/opts/SkBlitRow_opts_arm.cpp'].flags += ['-fomit-frame-pointer']
 
new file mode 100644
--- /dev/null
+++ b/gfx/skia/skia/include/android/SkBRDAllocator.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkBRDAllocator_DEFINED
+#define SkBRDAllocator_DEFINED
+
+#include "SkBitmap.h"
+#include "SkCodec.h"
+
+/**
+ *  Abstract subclass of SkBitmap's allocator.
+ *  Allows the allocator to indicate if the memory it allocates
+ *  is zero initialized.
+ */
+class SkBRDAllocator : public SkBitmap::Allocator {
+public:
+
+    /**
+     *  Indicates if the memory allocated by this allocator is
+     *  zero initialized.
+     */
+    virtual SkCodec::ZeroInitialized zeroInit() const = 0;
+};
+
+#endif // SkBRDAllocator_DEFINED
new file mode 100644
--- /dev/null
+++ b/gfx/skia/skia/include/android/SkBitmapRegionDecoder.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkBitmapRegionDecoder_DEFINED
+#define SkBitmapRegionDecoder_DEFINED
+
+#include "SkBitmap.h"
+#include "SkBRDAllocator.h"
+#include "SkEncodedFormat.h"
+#include "SkStream.h"
+
+/*
+ * This class aims to provide an interface to test multiple implementations of
+ * SkBitmapRegionDecoder.
+ */
+class SkBitmapRegionDecoder {
+public:
+
+    enum Strategy {
+        kCanvas_Strategy,       // Draw to the canvas, uses SkCodec
+        kAndroidCodec_Strategy, // Uses SkAndroidCodec for scaling and subsetting
+    };
+
+    /*
+     * @param data     Refs the data while this object exists, unrefs on destruction
+     * @param strategy Strategy used for scaling and subsetting
+     * @return         Tries to create an SkBitmapRegionDecoder, returns NULL on failure
+     */
+    static SkBitmapRegionDecoder* Create(
+            SkData* data, Strategy strategy);
+
+    /*
+     * @param stream   Takes ownership of the stream
+     * @param strategy Strategy used for scaling and subsetting
+     * @return         Tries to create an SkBitmapRegionDecoder, returns NULL on failure
+     */
+    static SkBitmapRegionDecoder* Create(
+            SkStreamRewindable* stream, Strategy strategy);
+
+    /*
+     * Decode a scaled region of the encoded image stream
+     *
+     * @param bitmap          Container for decoded pixels.  It is assumed that the pixels
+     *                        are initially unallocated and will be allocated by this function.
+     * @param allocator       Allocator for the pixels.  If this is NULL, the default
+     *                        allocator (HeapAllocator) will be used.
+     * @param desiredSubset   Subset of the original image to decode.
+     * @param sampleSize      An integer downscaling factor for the decode.
+     * @param colorType       Preferred output colorType.
+     *                        New implementations should return NULL if they do not support
+     *                        decoding to this color type.
+     *                        The old kOriginal_Strategy will decode to a default color type
+     *                        if this color type is unsupported.
+     * @param requireUnpremul If the image is not opaque, we will use this to determine the
+     *                        alpha type to use.
+     *
+     */
+    virtual bool decodeRegion(SkBitmap* bitmap, SkBRDAllocator* allocator,
+                              const SkIRect& desiredSubset, int sampleSize,
+                              SkColorType colorType, bool requireUnpremul) = 0;
+    /*
+     * @param  Requested destination color type
+     * @return true if we support the requested color type and false otherwise
+     */
+    virtual bool conversionSupported(SkColorType colorType) = 0;
+
+    virtual SkEncodedFormat getEncodedFormat() = 0;
+
+    int width() const { return fWidth; }
+    int height() const { return fHeight; }
+
+    virtual ~SkBitmapRegionDecoder() {}
+
+protected:
+
+    SkBitmapRegionDecoder(int width, int height)
+        : fWidth(width)
+        , fHeight(height)
+    {}
+
+private:
+    const int fWidth;
+    const int fHeight;
+};
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/skia/skia/include/c/sk_canvas.h
@@ -0,0 +1,154 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+// EXPERIMENTAL EXPERIMENTAL EXPERIMENTAL EXPERIMENTAL
+// DO NOT USE -- FOR INTERNAL TESTING ONLY
+
+#ifndef sk_canvas_DEFINED
+#define sk_canvas_DEFINED
+
+#include "sk_types.h"
+
+SK_C_PLUS_PLUS_BEGIN_GUARD
+
+/**
+    Save the current matrix and clip on the canvas.  When the
+    balancing call to sk_canvas_restore() is made, the previous matrix
+    and clip are restored.
+*/
+SK_API void sk_canvas_save(sk_canvas_t*);
+/**
+    This behaves the same as sk_canvas_save(), but in addition it
+    allocates an offscreen surface. All drawing calls are directed
+    there, and only when the balancing call to sk_canvas_restore() is
+    made is that offscreen transfered to the canvas (or the previous
+    layer).
+
+    @param sk_rect_t* (may be null) This rect, if non-null, is used as
+                      a hint to limit the size of the offscreen, and
+                      thus drawing may be clipped to it, though that
+                      clipping is not guaranteed to happen. If exact
+                      clipping is desired, use sk_canvas_clip_rect().
+    @param sk_paint_t* (may be null) The paint is copied, and is applied
+                       to the offscreen when sk_canvas_restore() is
+                       called.
+*/
+SK_API void sk_canvas_save_layer(sk_canvas_t*, const sk_rect_t*, const sk_paint_t*);
+/**
+    This call balances a previous call to sk_canvas_save() or
+    sk_canvas_save_layer(), and is used to remove all modifications to
+    the matrix and clip state since the last save call.  It is an
+    error to call sk_canvas_restore() more times than save and
+    save_layer were called.
+*/
+SK_API void sk_canvas_restore(sk_canvas_t*);
+
+/**
+    Preconcat the current coordinate transformation matrix with the
+    specified translation.
+*/
+SK_API void sk_canvas_translate(sk_canvas_t*, float dx, float dy);
+/**
+    Preconcat the current coordinate transformation matrix with the
+    specified scale.
+*/
+SK_API void sk_canvas_scale(sk_canvas_t*, float sx, float sy);
+/**
+    Preconcat the current coordinate transformation matrix with the
+    specified rotation in degrees.
+*/
+SK_API void sk_canvas_rotate_degrees(sk_canvas_t*, float degrees);
+/**
+    Preconcat the current coordinate transformation matrix with the
+    specified rotation in radians.
+*/
+SK_API void sk_canvas_rotate_radians(sk_canvas_t*, float radians);
+/**
+    Preconcat the current coordinate transformation matrix with the
+    specified skew.
+*/
+SK_API void sk_canvas_skew(sk_canvas_t*, float sx, float sy);
+/**
+    Preconcat the current coordinate transformation matrix with the
+    specified matrix.
+*/
+SK_API void sk_canvas_concat(sk_canvas_t*, const sk_matrix_t*);
+
+/**
+    Modify the current clip with the specified rectangle.  The new
+    current clip will be the intersection of the old clip and the
+    rectange.
+*/
+SK_API void sk_canvas_clip_rect(sk_canvas_t*, const sk_rect_t*);
+/**
+    Modify the current clip with the specified path.  The new
+    current clip will be the intersection of the old clip and the
+    path.
+*/
+SK_API void sk_canvas_clip_path(sk_canvas_t*, const sk_path_t*);
+
+/**
+    Fill the entire canvas (restricted to the current clip) with the
+    specified paint.
+*/
+SK_API void sk_canvas_draw_paint(sk_canvas_t*, const sk_paint_t*);
+/**
+    Draw the specified rectangle using the specified paint. The
+    rectangle will be filled or stroked based on the style in the
+    paint.
+*/
+SK_API void sk_canvas_draw_rect(sk_canvas_t*, const sk_rect_t*, const sk_paint_t*);
+/**
+    Draw the specified oval using the specified paint. The oval will be
+    filled or framed based on the style in the paint
+*/
+SK_API void sk_canvas_draw_oval(sk_canvas_t*, const sk_rect_t*, const sk_paint_t*);
+/**
+    Draw the specified path using the specified paint. The path will be
+    filled or framed based on the style in the paint
+*/
+SK_API void sk_canvas_draw_path(sk_canvas_t*, const sk_path_t*, const sk_paint_t*);
+/**
+    Draw the specified image, with its top/left corner at (x,y), using
+    the specified paint, transformed by the current matrix.
+
+    @param sk_paint_t* (may be NULL) the paint used to draw the image.
+*/
+SK_API void sk_canvas_draw_image(sk_canvas_t*, const sk_image_t*,
+                                 float x, float y, const sk_paint_t*);
+/**
+    Draw the specified image, scaling and translating so that it fills
+    the specified dst rect. If the src rect is non-null, only that
+    subset of the image is transformed and drawn.
+
+    @param sk_paint_t* (may be NULL) The paint used to draw the image.
+*/
+SK_API void sk_canvas_draw_image_rect(sk_canvas_t*, const sk_image_t*,
+                                      const sk_rect_t* src,
+                                      const sk_rect_t* dst, const sk_paint_t*);
+
+/**
+    Draw the picture into this canvas (replay the pciture's drawing commands).
+
+    @param sk_matrix_t* If non-null, apply that matrix to the CTM when
+                        drawing this picture. This is logically
+                        equivalent to: save, concat, draw_picture,
+                        restore.
+
+    @param sk_paint_t* If non-null, draw the picture into a temporary
+                       buffer, and then apply the paint's alpha,
+                       colorfilter, imagefilter, and xfermode to that
+                       buffer as it is drawn to the canvas.  This is
+                       logically equivalent to save_layer(paint),
+                       draw_picture, restore.
+*/
+SK_API void sk_canvas_draw_picture(sk_canvas_t*, const sk_picture_t*,
+                                   const sk_matrix_t*, const sk_paint_t*);
+
+SK_C_PLUS_PLUS_END_GUARD
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/skia/skia/include/c/sk_data.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+// EXPERIMENTAL EXPERIMENTAL EXPERIMENTAL EXPERIMENTAL
+// DO NOT USE -- FOR INTERNAL TESTING ONLY
+
+#ifndef sk_data_DEFINED
+#define sk_data_DEFINED
+
+#include "sk_types.h"
+
+SK_C_PLUS_PLUS_BEGIN_GUARD
+
+/**
+    Returns a new empty sk_data_t.  This call must be balanced with a call to
+    sk_data_unref().
+*/
+SK_API sk_data_t* sk_data_new_empty();
+/**
+    Returns a new sk_data_t by copying the specified source data.
+    This call must be balanced with a call to sk_data_unref().
+*/
+SK_API sk_data_t* sk_data_new_with_copy(const void* src, size_t length);
+/**
+    Pass ownership of the given memory to a new sk_data_t, which will
+    call free() when the refernce count of the data goes to zero.  For
+    example:
+        size_t length = 1024;
+        void* buffer = malloc(length);
+        memset(buffer, 'X', length);
+        sk_data_t* data = sk_data_new_from_malloc(buffer, length);
+    This call must be balanced with a call to sk_data_unref().
+*/
+SK_API sk_data_t* sk_data_new_from_malloc(const void* memory, size_t length);
+/**
+    Returns a new sk_data_t using a subset of the data in the
+    specified source sk_data_t.  This call must be balanced with a
+    call to sk_data_unref().
+*/
+SK_API sk_data_t* sk_data_new_subset(const sk_data_t* src, size_t offset, size_t length);
+
+/**
+    Increment the reference count on the given sk_data_t. Must be
+    balanced by a call to sk_data_unref().
+*/
+SK_API void sk_data_ref(const sk_data_t*);
+/**
+    Decrement the reference count. If the reference count is 1 before
+    the decrement, then release both the memory holding the sk_data_t
+    and the memory it is managing.  New sk_data_t are created with a
+    reference count of 1.
+*/
+SK_API void sk_data_unref(const sk_data_t*);
+
+/**
+    Returns the number of bytes stored.
+*/
+SK_API size_t sk_data_get_size(const sk_data_t*);
+/**
+    Returns the pointer to the data.
+ */
+SK_API const void* sk_data_get_data(const sk_data_t*);
+
+SK_C_PLUS_PLUS_END_GUARD
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/skia/skia/include/c/sk_image.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+// EXPERIMENTAL EXPERIMENTAL EXPERIMENTAL EXPERIMENTAL
+// DO NOT USE -- FOR INTERNAL TESTING ONLY
+
+#ifndef sk_image_DEFINED
+#define sk_image_DEFINED
+
+#include "sk_types.h"
+
+SK_C_PLUS_PLUS_BEGIN_GUARD
+
+/**
+ *  Return a new image that has made a copy of the provided pixels, or NULL on failure.
+ *  Balance with a call to sk_image_unref().
+ */
+SK_API sk_image_t* sk_image_new_raster_copy(const sk_imageinfo_t*, const void* pixels, size_t rowBytes);
+
+/**
+ *  If the specified data can be interpreted as a compressed image (e.g. PNG or JPEG) then this
+ *  returns an image. If the encoded data is not supported, returns NULL.
+ *
+ *  On success, the encoded data may be processed immediately, or it may be ref()'d for later
+ *  use.
+ */
+SK_API sk_image_t* sk_image_new_from_encoded(const sk_data_t* encoded, const sk_irect_t* subset);
+
+/**
+ *  Encode the image's pixels and return the result as a new PNG in a
+ *  sk_data_t, which the caller must manage: call sk_data_unref() when
+ *  they are done.
+ *
+ *  If the image type cannot be encoded, this will return NULL.
+ */
+SK_API sk_data_t* sk_image_encode(const sk_image_t*);
+
+/**
+ *  Increment the reference count on the given sk_image_t. Must be
+ *  balanced by a call to sk_image_unref().
+*/
+SK_API void sk_image_ref(const sk_image_t*);
+/**
+ *  Decrement the reference count. If the reference count is 1 before
+ *  the decrement, then release both the memory holding the sk_image_t
+ *  and the memory it is managing.  New sk_image_t are created with a
+    reference count of 1.
+*/
+SK_API void sk_image_unref(const sk_image_t*);
+
+/**
+ *  Return the width of the sk_image_t/
+ */
+SK_API int sk_image_get_width(const sk_image_t*);
+/**
+ *  Return the height of the sk_image_t/
+ */
+SK_API int sk_image_get_height(const sk_image_t*);
+
+/**
+ *  Returns a non-zero value unique among all images.
+ */
+SK_API uint32_t sk_image_get_unique_id(const sk_image_t*);
+
+SK_C_PLUS_PLUS_END_GUARD
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/skia/skia/include/c/sk_maskfilter.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+// EXPERIMENTAL EXPERIMENTAL EXPERIMENTAL EXPERIMENTAL
+// DO NOT USE -- FOR INTERNAL TESTING ONLY
+
+#ifndef sk_maskfilter_DEFINED
+#define sk_maskfilter_DEFINED
+
+#include "sk_types.h"
+
+typedef enum {
+    NORMAL_SK_BLUR_STYLE,   //!< fuzzy inside and outside
+    SOLID_SK_BLUR_STYLE,    //!< solid inside, fuzzy outside
+    OUTER_SK_BLUR_STYLE,    //!< nothing inside, fuzzy outside
+    INNER_SK_BLUR_STYLE,    //!< fuzzy inside, nothing outside
+} sk_blurstyle_t;
+
+SK_C_PLUS_PLUS_BEGIN_GUARD
+
+/**
+    Increment the reference count on the given sk_maskfilter_t. Must be
+    balanced by a call to sk_maskfilter_unref().
+*/
+void sk_maskfilter_ref(sk_maskfilter_t*);
+/**
+    Decrement the reference count. If the reference count is 1 before
+    the decrement, then release both the memory holding the
+    sk_maskfilter_t and any other associated resources.  New
+    sk_maskfilter_t are created with a reference count of 1.
+*/
+void sk_maskfilter_unref(sk_maskfilter_t*);
+
+/**
+    Create a blur maskfilter.
+    @param sk_blurstyle_t The SkBlurStyle to use
+    @param sigma Standard deviation of the Gaussian blur to apply. Must be > 0.
+*/
+sk_maskfilter_t* sk_maskfilter_new_blur(sk_blurstyle_t, float sigma);
+
+SK_C_PLUS_PLUS_END_GUARD
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/skia/skia/include/c/sk_matrix.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+// EXPERIMENTAL EXPERIMENTAL EXPERIMENTAL EXPERIMENTAL
+// DO NOT USE -- FOR INTERNAL TESTING ONLY
+
+#ifndef sk_matrix_DEFINED
+#define sk_matrix_DEFINED
+
+#include "sk_types.h"
+
+SK_C_PLUS_PLUS_BEGIN_GUARD
+
+/** Set the matrix to identity */
+void sk_matrix_set_identity(sk_matrix_t*);
+
+/** Set the matrix to translate by (tx, ty). */
+void sk_matrix_set_translate(sk_matrix_t*, float tx, float ty);
+/**
+    Preconcats the matrix with the specified translation.
+        M' = M * T(dx, dy)
+*/
+void sk_matrix_pre_translate(sk_matrix_t*, float tx, float ty);
+/**
+    Postconcats the matrix with the specified translation.
+        M' = T(dx, dy) * M
+*/
+void sk_matrix_post_translate(sk_matrix_t*, float tx, float ty);
+
+/** Set the matrix to scale by sx and sy. */
+void sk_matrix_set_scale(sk_matrix_t*, float sx, float sy);
+/**
+    Preconcats the matrix with the specified scale.
+        M' = M * S(sx, sy)
+*/
+void sk_matrix_pre_scale(sk_matrix_t*, float sx, float sy);
+/**
+    Postconcats the matrix with the specified scale.
+        M' = S(sx, sy) * M
+*/
+void sk_matrix_post_scale(sk_matrix_t*, float sx, float sy);
+
+SK_C_PLUS_PLUS_END_GUARD
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/skia/skia/include/c/sk_paint.h
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+// EXPERIMENTAL EXPERIMENTAL EXPERIMENTAL EXPERIMENTAL
+// DO NOT USE -- FOR INTERNAL TESTING ONLY
+
+#ifndef sk_paint_DEFINED
+#define sk_paint_DEFINED
+
+#include "sk_types.h"
+
+SK_C_PLUS_PLUS_BEGIN_GUARD
+
+/**
+    Create a new paint with default settings:
+        antialias : false
+        stroke : false
+        stroke width : 0.0f (hairline)
+        stroke miter : 4.0f
+        stroke cap : BUTT_SK_STROKE_CAP
+        stroke join : MITER_SK_STROKE_JOIN
+        color : opaque black
+        shader : NULL
+        maskfilter : NULL
+        xfermode_mode : SRCOVER_SK_XFERMODE_MODE
+*/
+SK_API sk_paint_t* sk_paint_new();
+/**
+    Release the memory storing the sk_paint_t and unref() all
+    associated objects.
+*/
+SK_API void sk_paint_delete(sk_paint_t*);
+
+/**
+    Return true iff the paint has antialiasing enabled.
+*/
+SK_API bool sk_paint_is_antialias(const sk_paint_t*);
+/**
+    Set to true to enable antialiasing, false to disable it on this
+    sk_paint_t.
+*/
+SK_API void sk_paint_set_antialias(sk_paint_t*, bool);
+
+/**
+    Return the paint's curent drawing color.
+*/
+SK_API sk_color_t sk_paint_get_color(const sk_paint_t*);
+/**
+    Set the paint's curent drawing color.
+*/
+SK_API void sk_paint_set_color(sk_paint_t*, sk_color_t);
+
+/* stroke settings */
+
+/**
+    Return true iff stroking is enabled rather than filling on this
+    sk_paint_t.
+*/
+SK_API bool sk_paint_is_stroke(const sk_paint_t*);
+/**
+    Set to true to enable stroking rather than filling with this
+    sk_paint_t.
+*/
+SK_API void sk_paint_set_stroke(sk_paint_t*, bool);
+
+/**
+    Return the width for stroking.  A value of 0 strokes in hairline mode.
+ */
+SK_API float sk_paint_get_stroke_width(const sk_paint_t*);
+/**
+   Set the width for stroking.  A value of 0 strokes in hairline mode
+   (always draw 1-pixel wide, regardless of the matrix).
+ */
+SK_API void sk_paint_set_stroke_width(sk_paint_t*, float width);
+
+/**
+    Return the paint's stroke miter value. This is used to control the
+    behavior of miter joins when the joins angle is sharp.
+*/
+SK_API float sk_paint_get_stroke_miter(const sk_paint_t*);
+/**
+   Set the paint's stroke miter value. This is used to control the
+   behavior of miter joins when the joins angle is sharp. This value
+   must be >= 0.
+*/
+SK_API void sk_paint_set_stroke_miter(sk_paint_t*, float miter);
+
+typedef enum {
+    BUTT_SK_STROKE_CAP,
+    ROUND_SK_STROKE_CAP,
+    SQUARE_SK_STROKE_CAP
+} sk_stroke_cap_t;
+
+/**
+    Return the paint's stroke cap type, controlling how the start and
+    end of stroked lines and paths are treated.
+*/
+SK_API sk_stroke_cap_t sk_paint_get_stroke_cap(const sk_paint_t*);
+/**
+    Set the paint's stroke cap type, controlling how the start and
+    end of stroked lines and paths are treated.
+*/
+SK_API void sk_paint_set_stroke_cap(sk_paint_t*, sk_stroke_cap_t);
+
+typedef enum {
+    MITER_SK_STROKE_JOIN,
+    ROUND_SK_STROKE_JOIN,
+    BEVEL_SK_STROKE_JOIN
+} sk_stroke_join_t;
+
+/**
+    Return the paint's stroke join type, specifies the treatment that
+    is applied to corners in paths and rectangles
+ */
+SK_API sk_stroke_join_t sk_paint_get_stroke_join(const sk_paint_t*);
+/**
+    Set the paint's stroke join type, specifies the treatment that
+    is applied to corners in paths and rectangles
+ */
+SK_API void sk_paint_set_stroke_join(sk_paint_t*, sk_stroke_join_t);
+
+/**
+ *  Set the paint's shader to the specified parameter. This will automatically call unref() on
+ *  any previous value, and call ref() on the new value.
+ */
+SK_API void sk_paint_set_shader(sk_paint_t*, sk_shader_t*);
+
+/**
+ *  Set the paint's maskfilter to the specified parameter. This will automatically call unref() on
+ *  any previous value, and call ref() on the new value.
+ */
+SK_API void sk_paint_set_maskfilter(sk_paint_t*, sk_maskfilter_t*);
+
+/**
+ *  Set the paint's xfermode to the specified parameter.
+ */
+SK_API void sk_paint_set_xfermode_mode(sk_paint_t*, sk_xfermode_mode_t);
+
+SK_C_PLUS_PLUS_END_GUARD
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/skia/skia/include/c/sk_path.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+// EXPERIMENTAL EXPERIMENTAL EXPERIMENTAL EXPERIMENTAL
+// DO NOT USE -- FOR INTERNAL TESTING ONLY
+
+#ifndef sk_path_DEFINED
+#define sk_path_DEFINED
+
+#include "sk_types.h"
+
+SK_C_PLUS_PLUS_BEGIN_GUARD
+
+typedef enum {
+    CW_SK_PATH_DIRECTION,
+    CCW_SK_PATH_DIRECTION,
+} sk_path_direction_t;
+
+/** Create a new, empty path. */
+SK_API sk_path_t* sk_path_new();
+/** Release the memory used by a sk_path_t. */
+SK_API void sk_path_delete(sk_path_t*);
+
+/** Set the beginning of the next contour to the point (x,y). */
+SK_API void sk_path_move_to(sk_path_t*, float x, float y);
+/**
+    Add a line from the last point to the specified point (x,y). If no
+    sk_path_move_to() call has been made for this contour, the first
+    point is automatically set to (0,0).
+*/
+SK_API void sk_path_line_to(sk_path_t*, float x, float y);
+/**
+    Add a quadratic bezier from the last point, approaching control
+    point (x0,y0), and ending at (x1,y1). If no sk_path_move_to() call
+    has been made for this contour, the first point is automatically
+    set to (0,0).
+*/
+SK_API void sk_path_quad_to(sk_path_t*, float x0, float y0, float x1, float y1);
+/**
+    Add a conic curve from the last point, approaching control point
+    (x0,y01), and ending at (x1,y1) with weight w.  If no
+    sk_path_move_to() call has been made for this contour, the first
+    point is automatically set to (0,0).
+*/
+SK_API void sk_path_conic_to(sk_path_t*, float x0, float y0, float x1, float y1, float w);
+/**
+    Add a cubic bezier from the last point, approaching control points
+    (x0,y0) and (x1,y1), and ending at (x2,y2). If no
+    sk_path_move_to() call has been made for this contour, the first
+    point is automatically set to (0,0).
+*/
+SK_API void sk_path_cubic_to(sk_path_t*,
+                             float x0, float y0,
+                             float x1, float y1,
+                             float x2, float y2);
+/**
+   Close the current contour. If the current point is not equal to the
+   first point of the contour, a line segment is automatically added.
+*/
+SK_API void sk_path_close(sk_path_t*);
+
+/**
+    Add a closed rectangle contour to the path.
+*/
+SK_API void sk_path_add_rect(sk_path_t*, const sk_rect_t*, sk_path_direction_t);
+/**
+    Add a closed oval contour to the path
+*/
+SK_API void sk_path_add_oval(sk_path_t*, const sk_rect_t*, sk_path_direction_t);
+
+/**
+ *  If the path is empty, return false and set the rect parameter to [0, 0, 0, 0].
+ *  else return true and set the rect parameter to the bounds of the control-points
+ *  of the path.
+ */
+SK_API bool sk_path_get_bounds(const sk_path_t*, sk_rect_t*);
+
+SK_C_PLUS_PLUS_END_GUARD
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/skia/skia/include/c/sk_picture.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+// EXPERIMENTAL EXPERIMENTAL EXPERIMENTAL EXPERIMENTAL
+// DO NOT USE -- FOR INTERNAL TESTING ONLY
+
+#ifndef sk_picture_DEFINED
+#define sk_picture_DEFINED
+
+#include "sk_types.h"
+
+SK_C_PLUS_PLUS_BEGIN_GUARD
+
+/**
+    Create a new sk_picture_recorder_t.  Its resources should be
+    released with a call to sk_picture_recorder_delete().
+*/
+sk_picture_recorder_t* sk_picture_recorder_new();
+/**
+    Release the memory and other resources used by this
+    sk_picture_recorder_t.
+*/
+void sk_picture_recorder_delete(sk_picture_recorder_t*);
+
+/**
+   Returns the canvas that records the drawing commands
+
+   @param sk_rect_t* the cull rect used when recording this
+                     picture. Any drawing the falls outside of this
+                     rect is undefined, and may be drawn or it may not.
+*/
+sk_canvas_t* sk_picture_recorder_begin_recording(sk_picture_recorder_t*, const sk_rect_t*);
+/**
+    Signal that the caller is done recording. This invalidates the
+    canvas returned by begin_recording. Ownership of the sk_picture_t
+    is passed to the caller, who must call sk_picture_unref() when
+    they are done using it.  The returned picture is immutable.
+*/
+sk_picture_t* sk_picture_recorder_end_recording(sk_picture_recorder_t*);
+
+/**
+    Increment the reference count on the given sk_picture_t. Must be
+    balanced by a call to sk_picture_unref().
+*/
+void sk_picture_ref(sk_picture_t*);
+/**
+    Decrement the reference count. If the reference count is 1 before
+    the decrement, then release both the memory holding the
+    sk_picture_t and any resouces it may be managing.  New
+    sk_picture_t are created with a reference count of 1.
+*/
+void sk_picture_unref(sk_picture_t*);
+
+/**
+    Returns a non-zero value unique among all pictures.
+ */
+uint32_t sk_picture_get_unique_id(sk_picture_t*);
+
+/**
+    Return the cull rect specified when this picture was recorded.
+*/
+sk_rect_t sk_picture_get_bounds(sk_picture_t*);
+
+SK_C_PLUS_PLUS_END_GUARD
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/skia/skia/include/c/sk_shader.h
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+// EXPERIMENTAL EXPERIMENTAL EXPERIMENTAL EXPERIMENTAL
+// DO NOT USE -- FOR INTERNAL TESTING ONLY
+
+#ifndef sk_shader_DEFINED
+#define sk_shader_DEFINED
+
+#include "sk_types.h"
+
+SK_C_PLUS_PLUS_BEGIN_GUARD
+
+void sk_shader_ref(sk_shader_t*);
+void sk_shader_unref(sk_shader_t*);
+
+typedef enum {
+    CLAMP_SK_SHADER_TILEMODE,
+    REPEAT_SK_SHADER_TILEMODE,
+    MIRROR_SK_SHADER_TILEMODE,
+} sk_shader_tilemode_t;
+
+/**
+    Returns a shader that generates a linear gradient between the two
+    specified points.
+
+    @param points The start and end points for the gradient.
+    @param colors The array[count] of colors, to be distributed between
+                  the two points
+    @param colorPos May be NULL. array[count] of SkScalars, or NULL, of
+                    the relative position of each corresponding color
+                    in the colors array. If this is NULL, the the
+                    colors are distributed evenly between the start
+                    and end point.  If this is not null, the values
+                    must begin with 0, end with 1.0, and intermediate
+                    values must be strictly increasing.
+    @param colorCount Must be >=2. The number of colors (and pos if not
+                      NULL) entries.
+    @param mode The tiling mode
+*/
+sk_shader_t* sk_shader_new_linear_gradient(const sk_point_t points[2],
+                                           const sk_color_t colors[],
+                                           const float colorPos[],
+                                           int colorCount,
+                                           sk_shader_tilemode_t tileMode,
+                                           const sk_matrix_t* localMatrix);
+
+
+/**
+    Returns a shader that generates a radial gradient given the center
+    and radius.
+
+    @param center The center of the circle for this gradient
+    @param radius Must be positive. The radius of the circle for this
+                  gradient
+    @param colors The array[count] of colors, to be distributed
+                  between the center and edge of the circle
+    @param colorPos May be NULL. The array[count] of the relative
+                    position of each corresponding color in the colors
+                    array. If this is NULL, the the colors are
+                    distributed evenly between the center and edge of
+                    the circle.  If this is not null, the values must
+                    begin with 0, end with 1.0, and intermediate
+                    values must be strictly increasing.
+    @param count Must be >= 2. The number of colors (and pos if not
+                 NULL) entries
+    @param tileMode The tiling mode
+    @param localMatrix May be NULL
+*/
+sk_shader_t* sk_shader_new_radial_gradient(const sk_point_t* center,
+                                           float radius,
+                                           const sk_color_t colors[],
+                                           const float colorPos[],
+                                           int colorCount,
+                                           sk_shader_tilemode_t tileMode,
+                                           const sk_matrix_t* localMatrix);
+
+/**
+    Returns a shader that generates a sweep gradient given a center.
+
+    @param center The coordinates of the center of the sweep
+    @param colors The array[count] of colors, to be distributed around
+                  the center.
+    @param colorPos May be NULL. The array[count] of the relative
+                    position of each corresponding color in the colors
+                    array. If this is NULL, the the colors are
+                    distributed evenly between the center and edge of
+                    the circle.  If this is not null, the values must
+                    begin with 0, end with 1.0, and intermediate
+                    values must be strictly increasing.
+    @param colorCount Must be >= 2. The number of colors (and pos if
+                      not NULL) entries
+    @param localMatrix May be NULL
+*/
+sk_shader_t* sk_shader_new_sweep_gradient(const sk_point_t* center,
+                                          const sk_color_t colors[],
+                                          const float colorPos[],
+                                          int colorCount,
+                                          const sk_matrix_t* localMatrix);
+
+/**
+    Returns a shader that generates a conical gradient given two circles, or
+    returns NULL if the inputs are invalid. The gradient interprets the
+    two circles according to the following HTML spec.
+    http://dev.w3.org/html5/2dcontext/#dom-context-2d-createradialgradient
+
+    Returns a shader that generates a sweep gradient given a center.
+
+    @param start, startRadius Defines the first circle.
+    @param end, endRadius Defines the first circle.
+    @param colors The array[count] of colors, to be distributed between
+                  the two circles.
+    @param colorPos May be NULL. The array[count] of the relative
+                    position of each corresponding color in the colors
+                    array. If this is NULL, the the colors are
+                    distributed evenly between the two circles.  If
+                    this is not null, the values must begin with 0,
+                    end with 1.0, and intermediate values must be
+                    strictly increasing.
+    @param colorCount Must be >= 2. The number of colors (and pos if
+                      not NULL) entries
+    @param tileMode The tiling mode
+    @param localMatrix May be NULL
+
+*/
+sk_shader_t* sk_shader_new_two_point_conical_gradient(
+        const sk_point_t* start,
+        float startRadius,
+        const sk_point_t* end,
+        float endRadius,
+        const sk_color_t colors[],
+        const float colorPos[],
+        int colorCount,
+        sk_shader_tilemode_t tileMode,
+        const sk_matrix_t* localMatrix);
+
+SK_C_PLUS_PLUS_END_GUARD
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/skia/skia/include/c/sk_surface.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+// EXPERIMENTAL EXPERIMENTAL EXPERIMENTAL EXPERIMENTAL
+// DO NOT USE -- FOR INTERNAL TESTING ONLY
+
+#ifndef sk_surface_DEFINED
+#define sk_surface_DEFINED
+
+#include "sk_types.h"
+
+SK_C_PLUS_PLUS_BEGIN_GUARD
+
+/**
+    Return a new surface, with the memory for the pixels automatically
+    allocated.  If the requested surface cannot be created, or the
+    request is not a supported configuration, NULL will be returned.
+
+    @param sk_imageinfo_t* Specify the width, height, color type, and
+                           alpha type for the surface.
+
+    @param sk_surfaceprops_t* If not NULL, specify additional non-default
+                              properties of the surface.
+*/
+SK_API sk_surface_t* sk_surface_new_raster(const sk_imageinfo_t*, const sk_surfaceprops_t*);
+
+/**
+    Create a new surface which will draw into the specified pixels
+    with the specified rowbytes.  If the requested surface cannot be
+    created, or the request is not a supported configuration, NULL
+    will be returned.
+
+    @param sk_imageinfo_t* Specify the width, height, color type, and
+                           alpha type for the surface.
+    @param void* pixels Specify the location in memory where the
+                        destination pixels are.  This memory must
+                        outlast this surface.
+     @param size_t rowBytes Specify the difference, in bytes, between
+                           each adjacent row.  Should be at least
+                           (width * sizeof(one pixel)).
+    @param sk_surfaceprops_t* If not NULL, specify additional non-default
+                              properties of the surface.
+*/
+SK_API sk_surface_t* sk_surface_new_raster_direct(const sk_imageinfo_t*,
+                                                  void* pixels, size_t rowBytes,
+                                                  const sk_surfaceprops_t* props);
+
+/**
+    Decrement the reference count. If the reference count is 1 before
+    the decrement, then release both the memory holding the
+    sk_surface_t and any pixel memory it may be managing.  New
+    sk_surface_t are created with a reference count of 1.
+*/
+SK_API void sk_surface_unref(sk_surface_t*);
+
+/**
+ *  Return the canvas associated with this surface. Note: the canvas is owned by the surface,
+ *  so the returned object is only valid while the owning surface is valid.
+ */
+SK_API sk_canvas_t* sk_surface_get_canvas(sk_surface_t*);
+
+/**
+ *  Call sk_image_unref() when the returned image is no longer used.
+ */
+SK_API sk_image_t* sk_surface_new_image_snapshot(sk_surface_t*);
+
+SK_C_PLUS_PLUS_END_GUARD
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/skia/skia/include/c/sk_types.h
@@ -0,0 +1,205 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+// EXPERIMENTAL EXPERIMENTAL EXPERIMENTAL EXPERIMENTAL
+// DO NOT USE -- FOR INTERNAL TESTING ONLY
+
+#ifndef sk_types_DEFINED
+#define sk_types_DEFINED
+
+#include <stdint.h>
+#include <stddef.h>
+
+#ifdef __cplusplus
+    #define SK_C_PLUS_PLUS_BEGIN_GUARD    extern "C" {
+    #define SK_C_PLUS_PLUS_END_GUARD      }
+#else
+    #include <stdbool.h>
+    #define SK_C_PLUS_PLUS_BEGIN_GUARD
+    #define SK_C_PLUS_PLUS_END_GUARD
+#endif
+
+#ifndef SK_API
+#define SK_API
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////
+
+SK_C_PLUS_PLUS_BEGIN_GUARD
+
+typedef uint32_t sk_color_t;
+
+/* This macro assumes all arguments are >=0 and <=255. */
+#define sk_color_set_argb(a, r, g, b)   (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
+#define sk_color_get_a(c)               (((c) >> 24) & 0xFF)
+#define sk_color_get_r(c)               (((c) >> 16) & 0xFF)
+#define sk_color_get_g(c)               (((c) >>  8) & 0xFF)
+#define sk_color_get_b(c)               (((c) >>  0) & 0xFF)
+
+typedef enum {
+    UNKNOWN_SK_COLORTYPE,
+    RGBA_8888_SK_COLORTYPE,
+    BGRA_8888_SK_COLORTYPE,
+    ALPHA_8_SK_COLORTYPE,
+} sk_colortype_t;
+
+typedef enum {
+    OPAQUE_SK_ALPHATYPE,
+    PREMUL_SK_ALPHATYPE,
+    UNPREMUL_SK_ALPHATYPE,
+} sk_alphatype_t;
+
+typedef enum {
+    INTERSECT_SK_CLIPTYPE,
+    DIFFERENCE_SK_CLIPTYPE,
+} sk_cliptype_t;
+
+typedef enum {
+    UNKNOWN_SK_PIXELGEOMETRY,
+    RGB_H_SK_PIXELGEOMETRY,
+    BGR_H_SK_PIXELGEOMETRY,
+    RGB_V_SK_PIXELGEOMETRY,
+    BGR_V_SK_PIXELGEOMETRY,
+} sk_pixelgeometry_t;
+
+/**
+    Return the default sk_colortype_t; this is operating-system dependent.
+*/
+SK_API sk_colortype_t sk_colortype_get_default_8888();
+
+typedef struct {
+    int32_t         width;
+    int32_t         height;
+    sk_colortype_t  colorType;
+    sk_alphatype_t  alphaType;
+} sk_imageinfo_t;
+
+typedef struct {
+    sk_pixelgeometry_t pixelGeometry;
+} sk_surfaceprops_t;
+
+typedef struct {
+    float   x;
+    float   y;
+} sk_point_t;
+
+typedef struct {
+    int32_t left;
+    int32_t top;
+    int32_t right;
+    int32_t bottom;
+} sk_irect_t;
+
+typedef struct {
+    float   left;
+    float   top;
+    float   right;
+    float   bottom;
+} sk_rect_t;
+
+typedef struct {
+    float   mat[9];
+} sk_matrix_t;
+
+/**
+    A sk_canvas_t encapsulates all of the state about drawing into a
+    destination This includes a reference to the destination itself,
+    and a stack of matrix/clip values.
+*/
+typedef struct sk_canvas_t sk_canvas_t;
+/**
+    A sk_data_ holds an immutable data buffer.
+*/
+typedef struct sk_data_t sk_data_t;
+/**
+    A sk_image_t is an abstraction for drawing a rectagle of pixels.
+    The content of the image is always immutable, though the actual
+    storage may change, if for example that image can be re-created via
+    encoded data or other means.
+*/
+typedef struct sk_image_t sk_image_t;
+/**
+    A sk_maskfilter_t is an object that perform transformations on an
+    alpha-channel mask before drawing it; it may be installed into a
+    sk_paint_t.  Each time a primitive is drawn, it is first
+    scan-converted into a alpha mask, which os handed to the
+    maskfilter, which may create a new mask is to render into the
+    destination.
+ */
+typedef struct sk_maskfilter_t sk_maskfilter_t;
+/**
+    A sk_paint_t holds the style and color information about how to
+    draw geometries, text and bitmaps.
+*/
+typedef struct sk_paint_t sk_paint_t;
+/**
+    A sk_path_t encapsulates compound (multiple contour) geometric
+    paths consisting of straight line segments, quadratic curves, and
+    cubic curves.
+*/
+typedef struct sk_path_t sk_path_t;
+/**
+    A sk_picture_t holds recorded canvas drawing commands to be played
+    back at a later time.
+*/
+typedef struct sk_picture_t sk_picture_t;
+/**
+    A sk_picture_recorder_t holds a sk_canvas_t that records commands
+    to create a sk_picture_t.
+*/
+typedef struct sk_picture_recorder_t sk_picture_recorder_t;
+/**
+    A sk_shader_t specifies the source color(s) for what is being drawn. If a
+    paint has no shader, then the paint's color is used. If the paint
+    has a shader, then the shader's color(s) are use instead, but they
+    are modulated by the paint's alpha.
+*/
+typedef struct sk_shader_t sk_shader_t;
+/**
+    A sk_surface_t holds the destination for drawing to a canvas. For
+    raster drawing, the destination is an array of pixels in memory.
+    For GPU drawing, the destination is a texture or a framebuffer.
+*/
+typedef struct sk_surface_t sk_surface_t;
+
+typedef enum {
+    CLEAR_SK_XFERMODE_MODE,
+    SRC_SK_XFERMODE_MODE,
+    DST_SK_XFERMODE_MODE,
+    SRCOVER_SK_XFERMODE_MODE,
+    DSTOVER_SK_XFERMODE_MODE,
+    SRCIN_SK_XFERMODE_MODE,
+    DSTIN_SK_XFERMODE_MODE,
+    SRCOUT_SK_XFERMODE_MODE,
+    DSTOUT_SK_XFERMODE_MODE,
+    SRCATOP_SK_XFERMODE_MODE,
+    DSTATOP_SK_XFERMODE_MODE,
+    XOR_SK_XFERMODE_MODE,
+    PLUS_SK_XFERMODE_MODE,
+    MODULATE_SK_XFERMODE_MODE,
+    SCREEN_SK_XFERMODE_MODE,
+    OVERLAY_SK_XFERMODE_MODE,
+    DARKEN_SK_XFERMODE_MODE,
+    LIGHTEN_SK_XFERMODE_MODE,
+    COLORDODGE_SK_XFERMODE_MODE,
+    COLORBURN_SK_XFERMODE_MODE,
+    HARDLIGHT_SK_XFERMODE_MODE,
+    SOFTLIGHT_SK_XFERMODE_MODE,
+    DIFFERENCE_SK_XFERMODE_MODE,
+    EXCLUSION_SK_XFERMODE_MODE,
+    MULTIPLY_SK_XFERMODE_MODE,
+    HUE_SK_XFERMODE_MODE,
+    SATURATION_SK_XFERMODE_MODE,
+    COLOR_SK_XFERMODE_MODE,
+    LUMINOSITY_SK_XFERMODE_MODE,
+} sk_xfermode_mode_t;
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+SK_C_PLUS_PLUS_END_GUARD
+
+#endif
new file mode 100644
--- /dev/null
+++ b/gfx/skia/skia/include/codec/SkAndroidCodec.h
@@ -0,0 +1,230 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkAndroidCodec_DEFINED
+#define SkAndroidCodec_DEFINED
+
+#include "SkCodec.h"
+#include "SkEncodedFormat.h"
+#include "SkStream.h"
+#include "SkTypes.h"
+
+/**
+ *  Abstract interface defining image codec functionality that is necessary for
+ *  Android.
+ */
+class SkAndroidCodec : SkNoncopyable {
+public:
+    /**
+     *  If this stream represents an encoded image that we know how to decode,
+     *  return an SkAndroidCodec that can decode it. Otherwise return NULL.
+     *
+     *  The SkPngChunkReader handles unknown chunks in PNGs.
+     *  See SkCodec.h for more details.
+     *
+     *  If NULL is returned, the stream is deleted immediately. Otherwise, the
+     *  SkCodec takes ownership of it, and will delete it when done with it.
+     */
+    static SkAndroidCodec* NewFromStream(SkStream*, SkPngChunkReader* = NULL);
+
+    /**
+     *  If this data represents an encoded image that we know how to decode,
+     *  return an SkAndroidCodec that can decode it. Otherwise return NULL.
+     *
+     *  The SkPngChunkReader handles unknown chunks in PNGs.
+     *  See SkCodec.h for more details.
+     *
+     *  Will take a ref if it returns a codec, else will not affect the data.
+     */
+    static SkAndroidCodec* NewFromData(SkData*, SkPngChunkReader* = NULL);
+
+    virtual ~SkAndroidCodec() {}
+
+
+    const SkImageInfo& getInfo() const { return fInfo; }
+
+    /**
+     *  Format of the encoded data.
+     */
+    SkEncodedFormat getEncodedFormat() const { return this->onGetEncodedFormat(); }
+
+    /**
+     *  Returns the dimensions of the scaled output image, for an input
+     *  sampleSize.
+     *
+     *  When the sample size divides evenly into the original dimensions, the
+     *  scaled output dimensions will simply be equal to the original
+     *  dimensions divided by the sample size.
+     *
+     *  When the sample size does not divide even into the original
+     *  dimensions, the codec may round up or down, depending on what is most
+     *  efficient to decode.
+     *
+     *  Finally, the codec will always recommend a non-zero output, so the output
+     *  dimension will always be one if the sampleSize is greater than the
+     *  original dimension.
+     */
+    SkISize getSampledDimensions(int sampleSize) const;
+
+    /**
+     *  Return (via desiredSubset) a subset which can decoded from this codec,
+     *  or false if the input subset is invalid.
+     *
+     *  @param desiredSubset in/out parameter
+     *                       As input, a desired subset of the original bounds
+     *                       (as specified by getInfo).
+     *                       As output, if true is returned, desiredSubset may
+     *                       have been modified to a subset which is
+     *                       supported. Although a particular change may have
+     *                       been made to desiredSubset to create something
+     *                       supported, it is possible other changes could
+     *                       result in a valid subset.  If false is returned,
+     *                       desiredSubset's value is undefined.
+     *  @return true         If the input desiredSubset is valid.
+     *                       desiredSubset may be modified to a subset
+     *                       supported by the codec.
+     *          false        If desiredSubset is invalid (NULL or not fully
+     *                       contained within the image).
+     */
+    bool getSupportedSubset(SkIRect* desiredSubset) const;
+    // TODO: Rename SkCodec::getValidSubset() to getSupportedSubset()
+
+    /**
+     *  Returns the dimensions of the scaled, partial output image, for an
+     *  input sampleSize and subset.
+     *
+     *  @param sampleSize Factor to scale down by.
+     *  @param subset     Must be a valid subset of the original image
+     *                    dimensions and a subset supported by SkAndroidCodec.
+     *                    getSubset() can be used to obtain a subset supported
+     *                    by SkAndroidCodec.
+     *  @return           Size of the scaled partial image.  Or zero size
+     *                    if either of the inputs is invalid.
+     */
+    SkISize getSampledSubsetDimensions(int sampleSize, const SkIRect& subset) const;
+
+    /**
+     *  Additional options to pass to getAndroidPixels().
+     */
+    // FIXME: It's a bit redundant to name these AndroidOptions when this class is already
+    //        called SkAndroidCodec.  On the other hand, it's may be a bit confusing to call
+    //        these Options when SkCodec has a slightly different set of Options.  Maybe these
+    //        should be DecodeOptions or SamplingOptions?
+    struct AndroidOptions {
+        AndroidOptions()
+            : fZeroInitialized(SkCodec::kNo_ZeroInitialized)
+            , fSubset(nullptr)
+            , fColorPtr(nullptr)
+            , fColorCount(nullptr)
+            , fSampleSize(1)
+        {}
+
+        /**
+         *  Indicates is destination pixel memory is zero initialized.
+         */
+        SkCodec::ZeroInitialized fZeroInitialized;
+
+        /**
+         *  If not NULL, represents a subset of the original image to decode.
+         *
+         *  Must be within the bounds returned by getInfo().
+         *
+         *  If the EncodedFormat is kWEBP_SkEncodedFormat, the top and left
+         *  values must be even.
+         */
+        SkIRect* fSubset;
+
+        /**
+         *  If the client has requested a decode to kIndex8_SkColorType
+         *  (specified in the SkImageInfo), then the caller must provide
+         *  storage for up to 256 SkPMColor values in fColorPtr.  On success,
+         *  the codec must copy N colors into that storage, (where N is the
+         *  logical number of table entries) and set fColorCount to N.
+         *
+         *  If the client does not request kIndex8_SkColorType, then the last
+         *  two parameters may be NULL. If fColorCount is not null, it will be
+         *  set to 0.
+         */
+        SkPMColor* fColorPtr;
+        int*       fColorCount;
+
+        /**
+         *  The client may provide an integer downscale factor for the decode.
+         *  The codec may implement this downscaling by sampling or another
+         *  method if it is more efficient.
+         */
+        int fSampleSize;
+    };
+
+    /**
+     *  Decode into the given pixels, a block of memory of size at
+     *  least (info.fHeight - 1) * rowBytes + (info.fWidth *
+     *  bytesPerPixel)
+     *
+     *  Repeated calls to this function should give the same results,
+     *  allowing the PixelRef to be immutable.
+     *
+     *  @param info A description of the format (config, size)
+     *         expected by the caller.  This can simply be identical
+     *         to the info returned by getInfo().
+     *
+     *         This contract also allows the caller to specify
+     *         different output-configs, which the implementation can
+     *         decide to support or not.
+     *
+     *         A size that does not match getInfo() implies a request
+     *         to scale or subset. If the codec cannot perform this
+     *         scaling or subsetting, it will return an error code.
+     *
+     *  If info is kIndex8_SkColorType, then the caller must provide storage for up to 256
+     *  SkPMColor values in options->fColorPtr. On success the codec must copy N colors into
+     *  that storage, (where N is the logical number of table entries) and set
+     *  options->fColorCount to N.
+     *
+     *  If info is not kIndex8_SkColorType, options->fColorPtr and options->fColorCount may
+     *  be nullptr.
+     *
+     *  The AndroidOptions object is also used to specify any requested scaling or subsetting
+     *  using options->fSampleSize and options->fSubset.
+     *
+     *  @return Result kSuccess, or another value explaining the type of failure.
+     */
+    // FIXME: It's a bit redundant to name this getAndroidPixels() when this class is already
+    //        called SkAndroidCodec.  On the other hand, it's may be a bit confusing to call
+    //        this getPixels() when it is a slightly different API than SkCodec's getPixels().
+    //        Maybe this should be decode() or decodeSubset()?
+    SkCodec::Result getAndroidPixels(const SkImageInfo& info, void* pixels, size_t rowBytes,
+            const AndroidOptions* options);
+
+    /**
+     *  Simplified version of getAndroidPixels() where we supply the default AndroidOptions.
+     *
+     *  This will return an error if the info is kIndex_8_SkColorType and also will not perform
+     *  any scaling or subsetting.
+     */
+    SkCodec::Result getAndroidPixels(const SkImageInfo& info, void* pixels, size_t rowBytes);
+
+protected:
+
+    SkAndroidCodec(const SkImageInfo&);
+
+    virtual SkEncodedFormat onGetEncodedFormat() const = 0;
+
+    virtual SkISize onGetSampledDimensions(int sampleSize) const = 0;
+
+    virtual bool onGetSupportedSubset(SkIRect* desiredSubset) const = 0;
+
+    virtual SkCodec::Result onGetAndroidPixels(const SkImageInfo& info, void* pixels,
+            size_t rowBytes, const AndroidOptions& options) = 0;
+
+private:
+
+    // This will always be a reference to the info that is contained by the
+    // embedded SkCodec.
+    const SkImageInfo& fInfo;
+};
+#endif // SkAndroidCodec_DEFINED
new file mode 100644
--- /dev/null
+++ b/gfx/skia/skia/include/codec/SkCodec.h
@@ -0,0 +1,614 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkCodec_DEFINED
+#define SkCodec_DEFINED
+
+#include "../private/SkTemplates.h"
+#include "SkColor.h"
+#include "SkEncodedFormat.h"
+#include "SkImageInfo.h"
+#include "SkSize.h"
+#include "SkStream.h"
+#include "SkTypes.h"
+
+class SkData;
+class SkPngChunkReader;
+class SkSampler;
+
+/**
+ *  Abstraction layer directly on top of an image codec.
+ */
+class SkCodec : SkNoncopyable {
+public:
+    /**
+     *  If this stream represents an encoded image that we know how to decode,
+     *  return an SkCodec that can decode it. Otherwise return NULL.
+     *
+     *  If the SkPngChunkReader is not NULL then:
+     *      If the image is not a PNG, the SkPngChunkReader will be ignored.
+     *      If the image is a PNG, the SkPngChunkReader will be reffed.
+     *      If the PNG has unknown chunks, the SkPngChunkReader will be used
+     *      to handle these chunks.  SkPngChunkReader will be called to read
+     *      any unknown chunk at any point during the creation of the codec
+     *      or the decode.  Note that if SkPngChunkReader fails to read a
+     *      chunk, this could result in a failure to create the codec or a
+     *      failure to decode the image.
+     *      If the PNG does not contain unknown chunks, the SkPngChunkReader
+     *      will not be used or modified.
+     *
+     *  If NULL is returned, the stream is deleted immediately. Otherwise, the
+     *  SkCodec takes ownership of it, and will delete it when done with it.
+     */
+    static SkCodec* NewFromStream(SkStream*, SkPngChunkReader* = NULL);
+
+    /**
+     *  If this data represents an encoded image that we know how to decode,
+     *  return an SkCodec that can decode it. Otherwise return NULL.
+     *
+     *  If the SkPngChunkReader is not NULL then:
+     *      If the image is not a PNG, the SkPngChunkReader will be ignored.
+     *      If the image is a PNG, the SkPngChunkReader will be reffed.
+     *      If the PNG has unknown chunks, the SkPngChunkReader will be used
+     *      to handle these chunks.  SkPngChunkReader will be called to read
+     *      any unknown chunk at any point during the creation of the codec
+     *      or the decode.  Note that if SkPngChunkReader fails to read a
+     *      chunk, this could result in a failure to create the codec or a
+     *      failure to decode the image.
+     *      If the PNG does not contain unknown chunks, the SkPngChunkReader
+     *      will not be used or modified.
+     *
+     *  Will take a ref if it returns a codec, else will not affect the data.
+     */
+    static SkCodec* NewFromData(SkData*, SkPngChunkReader* = NULL);
+
+    virtual ~SkCodec();
+
+    /**
+     *  Return the ImageInfo associated with this codec.
+     */
+    const SkImageInfo& getInfo() const { return fSrcInfo; }
+
+    /**
+     *  Return a size that approximately supports the desired scale factor.
+     *  The codec may not be able to scale efficiently to the exact scale
+     *  factor requested, so return a size that approximates that scale.
+     *  The returned value is the codec's suggestion for the closest valid
+     *  scale that it can natively support
+     */
+    SkISize getScaledDimensions(float desiredScale) const {
+        // Negative and zero scales are errors.
+        SkASSERT(desiredScale > 0.0f);
+        if (desiredScale <= 0.0f) {
+            return SkISize::Make(0, 0);
+        }
+
+        // Upscaling is not supported. Return the original size if the client
+        // requests an upscale.
+        if (desiredScale >= 1.0f) {
+            return this->getInfo().dimensions();
+        }
+        return this->onGetScaledDimensions(desiredScale);
+    }
+
+    /**
+     *  Return (via desiredSubset) a subset which can decoded from this codec,
+     *  or false if this codec cannot decode subsets or anything similar to
+     *  desiredSubset.
+     *
+     *  @param desiredSubset In/out parameter. As input, a desired subset of
+     *      the original bounds (as specified by getInfo). If true is returned,
+     *      desiredSubset may have been modified to a subset which is
+     *      supported. Although a particular change may have been made to
+     *      desiredSubset to create something supported, it is possible other
+     *      changes could result in a valid subset.
+     *      If false is returned, desiredSubset's value is undefined.
+     *  @return true if this codec supports decoding desiredSubset (as
+     *      returned, potentially modified)
+     */
+    bool getValidSubset(SkIRect* desiredSubset) const {
+        return this->onGetValidSubset(desiredSubset);
+    }
+
+    /**
+     *  Format of the encoded data.
+     */
+    SkEncodedFormat getEncodedFormat() const { return this->onGetEncodedFormat(); }
+
+    /**
+     *  Used to describe the result of a call to getPixels().
+     *
+     *  Result is the union of possible results from subclasses.
+     */
+    enum Result {
+        /**
+         *  General return value for success.
+         */
+        kSuccess,
+        /**
+         *  The input is incomplete. A partial image was generated.
+         */
+        kIncompleteInput,
+        /**
+         *  The generator cannot convert to match the request, ignoring
+         *  dimensions.
+         */
+        kInvalidConversion,
+        /**
+         *  The generator cannot scale to requested size.
+         */
+        kInvalidScale,
+        /**
+         *  Parameters (besides info) are invalid. e.g. NULL pixels, rowBytes
+         *  too small, etc.
+         */
+        kInvalidParameters,
+        /**
+         *  The input did not contain a valid image.
+         */
+        kInvalidInput,
+        /**
+         *  Fulfilling this request requires rewinding the input, which is not
+         *  supported for this input.
+         */
+        kCouldNotRewind,
+        /**
+         *  This method is not implemented by this codec.
+         *  FIXME: Perhaps this should be kUnsupported?
+         */
+        kUnimplemented,
+    };
+
+    /**
+     *  Whether or not the memory passed to getPixels is zero initialized.
+     */
+    enum ZeroInitialized {
+        /**
+         *  The memory passed to getPixels is zero initialized. The SkCodec
+         *  may take advantage of this by skipping writing zeroes.
+         */
+        kYes_ZeroInitialized,
+        /**
+         *  The memory passed to getPixels has not been initialized to zero,
+         *  so the SkCodec must write all zeroes to memory.
+         *
+         *  This is the default. It will be used if no Options struct is used.
+         */
+        kNo_ZeroInitialized,
+    };
+
+    /**
+     *  Additional options to pass to getPixels.
+     */
+    struct Options {
+        Options()
+            : fZeroInitialized(kNo_ZeroInitialized)
+            , fSubset(NULL)
+        {}
+
+        ZeroInitialized fZeroInitialized;
+        /**
+         *  If not NULL, represents a subset of the original image to decode.
+         *  Must be within the bounds returned by getInfo().
+         *  If the EncodedFormat is kWEBP_SkEncodedFormat (the only one which
+         *  currently supports subsets), the top and left values must be even.
+         *
+         *  In getPixels, we will attempt to decode the exact rectangular
+         *  subset specified by fSubset.
+         *
+         *  In a scanline decode, it does not make sense to specify a subset
+         *  top or subset height, since the client already controls which rows
+         *  to get and which rows to skip.  During scanline decodes, we will
+         *  require that the subset top be zero and the subset height be equal
+         *  to the full height.  We will, however, use the values of
+         *  subset left and subset width to decode partial scanlines on calls
+         *  to getScanlines().
+         */
+        SkIRect*        fSubset;
+    };
+
+    /**
+     *  Decode into the given pixels, a block of memory of size at
+     *  least (info.fHeight - 1) * rowBytes + (info.fWidth *
+     *  bytesPerPixel)
+     *
+     *  Repeated calls to this function should give the same results,
+     *  allowing the PixelRef to be immutable.
+     *
+     *  @param info A description of the format (config, size)
+     *         expected by the caller.  This can simply be identical
+     *         to the info returned by getInfo().
+     *
+     *         This contract also allows the caller to specify
+     *         different output-configs, which the implementation can
+     *         decide to support or not.
+     *
+     *         A size that does not match getInfo() implies a request
+     *         to scale. If the generator cannot perform this scale,
+     *         it will return kInvalidScale.
+     *
+     *  If info is kIndex8_SkColorType, then the caller must provide storage for up to 256
+     *  SkPMColor values in ctable. On success the generator must copy N colors into that storage,
+     *  (where N is the logical number of table entries) and set ctableCount to N.
+     *
+     *  If info is not kIndex8_SkColorType, then the last two parameters may be NULL. If ctableCount
+     *  is not null, it will be set to 0.
+     *
+     *  If a scanline decode is in progress, scanline mode will end, requiring the client to call
+     *  startScanlineDecode() in order to return to decoding scanlines.
+     *
+     *  @return Result kSuccess, or another value explaining the type of failure.
+     */
+    Result getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, const Options*,
+                     SkPMColor ctable[], int* ctableCount);
+
+    /**
+     *  Simplified version of getPixels() that asserts that info is NOT kIndex8_SkColorType and
+     *  uses the default Options.
+     */
+    Result getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes);
+
+    /**
+     *  Some images may initially report that they have alpha due to the format
+     *  of the encoded data, but then never use any colors which have alpha
+     *  less than 100%. This function can be called *after* decoding to
+     *  determine if such an image truly had alpha. Calling it before decoding
+     *  is undefined.
+     *  FIXME: see skbug.com/3582.
+     */
+    bool reallyHasAlpha() const {
+        return this->onReallyHasAlpha();
+    }
+
+    /**
+     * The remaining functions revolve around decoding scanlines.
+     */
+
+    /**
+     *  Prepare for a scanline decode with the specified options.
+     *
+     *  After this call, this class will be ready to decode the first scanline.
+     *
+     *  This must be called in order to call getScanlines or skipScanlines.
+     *
+     *  This may require rewinding the stream.
+     *
+     *  Not all SkCodecs support this.
+     *
+     *  @param dstInfo Info of the destination. If the dimensions do not match
+     *      those of getInfo, this implies a scale.
+     *  @param options Contains decoding options, including if memory is zero
+     *      initialized.
+     *  @param ctable A pointer to a color table.  When dstInfo.colorType() is
+     *      kIndex8, this should be non-NULL and have enough storage for 256
+     *      colors.  The color table will be populated after decoding the palette.
+     *  @param ctableCount A pointer to the size of the color table.  When
+     *      dstInfo.colorType() is kIndex8, this should be non-NULL.  It will
+     *      be modified to the true size of the color table (<= 256) after
+     *      decoding the palette.
+     *  @return Enum representing success or reason for failure.
+     */
+    Result startScanlineDecode(const SkImageInfo& dstInfo, const SkCodec::Options* options,
+            SkPMColor ctable[], int* ctableCount);
+
+    /**
+     *  Simplified version of startScanlineDecode() that asserts that info is NOT
+     *  kIndex8_SkColorType and uses the default Options.
+     */
+    Result startScanlineDecode(const SkImageInfo& dstInfo);
+
+    /**
+     *  Write the next countLines scanlines into dst.
+     *
+     *  Not valid to call before calling startScanlineDecode().
+     *
+     *  @param dst Must be non-null, and large enough to hold countLines
+     *      scanlines of size rowBytes.
+     *  @param countLines Number of lines to write.
+     *  @param rowBytes Number of bytes per row. Must be large enough to hold
+     *      a scanline based on the SkImageInfo used to create this object.
+     *  @return the number of lines successfully decoded.  If this value is
+     *      less than countLines, this will fill the remaining lines with a
+     *      default value.
+     */
+    int getScanlines(void* dst, int countLines, size_t rowBytes);
+
+    /**
+     *  Skip count scanlines.
+     *
+     *  Not valid to call before calling startScanlineDecode().
+     *
+     *  The default version just calls onGetScanlines and discards the dst.
+     *  NOTE: If skipped lines are the only lines with alpha, this default
+     *  will make reallyHasAlpha return true, when it could have returned
+     *  false.
+     *
+     *  @return true if the scanlines were successfully skipped
+     *          false on failure, possible reasons for failure include:
+     *              An incomplete input image stream.
+     *              Calling this function before calling startScanlineDecode().
+     *              If countLines is less than zero or so large that it moves
+     *                  the current scanline past the end of the image.
+     */
+    bool skipScanlines(int countLines);
+
+    /**
+     *  The order in which rows are output from the scanline decoder is not the
+     *  same for all variations of all image types.  This explains the possible
+     *  output row orderings.
+     */
+    enum SkScanlineOrder {
+        /*
+         * By far the most common, this indicates that the image can be decoded
+         * reliably using the scanline decoder, and that rows will be output in
+         * the logical order.
+         */
+        kTopDown_SkScanlineOrder,
+
+        /*
+         * This indicates that the scanline decoder reliably outputs rows, but
+         * they will be returned in reverse order.  If the scanline format is
+         * kBottomUp, the nextScanline() API can be used to determine the actual
+         * y-coordinate of the next output row, but the client is not forced
+         * to take advantage of this, given that it's not too tough to keep
+         * track independently.
+         *
+         * For full image decodes, it is safe to get all of the scanlines at
+         * once, since the decoder will handle inverting the rows as it
+         * decodes.
+         *
+         * For subset decodes and sampling, it is simplest to get and skip
+         * scanlines one at a time, using the nextScanline() API.  It is
+         * possible to ask for larger chunks at a time, but this should be used
+         * with caution.  As with full image decodes, the decoder will handle
+         * inverting the requested rows, but rows will still be delivered
+         * starting from the bottom of the image.
+         *
+         * Upside down bmps are an example.
+         */
+        kBottomUp_SkScanlineOrder,
+
+        /*
+         * This indicates that the scanline decoder reliably outputs rows, but
+         * they will not be in logical order.  If the scanline format is
+         * kOutOfOrder, the nextScanline() API should be used to determine the
+         * actual y-coordinate of the next output row.
+         *
+         * For this scanline ordering, it is advisable to get and skip
+         * scanlines one at a time.
+         *
+         * Interlaced gifs are an example.
+         */
+        kOutOfOrder_SkScanlineOrder,
+
+        /*
+         * Indicates that the entire image must be decoded in order to output
+         * any amount of scanlines.  In this case, it is a REALLY BAD IDEA to
+         * request scanlines 1-by-1 or in small chunks.  The client should
+         * determine which scanlines are needed and ask for all of them in
+         * a single call to getScanlines().
+         *
+         * Interlaced pngs are an example.
+         */
+        kNone_SkScanlineOrder,
+    };
+
+    /**
+     *  An enum representing the order in which scanlines will be returned by
+     *  the scanline decoder.
+     */
+    SkScanlineOrder getScanlineOrder() const { return this->onGetScanlineOrder(); }
+
+    /**
+     *  Returns the y-coordinate of the next row to be returned by the scanline
+     *  decoder.
+     *
+     *  This will equal fCurrScanline, except in the case of strangely
+     *  encoded image types (bottom-up bmps, interlaced gifs).
+     *
+     *  Results are undefined when not in scanline decoding mode.
+     */
+    int nextScanline() const { return this->outputScanline(fCurrScanline); }
+
+    /**
+     * Returns the output y-coordinate of the row that corresponds to an input
+     * y-coordinate.  The input y-coordinate represents where the scanline
+     * is located in the encoded data.
+     *
+     *  This will equal inputScanline, except in the case of strangely
+     *  encoded image types (bottom-up bmps, interlaced gifs).
+     */
+    int outputScanline(int inputScanline) const;
+
+protected:
+    SkCodec(const SkImageInfo&, SkStream*);
+
+    virtual SkISize onGetScaledDimensions(float /* desiredScale */) const {
+        // By default, scaling is not supported.
+        return this->getInfo().dimensions();
+    }
+
+    // FIXME: What to do about subsets??
+    /**
+     *  Subclasses should override if they support dimensions other than the
+     *  srcInfo's.
+     */
+    virtual bool onDimensionsSupported(const SkISize&) {
+        return false;
+    }
+
+    virtual SkEncodedFormat onGetEncodedFormat() const = 0;
+
+    /**
+     * @param rowsDecoded When the encoded image stream is incomplete, this function
+     *                    will return kIncompleteInput and rowsDecoded will be set to
+     *                    the number of scanlines that were successfully decoded.
+     *                    This will allow getPixels() to fill the uninitialized memory.
+     */
+    virtual Result onGetPixels(const SkImageInfo& info,
+                               void* pixels, size_t rowBytes, const Options&,
+                               SkPMColor ctable[], int* ctableCount,
+                               int* rowsDecoded) = 0;
+
+    virtual bool onGetValidSubset(SkIRect* /* desiredSubset */) const {
+        // By default, subsets are not supported.
+        return false;
+    }
+
+    virtual bool onReallyHasAlpha() const { return false; }
+
+    /**
+     *  If the stream was previously read, attempt to rewind.
+     *
+     *  If the stream needed to be rewound, call onRewind.
+     *  @returns true if the codec is at the right position and can be used.
+     *      false if there was a failure to rewind.
+     *
+     *  This is called by getPixels() and start(). Subclasses may call if they
+     *  need to rewind at another time.
+     */
+    bool SK_WARN_UNUSED_RESULT rewindIfNeeded();
+
+    /**
+     *  Called by rewindIfNeeded, if the stream needed to be rewound.
+     *
+     *  Subclasses should do any set up needed after a rewind.
+     */
+    virtual bool onRewind() {
+        return true;
+    }
+
+    /**
+     * On an incomplete input, getPixels() and getScanlines() will fill any uninitialized
+     * scanlines.  This allows the subclass to indicate what value to fill with.
+     *
+     * @param colorType Destination color type.
+     * @param alphaType Destination alpha type.
+     * @return          The value with which to fill uninitialized pixels.
+     *
+     * Note that we can interpret the return value as an SkPMColor, a 16-bit 565 color,
+     * an 8-bit gray color, or an 8-bit index into a color table, depending on the color
+     * type.
+     */
+    uint32_t getFillValue(SkColorType colorType, SkAlphaType alphaType) const {
+        return this->onGetFillValue(colorType, alphaType);
+    }
+
+    /**
+     * Some subclasses will override this function, but this is a useful default for the color
+     * types that we support.  Note that for color types that do not use the full 32-bits,
+     * we will simply take the low bits of the fill value.
+     *
+     * kN32_SkColorType: Transparent or Black
+     * kRGB_565_SkColorType: Black
+     * kGray_8_SkColorType: Black
+     * kIndex_8_SkColorType: First color in color table
+     */
+    virtual uint32_t onGetFillValue(SkColorType /*colorType*/, SkAlphaType alphaType) const {
+        return kOpaque_SkAlphaType == alphaType ? SK_ColorBLACK : SK_ColorTRANSPARENT;
+    }
+
+    /**
+     * Get method for the input stream
+     */
+    SkStream* stream() {
+        return fStream.get();
+    }
+
+    /**
+     *  The remaining functions revolve around decoding scanlines.
+     */
+
+    /**
+     *  Most images types will be kTopDown and will not need to override this function.
+     */
+    virtual SkScanlineOrder onGetScanlineOrder() const { return kTopDown_SkScanlineOrder; }
+
+    /**
+     *  Update the next scanline. Used by interlaced png.
+     */
+    void updateNextScanline(int newY) { fCurrScanline = newY; }