summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
Diffstat (limited to 'libs')
-rw-r--r--libs/androidfw/AssetManager2.cpp17
-rw-r--r--libs/hwui/GlopBuilder.cpp1
-rw-r--r--libs/hwui/Properties.cpp1
-rw-r--r--libs/hwui/Properties.h3
-rw-r--r--libs/hwui/RecordingCanvas.h6
-rw-r--r--libs/hwui/RenderNode.cpp19
-rw-r--r--libs/hwui/RenderNode.h21
-rw-r--r--libs/hwui/SkiaCanvas.cpp119
-rw-r--r--libs/hwui/SkiaCanvas.h16
-rw-r--r--libs/hwui/SkiaCanvasProxy.cpp4
-rw-r--r--libs/hwui/VectorDrawable.cpp4
-rw-r--r--libs/hwui/hwui/Bitmap.cpp19
-rw-r--r--libs/hwui/hwui/Bitmap.h16
-rw-r--r--libs/hwui/hwui/Canvas.cpp4
-rw-r--r--libs/hwui/hwui/Canvas.h21
-rw-r--r--libs/hwui/hwui/MinikinSkia.cpp11
-rw-r--r--libs/hwui/hwui/MinikinSkia.h3
-rw-r--r--libs/hwui/hwui/MinikinUtils.cpp19
-rw-r--r--libs/hwui/hwui/MinikinUtils.h11
-rw-r--r--libs/hwui/hwui/Paint.h14
-rw-r--r--libs/hwui/hwui/PaintImpl.cpp7
-rw-r--r--libs/hwui/hwui/Typeface.cpp22
-rw-r--r--libs/hwui/hwui/Typeface.h4
-rw-r--r--libs/hwui/pipeline/skia/GLFunctorDrawable.cpp42
-rw-r--r--libs/hwui/pipeline/skia/LayerDrawable.cpp5
-rw-r--r--libs/hwui/pipeline/skia/LayerDrawable.h10
-rw-r--r--libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp22
-rw-r--r--libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp31
-rw-r--r--libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp68
-rw-r--r--libs/hwui/pipeline/skia/SkiaPipeline.cpp11
-rw-r--r--libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp62
-rw-r--r--libs/hwui/pipeline/skia/VectorDrawableAtlas.cpp18
-rw-r--r--libs/hwui/pipeline/skia/VectorDrawableAtlas.h21
-rw-r--r--libs/hwui/renderthread/CacheManager.cpp5
-rw-r--r--libs/hwui/renderthread/EglManager.cpp2
-rw-r--r--libs/hwui/renderthread/RenderProxy.cpp12
-rw-r--r--libs/hwui/renderthread/RenderProxy.h2
-rw-r--r--libs/hwui/renderthread/RenderThread.cpp4
-rw-r--r--libs/hwui/renderthread/RenderThread.h8
-rw-r--r--libs/hwui/tests/common/scenes/BitmapShaders.cpp3
-rw-r--r--libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp3
-rw-r--r--libs/hwui/tests/microbench/DisplayListCanvasBench.cpp1
-rw-r--r--libs/hwui/tests/unit/RecordingCanvasTests.cpp3
-rw-r--r--libs/hwui/tests/unit/SkiaCanvasTests.cpp26
-rw-r--r--libs/hwui/tests/unit/TypefaceTests.cpp3
-rw-r--r--libs/incident/proto/android/privacy.proto7
-rw-r--r--libs/incident/proto/android/section.proto50
47 files changed, 540 insertions, 241 deletions
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index 5667f9283241..ab7e14de48fb 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -533,8 +533,8 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid) {
// Create the max possible entries we can make. Once we construct the bag,
// we will realloc to fit to size.
const size_t max_count = parent_bag->entry_count + dtohl(map->count);
- ResolvedBag* new_bag = reinterpret_cast<ResolvedBag*>(
- malloc(sizeof(ResolvedBag) + (max_count * sizeof(ResolvedBag::Entry))));
+ util::unique_cptr<ResolvedBag> new_bag{reinterpret_cast<ResolvedBag*>(
+ malloc(sizeof(ResolvedBag) + (max_count * sizeof(ResolvedBag::Entry))))};
ResolvedBag::Entry* new_entry = new_bag->entries;
const ResolvedBag::Entry* parent_entry = parent_bag->entries;
@@ -601,15 +601,14 @@ const ResolvedBag* AssetManager2::GetBag(uint32_t resid) {
// Resize the resulting array to fit.
const size_t actual_count = new_entry - new_bag->entries;
if (actual_count != max_count) {
- new_bag = reinterpret_cast<ResolvedBag*>(
- realloc(new_bag, sizeof(ResolvedBag) + (actual_count * sizeof(ResolvedBag::Entry))));
+ new_bag.reset(reinterpret_cast<ResolvedBag*>(realloc(
+ new_bag.release(), sizeof(ResolvedBag) + (actual_count * sizeof(ResolvedBag::Entry)))));
}
- util::unique_cptr<ResolvedBag> final_bag{new_bag};
- final_bag->type_spec_flags = flags;
- final_bag->entry_count = static_cast<uint32_t>(actual_count);
- ResolvedBag* result = final_bag.get();
- cached_bags_[resid] = std::move(final_bag);
+ new_bag->type_spec_flags = flags;
+ new_bag->entry_count = static_cast<uint32_t>(actual_count);
+ ResolvedBag* result = new_bag.get();
+ cached_bags_[resid] = std::move(new_bag);
return result;
}
diff --git a/libs/hwui/GlopBuilder.cpp b/libs/hwui/GlopBuilder.cpp
index c19c1a11e3e2..8727a1d20dfd 100644
--- a/libs/hwui/GlopBuilder.cpp
+++ b/libs/hwui/GlopBuilder.cpp
@@ -296,6 +296,7 @@ void GlopBuilder::setFill(int color, float alphaScale,
colorVector[2] = EOCF(srcColorMatrix[14] / 255.0f);
colorVector[3] = srcColorMatrix[19] / 255.0f; // alpha is linear
} else {
+ ALOGE("unsupported ColorFilter type: %s", colorFilter->getTypeName());
LOG_ALWAYS_FATAL("unsupported ColorFilter");
}
} else {
diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp
index acc75393ebcf..fe291d2a4bfe 100644
--- a/libs/hwui/Properties.cpp
+++ b/libs/hwui/Properties.cpp
@@ -51,6 +51,7 @@ int Properties::overrideSpotShadowStrength = -1;
ProfileType Properties::sProfileType = ProfileType::None;
bool Properties::sDisableProfileBars = false;
RenderPipelineType Properties::sRenderPipelineType = RenderPipelineType::NotInitialized;
+bool Properties::enableHighContrastText = false;
bool Properties::waitForGpuCompletion = false;
bool Properties::forceDrawFrame = false;
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index 47ae9e912127..0fe4c7714761 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -17,6 +17,7 @@
#ifndef ANDROID_HWUI_PROPERTIES_H
#define ANDROID_HWUI_PROPERTIES_H
+#include <cutils/compiler.h>
#include <cutils/properties.h>
/**
@@ -237,6 +238,8 @@ public:
static RenderPipelineType getRenderPipelineType();
static bool isSkiaEnabled();
+ ANDROID_API static bool enableHighContrastText;
+
// Should be used only by test apps
static bool waitForGpuCompletion;
static bool forceDrawFrame;
diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h
index ccdb4b0c1d8e..79db496f2acd 100644
--- a/libs/hwui/RecordingCanvas.h
+++ b/libs/hwui/RecordingCanvas.h
@@ -93,11 +93,6 @@ public:
virtual int width() override { return mState.getWidth(); }
virtual int height() override { return mState.getHeight(); }
- virtual void setHighContrastText(bool highContrastText) override {
- mHighContrastText = highContrastText;
- }
- virtual bool isHighContrastText() override { return mHighContrastText; }
-
// ----------------------------------------------------------------------------
// android/graphics/Canvas state operations
// ----------------------------------------------------------------------------
@@ -311,7 +306,6 @@ private:
DeferredBarrierType mDeferredBarrierType = DeferredBarrierType::None;
const ClipBase* mDeferredBarrierClip = nullptr;
DisplayList* mDisplayList = nullptr;
- bool mHighContrastText = false;
sk_sp<SkDrawFilter> mDrawFilter;
}; // class RecordingCanvas
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 61b3876cd095..36a747519c37 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -32,6 +32,7 @@
#include "protos/hwui.pb.h"
#include "protos/ProtoHelpers.h"
+#include <SkPathOps.h>
#include <algorithm>
#include <sstream>
#include <string>
@@ -555,5 +556,23 @@ void RenderNode::computeOrderingImpl(
}
}
+const SkPath* RenderNode::getClippedOutline(const SkRect& clipRect) const {
+ const SkPath* outlinePath = properties().getOutline().getPath();
+ const uint32_t outlineID = outlinePath->getGenerationID();
+
+ if (outlineID != mClippedOutlineCache.outlineID || clipRect != mClippedOutlineCache.clipRect) {
+ // update the cache keys
+ mClippedOutlineCache.outlineID = outlineID;
+ mClippedOutlineCache.clipRect = clipRect;
+
+ // update the cache value by recomputing a new path
+ SkPath clipPath;
+ clipPath.addRect(clipRect);
+ Op(*outlinePath, clipPath, kIntersect_SkPathOp, &mClippedOutlineCache.clippedOutline);
+
+ }
+ return &mClippedOutlineCache.clippedOutline;
+}
+
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index c4ae82af430c..89e022f5e68d 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -365,6 +365,17 @@ public:
return mSkiaLayer.get();
}
+ /**
+ * Returns the path that represents the outline of RenderNode intersected with
+ * the provided rect. This call will internally cache the resulting path in
+ * order to potentially return that path for subsequent calls to this method.
+ * By reusing the same path we get better performance on the GPU backends since
+ * those resources are cached in the hardware based on the path's genID.
+ *
+ * The returned path is only guaranteed to be valid until this function is called
+ * again or the RenderNode's outline is mutated.
+ */
+ const SkPath* getClippedOutline(const SkRect& clipRect) const;
private:
/**
* If this RenderNode has been used in a previous frame then the SkiaDisplayList
@@ -380,6 +391,16 @@ private:
* when it has been set to draw as a LayerType::RenderLayer.
*/
std::unique_ptr<skiapipeline::SkiaLayer> mSkiaLayer;
+
+ struct ClippedOutlineCache {
+ // keys
+ uint32_t outlineID = 0;
+ SkRect clipRect;
+
+ // value
+ SkPath clippedOutline;
+ };
+ mutable ClippedOutlineCache mClippedOutlineCache;
}; // class RenderNode
class MarkAndSweepRemoved : public TreeObserver {
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index 0a642b60d4c7..1f5f733188de 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -24,6 +24,7 @@
#include "pipeline/skia/AnimatedDrawables.h"
#include <SkCanvasStateUtils.h>
+#include <SkColorFilter.h>
#include <SkColorSpaceXformCanvas.h>
#include <SkDrawable.h>
#include <SkDeque.h>
@@ -46,25 +47,33 @@ Canvas* Canvas::create_canvas(const SkBitmap& bitmap) {
return new SkiaCanvas(bitmap);
}
-Canvas* Canvas::create_canvas(SkCanvas* skiaCanvas, XformToSRGB xformToSRGB) {
- return new SkiaCanvas(skiaCanvas, xformToSRGB);
+Canvas* Canvas::create_canvas(SkCanvas* skiaCanvas) {
+ return new SkiaCanvas(skiaCanvas);
}
SkiaCanvas::SkiaCanvas() {}
-SkiaCanvas::SkiaCanvas(SkCanvas* canvas, XformToSRGB xformToSRGB)
- : mCanvas(canvas)
-{
- LOG_ALWAYS_FATAL_IF(XformToSRGB::kImmediate == xformToSRGB);
-}
+SkiaCanvas::SkiaCanvas(SkCanvas* canvas) : mCanvas(canvas) {}
SkiaCanvas::SkiaCanvas(const SkBitmap& bitmap) {
sk_sp<SkColorSpace> cs = bitmap.refColorSpace();
mCanvasOwned =
std::unique_ptr<SkCanvas>(new SkCanvas(bitmap, SkCanvas::ColorBehavior::kLegacy));
- mCanvasWrapper = SkCreateColorSpaceXformCanvas(mCanvasOwned.get(),
- cs == nullptr ? SkColorSpace::MakeSRGB() : std::move(cs));
- mCanvas = mCanvasWrapper.get();
+ if (cs.get() == nullptr || cs->isSRGB()) {
+ if(!uirenderer::Properties::isSkiaEnabled()) {
+ mCanvasWrapper = SkCreateColorSpaceXformCanvas(mCanvasOwned.get(), SkColorSpace::MakeSRGB());
+ mCanvas = mCanvasWrapper.get();
+ } else {
+ mCanvas = mCanvasOwned.get();
+ }
+ } else {
+ /** The wrapper is needed if we are drawing into a non-sRGB destination, since
+ * we need to transform all colors (not just bitmaps via filters) into the
+ * destination's colorspace.
+ */
+ mCanvasWrapper = SkCreateColorSpaceXformCanvas(mCanvasOwned.get(), std::move(cs));
+ mCanvas = mCanvasWrapper.get();
+ }
}
SkiaCanvas::~SkiaCanvas() {}
@@ -73,9 +82,9 @@ void SkiaCanvas::reset(SkCanvas* skiaCanvas) {
if (mCanvas != skiaCanvas) {
mCanvas = skiaCanvas;
mCanvasOwned.reset();
+ mCanvasWrapper.reset();
}
mSaveStack.reset(nullptr);
- mHighContrastText = false;
}
// ----------------------------------------------------------------------------
@@ -86,13 +95,18 @@ void SkiaCanvas::setBitmap(const SkBitmap& bitmap) {
sk_sp<SkColorSpace> cs = bitmap.refColorSpace();
std::unique_ptr<SkCanvas> newCanvas =
std::unique_ptr<SkCanvas>(new SkCanvas(bitmap, SkCanvas::ColorBehavior::kLegacy));
- std::unique_ptr<SkCanvas> newCanvasWrapper = SkCreateColorSpaceXformCanvas(newCanvas.get(),
- cs == nullptr ? SkColorSpace::MakeSRGB() : std::move(cs));
+ std::unique_ptr<SkCanvas> newCanvasWrapper;
+ if (cs.get() != nullptr && !cs->isSRGB()) {
+ newCanvasWrapper = SkCreateColorSpaceXformCanvas(newCanvas.get(), std::move(cs));
+ }
+ else if(!uirenderer::Properties::isSkiaEnabled()) {
+ newCanvasWrapper = SkCreateColorSpaceXformCanvas(newCanvas.get(), SkColorSpace::MakeSRGB());
+ }
// deletes the previously owned canvas (if any)
mCanvasOwned = std::move(newCanvas);
mCanvasWrapper = std::move(newCanvasWrapper);
- mCanvas = mCanvasWrapper.get();
+ mCanvas = mCanvasWrapper ? mCanvasWrapper.get() : mCanvasOwned.get();
// clean up the old save stack
mSaveStack.reset(nullptr);
@@ -518,6 +532,9 @@ void SkiaCanvas::drawArc(float left, float top, float right, float bottom,
void SkiaCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
if (CC_UNLIKELY(paint.nothingToDraw())) return;
+ if (CC_UNLIKELY(path.isEmpty() && (!path.isInverseFillType()))) {
+ return;
+ }
mCanvas->drawPath(path, paint);
}
@@ -529,25 +546,64 @@ void SkiaCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, cons
// Canvas draw operations: Bitmaps
// ----------------------------------------------------------------------------
+const SkPaint* SkiaCanvas::addFilter(const SkPaint* origPaint, SkPaint* tmpPaint,
+ sk_sp<SkColorFilter> colorSpaceFilter) {
+ /* We don't apply the colorSpace filter if this canvas is already wrapped with
+ * a SkColorSpaceXformCanvas since it already takes care of converting the
+ * contents of the bitmap into the appropriate colorspace. The mCanvasWrapper
+ * should only be used if this canvas is backed by a surface/bitmap that is known
+ * to have a non-sRGB colorspace.
+ */
+ if (!mCanvasWrapper && colorSpaceFilter) {
+ if (origPaint) {
+ *tmpPaint = *origPaint;
+ }
+
+ if (tmpPaint->getColorFilter()) {
+ tmpPaint->setColorFilter(SkColorFilter::MakeComposeFilter(
+ tmpPaint->refColorFilter(), colorSpaceFilter));
+ LOG_ALWAYS_FATAL_IF(!tmpPaint->getColorFilter());
+ } else {
+ tmpPaint->setColorFilter(colorSpaceFilter);
+ }
+
+ return tmpPaint;
+ } else {
+ return origPaint;
+ }
+}
+
void SkiaCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) {
- mCanvas->drawImage(bitmap.makeImage(), left, top, paint);
+ SkPaint tmpPaint;
+ sk_sp<SkColorFilter> colorFilter;
+ sk_sp<SkImage> image = bitmap.makeImage(&colorFilter);
+ mCanvas->drawImage(image, left, top, addFilter(paint, &tmpPaint, colorFilter));
}
-void SkiaCanvas::drawBitmap(Bitmap& hwuiBitmap, const SkMatrix& matrix, const SkPaint* paint) {
+void SkiaCanvas::drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint) {
SkAutoCanvasRestore acr(mCanvas, true);
mCanvas->concat(matrix);
- mCanvas->drawImage(hwuiBitmap.makeImage(), 0, 0, paint);
+
+ SkPaint tmpPaint;
+ sk_sp<SkColorFilter> colorFilter;
+ sk_sp<SkImage> image = bitmap.makeImage(&colorFilter);
+ mCanvas->drawImage(image, 0, 0, addFilter(paint, &tmpPaint, colorFilter));
}
-void SkiaCanvas::drawBitmap(Bitmap& hwuiBitmap, float srcLeft, float srcTop,
+void SkiaCanvas::drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop,
float srcRight, float srcBottom, float dstLeft, float dstTop,
float dstRight, float dstBottom, const SkPaint* paint) {
SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom);
SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
- mCanvas->drawImageRect(hwuiBitmap.makeImage(), srcRect, dstRect, paint);
+
+ SkPaint tmpPaint;
+ sk_sp<SkColorFilter> colorFilter;
+ sk_sp<SkImage> image = bitmap.makeImage(&colorFilter);
+ mCanvas->drawImageRect(image, srcRect, dstRect, addFilter(paint, &tmpPaint, colorFilter),
+ SkCanvas::kFast_SrcRectConstraint);
}
-void SkiaCanvas::drawBitmapMesh(Bitmap& hwuiBitmap, int meshWidth, int meshHeight,
+void SkiaCanvas::drawBitmapMesh(Bitmap& bitmap, int meshWidth, int meshHeight,
const float* vertices, const int* colors, const SkPaint* paint) {
const int ptCount = (meshWidth + 1) * (meshHeight + 1);
const int indexCount = meshWidth * meshHeight * 6;
@@ -565,8 +621,8 @@ void SkiaCanvas::drawBitmapMesh(Bitmap& hwuiBitmap, int meshWidth, int meshHeigh
// cons up texture coordinates and indices
{
- const SkScalar w = SkIntToScalar(hwuiBitmap.width());
- const SkScalar h = SkIntToScalar(hwuiBitmap.height());
+ const SkScalar w = SkIntToScalar(bitmap.width());
+ const SkScalar h = SkIntToScalar(bitmap.height());
const SkScalar dx = w / meshWidth;
const SkScalar dy = h / meshHeight;
@@ -627,17 +683,22 @@ void SkiaCanvas::drawBitmapMesh(Bitmap& hwuiBitmap, int meshWidth, int meshHeigh
tmpPaint = *paint;
}
- sk_sp<SkImage> image = hwuiBitmap.makeImage();
- tmpPaint.setShader(image->makeShader(SkShader::kClamp_TileMode, SkShader::kClamp_TileMode));
+ sk_sp<SkColorFilter> colorFilter;
+ sk_sp<SkImage> image = bitmap.makeImage(&colorFilter);
+ sk_sp<SkShader> shader = image->makeShader(SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
+ if(colorFilter) {
+ shader = shader->makeWithColorFilter(colorFilter);
+ }
+ tmpPaint.setShader(shader);
mCanvas->drawVertices(builder.detach(), SkBlendMode::kModulate, tmpPaint);
}
-void SkiaCanvas::drawNinePatch(Bitmap& hwuiBitmap, const Res_png_9patch& chunk,
+void SkiaCanvas::drawNinePatch(Bitmap& bitmap, const Res_png_9patch& chunk,
float dstLeft, float dstTop, float dstRight, float dstBottom, const SkPaint* paint) {
SkCanvas::Lattice lattice;
- NinePatchUtils::SetLatticeDivs(&lattice, chunk, hwuiBitmap.width(), hwuiBitmap.height());
+ NinePatchUtils::SetLatticeDivs(&lattice, chunk, bitmap.width(), bitmap.height());
lattice.fFlags = nullptr;
int numFlags = 0;
@@ -654,7 +715,11 @@ void SkiaCanvas::drawNinePatch(Bitmap& hwuiBitmap, const Res_png_9patch& chunk,
lattice.fBounds = nullptr;
SkRect dst = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
- mCanvas->drawImageLattice(hwuiBitmap.makeImage().get(), lattice, dst, paint);
+
+ SkPaint tmpPaint;
+ sk_sp<SkColorFilter> colorFilter;
+ sk_sp<SkImage> image = bitmap.makeImage(&colorFilter);
+ mCanvas->drawImageLattice(image.get(), lattice, dst, addFilter(paint, &tmpPaint, colorFilter));
}
void SkiaCanvas::drawVectorDrawable(VectorDrawableRoot* vectorDrawable) {
diff --git a/libs/hwui/SkiaCanvas.h b/libs/hwui/SkiaCanvas.h
index af2c23e4a2b7..e17f835031bb 100644
--- a/libs/hwui/SkiaCanvas.h
+++ b/libs/hwui/SkiaCanvas.h
@@ -37,12 +37,8 @@ public:
* @param canvas SkCanvas to handle calls made to this SkiaCanvas. Must
* not be NULL. This constructor does not take ownership, so the caller
* must guarantee that it remains valid while the SkiaCanvas is valid.
- * @param xformToSRGB Indicates if bitmaps should be xformed to the sRGB
- * color space before drawing. This makes sense for software rendering.
- * For the picture case, it may make more sense to leave bitmaps as is,
- * and handle the xform when replaying the picture.
*/
- explicit SkiaCanvas(SkCanvas* canvas, XformToSRGB xformToSRGB);
+ explicit SkiaCanvas(SkCanvas* canvas);
virtual ~SkiaCanvas();
@@ -69,11 +65,6 @@ public:
virtual int width() override;
virtual int height() override;
- virtual void setHighContrastText(bool highContrastText) override {
- mHighContrastText = highContrastText;
- }
- virtual bool isHighContrastText() override { return mHighContrastText; }
-
virtual int getSaveCount() const override;
virtual int save(SaveFlags::Flags flags) override;
virtual void restore() override;
@@ -170,8 +161,6 @@ private:
size_t clipIndex;
};
- bool mHighContrastText = false;
-
const SaveRec* currentSaveRec() const;
void recordPartialSave(SaveFlags::Flags flags);
@@ -182,6 +171,9 @@ private:
void drawPoints(const float* points, int count, const SkPaint& paint,
SkCanvas::PointMode mode);
+ const SkPaint* addFilter(const SkPaint* origPaint, SkPaint* tmpPaint,
+ sk_sp<SkColorFilter> colorSpaceFilter);
+
class Clip;
std::unique_ptr<SkCanvas> mCanvasWrapper; // might own a wrapper on the canvas
diff --git a/libs/hwui/SkiaCanvasProxy.cpp b/libs/hwui/SkiaCanvasProxy.cpp
index 16a19ca4d36a..ddddefac74b9 100644
--- a/libs/hwui/SkiaCanvasProxy.cpp
+++ b/libs/hwui/SkiaCanvasProxy.cpp
@@ -179,7 +179,7 @@ void SkiaCanvasProxy::onDrawImageLattice(const SkImage* image, const Lattice& la
SkLatticeIter iter(lattice, dst);
SkRect srcR, dstR;
while (iter.next(&srcR, &dstR)) {
- onDrawImageRect(image, &srcR, dstR, paint, SkCanvas::kStrict_SrcRectConstraint);
+ onDrawImageRect(image, &srcR, dstR, paint, SkCanvas::kFast_SrcRectConstraint);
}
}
@@ -452,7 +452,7 @@ void SkiaCanvasProxy::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScala
break;
}
default:
- SkFAIL("unhandled positioning mode");
+ SK_ABORT("unhandled positioning mode");
}
}
}
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
index 8a1de02e6a0c..f4ce864e83e1 100644
--- a/libs/hwui/VectorDrawable.cpp
+++ b/libs/hwui/VectorDrawable.cpp
@@ -565,7 +565,7 @@ void Tree::draw(SkCanvas* canvas) {
sk_sp<SkSurface> vdSurface = mCache.getSurface(&src);
if (vdSurface) {
canvas->drawImageRect(vdSurface->makeImageSnapshot().get(), src,
- mutateProperties()->getBounds(), getPaint());
+ mutateProperties()->getBounds(), getPaint(), SkCanvas::kFast_SrcRectConstraint);
} else {
// Handle the case when VectorDrawableAtlas has been destroyed, because of memory pressure.
// We render the VD into a temporary standalone buffer and mark the frame as dirty. Next
@@ -585,7 +585,7 @@ void Tree::draw(SkCanvas* canvas) {
draw(surface.get(), src);
mCache.clear();
canvas->drawImageRect(surface->makeImageSnapshot().get(), mutateProperties()->getBounds(),
- getPaint());
+ getPaint(), SkCanvas::kFast_SrcRectConstraint);
markDirty();
}
}
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index 75b6d233643d..0aeb7627233a 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -31,6 +31,7 @@
#include <ui/PixelFormat.h>
#include <SkCanvas.h>
+#include <SkToSRGBColorFilter.h>
#include <SkImagePriv.h>
namespace android {
@@ -208,11 +209,8 @@ Bitmap::Bitmap(GraphicBuffer* buffer, const SkImageInfo& info)
buffer->incStrong(buffer);
setImmutable(); // HW bitmaps are always immutable
if (uirenderer::Properties::isSkiaEnabled()) {
- // GraphicBuffer should be in the display color space (Bitmap::createFrom is always
- // passing SRGB). The code that uploads into a GraphicBuffer should do color conversion if
- // needed.
mImage = SkImage::MakeFromAHardwareBuffer(reinterpret_cast<AHardwareBuffer*>(buffer),
- mInfo.alphaType(), nullptr);
+ mInfo.alphaType(), mInfo.refColorSpace());
}
}
@@ -319,7 +317,7 @@ GraphicBuffer* Bitmap::graphicBuffer() {
return nullptr;
}
-sk_sp<SkImage> Bitmap::makeImage() {
+sk_sp<SkImage> Bitmap::makeImage(sk_sp<SkColorFilter>* outputColorFilter) {
sk_sp<SkImage> image = mImage;
if (!image) {
SkASSERT(!(isHardware() && uirenderer::Properties::isSkiaEnabled()));
@@ -330,12 +328,11 @@ sk_sp<SkImage> Bitmap::makeImage() {
// Note we don't cache in this case, because the raster image holds a pointer to this Bitmap
// internally and ~Bitmap won't be invoked.
// TODO: refactor Bitmap to not derive from SkPixelRef, which would allow caching here.
- if (uirenderer::Properties::isSkiaEnabled()) {
- image = SkMakeImageInColorSpace(skiaBitmap, SkColorSpace::MakeSRGB(),
- skiaBitmap.getGenerationID(), kNever_SkCopyPixelsMode);
- } else {
- image = SkMakeImageFromRasterBitmap(skiaBitmap, kNever_SkCopyPixelsMode);
- }
+ image = SkMakeImageFromRasterBitmap(skiaBitmap, kNever_SkCopyPixelsMode);
+ }
+ if(uirenderer::Properties::isSkiaEnabled() && image->colorSpace() != nullptr
+ && !image->colorSpace()->isSRGB()) {
+ *outputColorFilter = SkToSRGBColorFilter::Make(image->refColorSpace());
}
return image;
}
diff --git a/libs/hwui/hwui/Bitmap.h b/libs/hwui/hwui/Bitmap.h
index 634e76450c38..fc27af9fb4e7 100644
--- a/libs/hwui/hwui/Bitmap.h
+++ b/libs/hwui/hwui/Bitmap.h
@@ -16,6 +16,7 @@
#pragma once
#include <SkBitmap.h>
+#include <SkColorFilter.h>
#include <SkColorSpace.h>
#include <SkImage.h>
#include <SkImageInfo.h>
@@ -96,9 +97,18 @@ public:
GraphicBuffer* graphicBuffer();
- // makeImage creates or returns a cached SkImage. Can be invoked from UI or render thread.
- // Caching is supported only for HW Bitmaps with skia pipeline.
- sk_sp<SkImage> makeImage();
+ /**
+ * Creates or returns a cached SkImage and is safe to be invoked from either
+ * the UI or RenderThread.
+ *
+ * @param outputColorFilter is a required param that will be populated by
+ * this function if the bitmap's colorspace is not sRGB. If populated the
+ * filter will convert colors from the bitmaps colorspace into sRGB. It
+ * is the callers responsibility to use this colorFilter when drawing
+ * this image into any destination that is presumed to be sRGB (i.e. a
+ * buffer that has no colorspace defined).
+ */
+ sk_sp<SkImage> makeImage(sk_sp<SkColorFilter>* outputColorFilter);
private:
virtual ~Bitmap();
void* getStorage() const;
diff --git a/libs/hwui/hwui/Canvas.cpp b/libs/hwui/hwui/Canvas.cpp
index e754daf7c42e..a087035fd8e5 100644
--- a/libs/hwui/hwui/Canvas.cpp
+++ b/libs/hwui/hwui/Canvas.cpp
@@ -158,7 +158,7 @@ private:
};
void Canvas::drawText(const uint16_t* text, int start, int count, int contextCount,
- float x, float y, int bidiFlags, const Paint& origPaint, Typeface* typeface) {
+ float x, float y, int bidiFlags, const Paint& origPaint, const Typeface* typeface) {
// minikin may modify the original paint
Paint paint(origPaint);
@@ -207,7 +207,7 @@ private:
};
void Canvas::drawTextOnPath(const uint16_t* text, int count, int bidiFlags, const SkPath& path,
- float hOffset, float vOffset, const Paint& paint, Typeface* typeface) {
+ float hOffset, float vOffset, const Paint& paint, const Typeface* typeface) {
Paint paintCopy(paint);
minikin::Layout layout = MinikinUtils::doLayout(
&paintCopy, bidiFlags, typeface, text, 0, count, count);
diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h
index ac8a08169997..fbd89606fc9d 100644
--- a/libs/hwui/hwui/Canvas.h
+++ b/libs/hwui/hwui/Canvas.h
@@ -20,6 +20,7 @@
#include <utils/Functor.h>
#include "GlFunctorLifecycleListener.h"
+#include "Properties.h"
#include "utils/Macros.h"
#include <androidfw/ResourceTypes.h>
@@ -98,15 +99,6 @@ public:
static WARN_UNUSED_RESULT Canvas* create_recording_canvas(int width, int height,
uirenderer::RenderNode* renderNode = nullptr);
- enum class XformToSRGB {
- // Transform any Bitmaps to the sRGB color space before drawing.
- kImmediate,
-
- // Draw the Bitmap as is. This likely means that we are recording and that the
- // transform can be handled at playback time.
- kDefer,
- };
-
/**
* Create a new Canvas object which delegates to an SkCanvas.
*
@@ -114,12 +106,10 @@ public:
* delegated to this object. This function will call ref() on the
* SkCanvas, and the returned Canvas will unref() it upon
* destruction.
- * @param xformToSRGB Indicates if bitmaps should be xformed to the sRGB
- * color space before drawing.
* @return new non-null Canvas Object. The type of DisplayList produced by this canvas is
* determined based on Properties::getRenderPipelineType().
*/
- static Canvas* create_canvas(SkCanvas* skiaCanvas, XformToSRGB xformToSRGB);
+ static Canvas* create_canvas(SkCanvas* skiaCanvas);
/**
* Provides a Skia SkCanvas interface that acts as a proxy to this Canvas.
@@ -151,8 +141,7 @@ public:
virtual uirenderer::DisplayList* finishRecording() = 0;
virtual void insertReorderBarrier(bool enableReorder) = 0;
- virtual void setHighContrastText(bool highContrastText) = 0;
- virtual bool isHighContrastText() = 0;
+ bool isHighContrastText() const { return uirenderer::Properties::enableHighContrastText; }
virtual void drawRoundRect(uirenderer::CanvasPropertyPrimitive* left,
uirenderer::CanvasPropertyPrimitive* top, uirenderer::CanvasPropertyPrimitive* right,
@@ -266,10 +255,10 @@ public:
* and delegating the final draw to virtual drawGlyphs method.
*/
void drawText(const uint16_t* text, int start, int count, int contextCount,
- float x, float y, int bidiFlags, const Paint& origPaint, Typeface* typeface);
+ float x, float y, int bidiFlags, const Paint& origPaint, const Typeface* typeface);
void drawTextOnPath(const uint16_t* text, int count, int bidiFlags, const SkPath& path,
- float hOffset, float vOffset, const Paint& paint, Typeface* typeface);
+ float hOffset, float vOffset, const Paint& paint, const Typeface* typeface);
protected:
void drawTextDecorations(float x, float y, float length, const SkPaint& paint);
diff --git a/libs/hwui/hwui/MinikinSkia.cpp b/libs/hwui/hwui/MinikinSkia.cpp
index ba4e3a4df578..2b29542fb623 100644
--- a/libs/hwui/hwui/MinikinSkia.cpp
+++ b/libs/hwui/hwui/MinikinSkia.cpp
@@ -67,6 +67,17 @@ void MinikinFontSkia::GetBounds(minikin::MinikinRect* bounds, uint32_t glyph_id,
bounds->mBottom = skBounds.fBottom;
}
+void MinikinFontSkia::GetFontExtent(minikin::MinikinExtent* extent,
+ const minikin::MinikinPaint& paint) const {
+ SkPaint skPaint;
+ MinikinFontSkia_SetSkiaPaint(this, &skPaint, paint);
+ SkPaint::FontMetrics metrics;
+ skPaint.getFontMetrics(&metrics);
+ extent->ascent = metrics.fAscent;
+ extent->descent = metrics.fDescent;
+ extent->line_gap = metrics.fLeading;
+}
+
SkTypeface *MinikinFontSkia::GetSkTypeface() const {
return mTypeface.get();
}
diff --git a/libs/hwui/hwui/MinikinSkia.h b/libs/hwui/hwui/MinikinSkia.h
index 6c12485845fd..a19f4a769444 100644
--- a/libs/hwui/hwui/MinikinSkia.h
+++ b/libs/hwui/hwui/MinikinSkia.h
@@ -37,6 +37,9 @@ public:
void GetBounds(minikin::MinikinRect* bounds, uint32_t glyph_id,
const minikin::MinikinPaint &paint) const;
+ void GetFontExtent(minikin::MinikinExtent* extent,
+ const minikin::MinikinPaint &paint) const;
+
SkTypeface* GetSkTypeface() const;
sk_sp<SkTypeface> RefSkTypeface() const;
diff --git a/libs/hwui/hwui/MinikinUtils.cpp b/libs/hwui/hwui/MinikinUtils.cpp
index 415eef77f44e..7da7f3876a3d 100644
--- a/libs/hwui/hwui/MinikinUtils.cpp
+++ b/libs/hwui/hwui/MinikinUtils.cpp
@@ -27,7 +27,7 @@
namespace android {
minikin::FontStyle MinikinUtils::prepareMinikinPaint(minikin::MinikinPaint* minikinPaint,
- const Paint* paint, Typeface* typeface) {
+ const Paint* paint, const Typeface* typeface) {
const Typeface* resolvedFace = Typeface::resolveDefault(typeface);
minikin::FontStyle resolved = resolvedFace->fStyle;
@@ -39,10 +39,8 @@ minikin::FontStyle MinikinUtils::prepareMinikinPaint(minikin::MinikinPaint* mini
resolved.getItalic());
/* Prepare minikin Paint */
- // Note: it would be nice to handle fractional size values (it would improve smooth zoom
- // behavior), but historically size has been treated as an int.
- // TODO: explore whether to enable fractional sizes, possibly when linear text flag is set.
- minikinPaint->size = (int)paint->getTextSize();
+ minikinPaint->size = paint->isLinearText() ?
+ paint->getTextSize() : static_cast<int>(paint->getTextSize());
minikinPaint->scaleX = paint->getTextScaleX();
minikinPaint->skewX = paint->getTextSkewX();
minikinPaint->letterSpacing = paint->getLetterSpacing();
@@ -54,7 +52,7 @@ minikin::FontStyle MinikinUtils::prepareMinikinPaint(minikin::MinikinPaint* mini
}
minikin::Layout MinikinUtils::doLayout(const Paint* paint, int bidiFlags,
- Typeface* typeface, const uint16_t* buf, size_t start, size_t count,
+ const Typeface* typeface, const uint16_t* buf, size_t start, size_t count,
size_t bufSize) {
minikin::MinikinPaint minikinPaint;
minikin::FontStyle minikinStyle = prepareMinikinPaint(&minikinPaint, paint, typeface);
@@ -64,16 +62,17 @@ minikin::Layout MinikinUtils::doLayout(const Paint* paint, int bidiFlags,
return layout;
}
-float MinikinUtils::measureText(const Paint* paint, int bidiFlags, Typeface* typeface,
+float MinikinUtils::measureText(const Paint* paint, int bidiFlags, const Typeface* typeface,
const uint16_t* buf, size_t start, size_t count, size_t bufSize, float *advances) {
minikin::MinikinPaint minikinPaint;
minikin::FontStyle minikinStyle = prepareMinikinPaint(&minikinPaint, paint, typeface);
- Typeface* resolvedTypeface = Typeface::resolveDefault(typeface);
+ const Typeface* resolvedTypeface = Typeface::resolveDefault(typeface);
return minikin::Layout::measureText(buf, start, count, bufSize, bidiFlags, minikinStyle,
- minikinPaint, resolvedTypeface->fFontCollection, advances);
+ minikinPaint, resolvedTypeface->fFontCollection, advances, nullptr /* extent */,
+ nullptr /* overhangs */);
}
-bool MinikinUtils::hasVariationSelector(Typeface* typeface, uint32_t codepoint, uint32_t vs) {
+bool MinikinUtils::hasVariationSelector(const Typeface* typeface, uint32_t codepoint, uint32_t vs) {
const Typeface* resolvedFace = Typeface::resolveDefault(typeface);
return resolvedFace->fFontCollection->hasVariationSelector(codepoint, vs);
}
diff --git a/libs/hwui/hwui/MinikinUtils.h b/libs/hwui/hwui/MinikinUtils.h
index 0f22adc5d42b..bfd816fd3b58 100644
--- a/libs/hwui/hwui/MinikinUtils.h
+++ b/libs/hwui/hwui/MinikinUtils.h
@@ -35,16 +35,17 @@ namespace android {
class MinikinUtils {
public:
ANDROID_API static minikin::FontStyle prepareMinikinPaint(minikin::MinikinPaint* minikinPaint,
- const Paint* paint, Typeface* typeface);
+ const Paint* paint, const Typeface* typeface);
ANDROID_API static minikin::Layout doLayout(const Paint* paint, int bidiFlags,
- Typeface* typeface, const uint16_t* buf, size_t start, size_t count,
+ const Typeface* typeface, const uint16_t* buf, size_t start, size_t count,
size_t bufSize);
- ANDROID_API static float measureText(const Paint* paint, int bidiFlags, Typeface* typeface,
- const uint16_t* buf, size_t start, size_t count, size_t bufSize, float *advances);
+ ANDROID_API static float measureText(const Paint* paint, int bidiFlags,
+ const Typeface* typeface, const uint16_t* buf, size_t start, size_t count,
+ size_t bufSize, float *advances);
- ANDROID_API static bool hasVariationSelector(Typeface* typeface, uint32_t codepoint,
+ ANDROID_API static bool hasVariationSelector(const Typeface* typeface, uint32_t codepoint,
uint32_t vs);
ANDROID_API static float xOffsetForTextAlign(Paint* paint, const minikin::Layout& layout);
diff --git a/libs/hwui/hwui/Paint.h b/libs/hwui/hwui/Paint.h
index a5d83a0ca018..f3779fddb620 100644
--- a/libs/hwui/hwui/Paint.h
+++ b/libs/hwui/hwui/Paint.h
@@ -17,6 +17,8 @@
#ifndef ANDROID_GRAPHICS_PAINT_H_
#define ANDROID_GRAPHICS_PAINT_H_
+#include "Typeface.h"
+
#include <cutils/compiler.h>
#include <SkPaint.h>
@@ -101,6 +103,14 @@ public:
return mHyphenEdit;
}
+ void setAndroidTypeface(Typeface* typeface) {
+ mTypeface = typeface;
+ }
+
+ const Typeface* getAndroidTypeface() const {
+ return mTypeface;
+ }
+
private:
float mLetterSpacing = 0;
float mWordSpacing = 0;
@@ -108,6 +118,10 @@ private:
uint32_t mMinikinLangListId;
minikin::FontVariant mFontVariant;
uint32_t mHyphenEdit = 0;
+ // The native Typeface object has the same lifetime of the Java Typeface object. The Java Paint
+ // object holds a strong reference to the Java Typeface object. Thus, following pointer can
+ // never be a dangling pointer. Note that nullptr is valid: it means the default typeface.
+ const Typeface* mTypeface = nullptr;
};
} // namespace android
diff --git a/libs/hwui/hwui/PaintImpl.cpp b/libs/hwui/hwui/PaintImpl.cpp
index 67427433bb89..a5c2087490aa 100644
--- a/libs/hwui/hwui/PaintImpl.cpp
+++ b/libs/hwui/hwui/PaintImpl.cpp
@@ -27,7 +27,8 @@ Paint::Paint(const Paint& paint) : SkPaint(paint),
mLetterSpacing(paint.mLetterSpacing), mWordSpacing(paint.mWordSpacing),
mFontFeatureSettings(paint.mFontFeatureSettings),
mMinikinLangListId(paint.mMinikinLangListId), mFontVariant(paint.mFontVariant),
- mHyphenEdit(paint.mHyphenEdit) {
+ mHyphenEdit(paint.mHyphenEdit),
+ mTypeface(paint.mTypeface) {
}
Paint::Paint(const SkPaint& paint) : SkPaint(paint),
@@ -46,6 +47,7 @@ Paint& Paint::operator=(const Paint& other) {
mMinikinLangListId = other.mMinikinLangListId;
mFontVariant = other.mFontVariant;
mHyphenEdit = other.mHyphenEdit;
+ mTypeface = other.mTypeface;
return *this;
}
@@ -56,7 +58,8 @@ bool operator==(const Paint& a, const Paint& b) {
&& a.mFontFeatureSettings == b.mFontFeatureSettings
&& a.mMinikinLangListId == b.mMinikinLangListId
&& a.mFontVariant == b.mFontVariant
- && a.mHyphenEdit == b.mHyphenEdit;
+ && a.mHyphenEdit == b.mHyphenEdit
+ && a.mTypeface == b.mTypeface;
}
}
diff --git a/libs/hwui/hwui/Typeface.cpp b/libs/hwui/hwui/Typeface.cpp
index f66bb045373c..0a388745b14c 100644
--- a/libs/hwui/hwui/Typeface.cpp
+++ b/libs/hwui/hwui/Typeface.cpp
@@ -14,12 +14,6 @@
* limitations under the License.
*/
-/**
- * This is the implementation of the Typeface object. Historically, it has
- * just been SkTypeface, but we are migrating to Minikin. For the time
- * being, that choice is hidden under the USE_MINIKIN compile-time flag.
- */
-
#include "Typeface.h"
#include <pthread.h>
@@ -65,15 +59,15 @@ static minikin::FontStyle computeRelativeStyle(int baseWeight, SkTypeface::Style
return computeMinikinStyle(weight, italic);
}
-Typeface* gDefaultTypeface = NULL;
+const Typeface* gDefaultTypeface = NULL;
-Typeface* Typeface::resolveDefault(Typeface* src) {
- LOG_ALWAYS_FATAL_IF(gDefaultTypeface == nullptr);
+const Typeface* Typeface::resolveDefault(const Typeface* src) {
+ LOG_ALWAYS_FATAL_IF(src == nullptr && gDefaultTypeface == nullptr);
return src == nullptr ? gDefaultTypeface : src;
}
Typeface* Typeface::createRelative(Typeface* src, SkTypeface::Style style) {
- Typeface* resolvedFace = Typeface::resolveDefault(src);
+ const Typeface* resolvedFace = Typeface::resolveDefault(src);
Typeface* result = new Typeface;
if (result != nullptr) {
result->fFontCollection = resolvedFace->fFontCollection;
@@ -85,7 +79,7 @@ Typeface* Typeface::createRelative(Typeface* src, SkTypeface::Style style) {
}
Typeface* Typeface::createAbsolute(Typeface* base, int weight, bool italic) {
- Typeface* resolvedFace = Typeface::resolveDefault(base);
+ const Typeface* resolvedFace = Typeface::resolveDefault(base);
Typeface* result = new Typeface();
if (result != nullptr) {
result->fFontCollection = resolvedFace->fFontCollection;
@@ -98,7 +92,7 @@ Typeface* Typeface::createAbsolute(Typeface* base, int weight, bool italic) {
Typeface* Typeface::createFromTypefaceWithVariation(Typeface* src,
const std::vector<minikin::FontVariation>& variations) {
- Typeface* resolvedFace = Typeface::resolveDefault(src);
+ const Typeface* resolvedFace = Typeface::resolveDefault(src);
Typeface* result = new Typeface();
if (result != nullptr) {
result->fFontCollection =
@@ -118,7 +112,7 @@ Typeface* Typeface::createFromTypefaceWithVariation(Typeface* src,
}
Typeface* Typeface::createWithDifferentBaseWeight(Typeface* src, int weight) {
- Typeface* resolvedFace = Typeface::resolveDefault(src);
+ const Typeface* resolvedFace = Typeface::resolveDefault(src);
Typeface* result = new Typeface;
if (result != nullptr) {
result->fFontCollection = resolvedFace->fFontCollection;
@@ -172,7 +166,7 @@ Typeface* Typeface::createFromFamilies(
return result;
}
-void Typeface::setDefault(Typeface* face) {
+void Typeface::setDefault(const Typeface* face) {
gDefaultTypeface = face;
}
diff --git a/libs/hwui/hwui/Typeface.h b/libs/hwui/hwui/Typeface.h
index db0b2cdeba00..38c623480196 100644
--- a/libs/hwui/hwui/Typeface.h
+++ b/libs/hwui/hwui/Typeface.h
@@ -41,7 +41,7 @@ struct ANDROID_API Typeface {
// style used for constructing and querying Typeface objects
SkTypeface::Style fSkiaStyle;
- static Typeface* resolveDefault(Typeface* src);
+ static const Typeface* resolveDefault(const Typeface* src);
// The following three functions create new Typeface from an existing Typeface with a different
// style. There is a base weight concept which is used for calculating relative style from an
@@ -78,7 +78,7 @@ struct ANDROID_API Typeface {
std::vector<std::shared_ptr<minikin::FontFamily>>&& families,
int weight, int italic);
- static void setDefault(Typeface* face);
+ static void setDefault(const Typeface* face);
// Sets roboto font as the default typeface for testing purpose.
static void setRobotoTypefaceForTest();
diff --git a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
index ea302a154616..fcd72afe4fb9 100644
--- a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
+++ b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
@@ -17,6 +17,7 @@
#include "GLFunctorDrawable.h"
#include "GlFunctorLifecycleListener.h"
#include "RenderNode.h"
+#include "SkAndroidFrameworkUtils.h"
#include "SkClipStack.h"
#include <private/hwui/DrawGlInfo.h>
#include <GrContext.h>
@@ -49,8 +50,6 @@ void GLFunctorDrawable::onDraw(SkCanvas* canvas) {
return;
}
- canvas->flush();
-
if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) {
canvas->clear(SK_ColorRED);
return;
@@ -72,33 +71,33 @@ void GLFunctorDrawable::onDraw(SkCanvas* canvas) {
info.height = canvasInfo.height();
mat4.asColMajorf(&info.transform[0]);
+ bool clearStencilAfterFunctor = false;
+
//apply a simple clip with a scissor or a complex clip with a stencil
SkRegion clipRegion;
canvas->temporary_internal_getRgnClip(&clipRegion);
if (CC_UNLIKELY(clipRegion.isComplex())) {
- //It is only a temporary solution to use a scissor to draw the stencil.
- //There is a bug 31489986 to implement efficiently non-rectangular clips.
glDisable(GL_SCISSOR_TEST);
- glDisable(GL_STENCIL_TEST);
- glStencilMask(0xff);
+ glStencilMask(0x1);
glClearStencil(0);
glClear(GL_STENCIL_BUFFER_BIT);
- glEnable(GL_SCISSOR_TEST);
- SkRegion::Cliperator it(clipRegion, ibounds);
- while (!it.done()) {
- setScissor(info.height, it.rect());
- glClearStencil(0x1);
- glClear(GL_STENCIL_BUFFER_BIT);
- it.next();
+ bool stencilWritten = SkAndroidFrameworkUtils::clipWithStencil(canvas);
+ canvas->flush();
+ if (stencilWritten) {
+ glStencilMask(0x1);
+ glStencilFunc(GL_EQUAL, 0x1, 0x1);
+ glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
+ clearStencilAfterFunctor = true;
+ glEnable(GL_STENCIL_TEST);
+ } else {
+ glDisable(GL_STENCIL_TEST);
}
- glDisable(GL_SCISSOR_TEST);
- glStencilFunc(GL_EQUAL, 0x1, 0xff);
- glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
- glEnable(GL_STENCIL_TEST);
} else if (clipRegion.isEmpty()) {
+ canvas->flush();
glDisable(GL_STENCIL_TEST);
glDisable(GL_SCISSOR_TEST);
} else {
+ canvas->flush();
glDisable(GL_STENCIL_TEST);
glEnable(GL_SCISSOR_TEST);
setScissor(info.height, clipRegion.getBounds());
@@ -106,6 +105,15 @@ void GLFunctorDrawable::onDraw(SkCanvas* canvas) {
(*mFunctor)(DrawGlInfo::kModeDraw, &info);
+ if (clearStencilAfterFunctor) {
+ //clear stencil buffer as it may be used by Skia
+ glDisable(GL_SCISSOR_TEST);
+ glDisable(GL_STENCIL_TEST);
+ glStencilMask(0x1);
+ glClearStencil(0);
+ glClear(GL_STENCIL_BUFFER_BIT);
+ }
+
canvas->getGrContext()->resetContext();
}
diff --git a/libs/hwui/pipeline/skia/LayerDrawable.cpp b/libs/hwui/pipeline/skia/LayerDrawable.cpp
index 4feeb2d6facb..17438e5e1cdc 100644
--- a/libs/hwui/pipeline/skia/LayerDrawable.cpp
+++ b/libs/hwui/pipeline/skia/LayerDrawable.cpp
@@ -28,7 +28,10 @@ namespace uirenderer {
namespace skiapipeline {
void LayerDrawable::onDraw(SkCanvas* canvas) {
- DrawLayer(canvas->getGrContext(), canvas, mLayer.get());
+ Layer* layer = mLayerUpdater->backingLayer();
+ if (layer) {
+ DrawLayer(canvas->getGrContext(), canvas, layer);
+ }
}
bool LayerDrawable::DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer) {
diff --git a/libs/hwui/pipeline/skia/LayerDrawable.h b/libs/hwui/pipeline/skia/LayerDrawable.h
index 431989519a70..d34d8e07c133 100644
--- a/libs/hwui/pipeline/skia/LayerDrawable.h
+++ b/libs/hwui/pipeline/skia/LayerDrawable.h
@@ -16,7 +16,7 @@
#pragma once
-#include "Layer.h"
+#include "DeferredLayerUpdater.h"
#include <SkCanvas.h>
#include <SkDrawable.h>
@@ -30,18 +30,18 @@ namespace skiapipeline {
*/
class LayerDrawable : public SkDrawable {
public:
- explicit LayerDrawable(Layer* layer)
- : mLayer(layer) {}
+ explicit LayerDrawable(DeferredLayerUpdater* layerUpdater)
+ : mLayerUpdater(layerUpdater) {}
static bool DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer);
protected:
virtual SkRect onGetBounds() override {
- return SkRect::MakeWH(mLayer->getWidth(), mLayer->getHeight());
+ return SkRect::MakeWH(mLayerUpdater->getWidth(), mLayerUpdater->getHeight());
}
virtual void onDraw(SkCanvas* canvas) override;
private:
- sp<Layer> mLayer;
+ sp<DeferredLayerUpdater> mLayerUpdater;
};
}; // namespace skiapipeline
diff --git a/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp b/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp
index 374d364787de..c8207bc70dd4 100644
--- a/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp
+++ b/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp
@@ -163,28 +163,22 @@ void EndReorderBarrierDrawable::drawShadow(SkCanvas* canvas, RenderNodeDrawable*
hwuiMatrix.copyTo(shadowMatrix);
canvas->concat(shadowMatrix);
- const SkPath* casterOutlinePath = casterProperties.getOutline().getPath();
- // holds temporary SkPath to store the result of intersections
- SkPath tmpPath;
- const SkPath* casterPath = casterOutlinePath;
+ // default the shadow-casting path to the outline of the caster
+ const SkPath* casterPath = casterProperties.getOutline().getPath();
+
+ // intersect the shadow-casting path with the clipBounds, if present
+ if (clippedToBounds && !casterClipRect.contains(casterPath->getBounds())) {
+ casterPath = caster->getRenderNode()->getClippedOutline(casterClipRect);
+ }
- // TODO: In to following course of code that calculates the final shape, is there an optimal
- // of doing the Op calculations?
// intersect the shadow-casting path with the reveal, if present
+ SkPath tmpPath; // holds temporary SkPath to store the result of intersections
if (revealClipPath) {
Op(*casterPath, *revealClipPath, kIntersect_SkPathOp, &tmpPath);
tmpPath.setIsVolatile(true);
casterPath = &tmpPath;
}
- // intersect the shadow-casting path with the clipBounds, if present
- if (clippedToBounds) {
- SkPath clipBoundsPath;
- clipBoundsPath.addRect(casterClipRect);
- Op(*casterPath, clipBoundsPath, kIntersect_SkPathOp, &tmpPath);
- tmpPath.setIsVolatile(true);
- casterPath = &tmpPath;
- }
const Vector3 lightPos = SkiaPipeline::getLightCenter();
SkPoint3 skiaLightPos = SkPoint3::Make(lightPos.x, lightPos.y, lightPos.z);
SkPoint3 zParams;
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
index 925db303461f..abba70e4bdd5 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
@@ -73,9 +73,11 @@ bool SkiaOpenGLPipeline::draw(const Frame& frame, const SkRect& screenDirty,
// setup surface for fbo0
GrGLFramebufferInfo fboInfo;
fboInfo.fFBOID = 0;
+ GrPixelConfig pixelConfig =
+ wideColorGamut ? kRGBA_half_GrPixelConfig : kRGBA_8888_GrPixelConfig;
GrBackendRenderTarget backendRT(frame.width(), frame.height(), 0, STENCIL_BUFFER_SIZE,
- kRGBA_8888_GrPixelConfig, fboInfo);
+ pixelConfig, fboInfo);
SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
@@ -132,9 +134,24 @@ bool SkiaOpenGLPipeline::copyLayerInto(DeferredLayerUpdater* deferredLayer, SkBi
deferredLayer->updateTexImage();
deferredLayer->apply();
- SkCanvas canvas(*bitmap);
+ /* This intermediate surface is present to work around a bug in SwiftShader that
+ * prevents us from reading the contents of the layer's texture directly. The
+ * workaround involves first rendering that texture into an intermediate buffer and
+ * then reading from the intermediate buffer into the bitmap.
+ */
+ sk_sp<SkSurface> tmpSurface = SkSurface::MakeRenderTarget(mRenderThread.getGrContext(),
+ SkBudgeted::kYes, bitmap->info());
+
Layer* layer = deferredLayer->backingLayer();
- return LayerDrawable::DrawLayer(mRenderThread.getGrContext(), &canvas, layer);
+ if (LayerDrawable::DrawLayer(mRenderThread.getGrContext(), tmpSurface->getCanvas(), layer)) {
+ sk_sp<SkImage> tmpImage = tmpSurface->makeImageSnapshot();
+ if (tmpImage->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), 0, 0)) {
+ bitmap->notifyPixelsChanged();
+ return true;
+ }
+ }
+
+ return false;
}
static Layer* createLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight,
@@ -303,12 +320,6 @@ sk_sp<Bitmap> SkiaOpenGLPipeline::allocateHardwareBitmap(renderthread::RenderThr
return nullptr;
}
- auto colorSpace = info.colorSpace();
- bool convertToSRGB = false;
- if (colorSpace && (!colorSpace->isSRGB())) {
- isSupported = false;
- convertToSRGB = true;
- }
SkBitmap bitmap;
if (isSupported) {
@@ -317,7 +328,7 @@ sk_sp<Bitmap> SkiaOpenGLPipeline::allocateHardwareBitmap(renderthread::RenderThr
bitmap.allocPixels(SkImageInfo::MakeN32(info.width(), info.height(), info.alphaType(),
nullptr));
bitmap.eraseColor(0);
- if (info.colorType() == kRGBA_F16_SkColorType || convertToSRGB) {
+ if (info.colorType() == kRGBA_F16_SkColorType) {
// Drawing RGBA_F16 onto ARGB_8888 is not supported
skBitmap.readPixels(bitmap.info().makeColorSpace(SkColorSpace::MakeSRGB()),
bitmap.getPixels(), bitmap.rowBytes(), 0, 0);
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp
index 311419dd2b65..9982a0cfe2bf 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp
@@ -16,6 +16,7 @@
#include "SkiaOpenGLReadback.h"
+#include "DeviceInfo.h"
#include "Matrix.h"
#include "Properties.h"
#include <SkCanvas.h>
@@ -54,28 +55,60 @@ CopyResult SkiaOpenGLReadback::copyImageInto(EGLImageKHR eglImage, const Matrix4
externalTexture.fTarget = GL_TEXTURE_EXTERNAL_OES;
externalTexture.fID = sourceTexId;
- GrBackendTexture backendTexture(imgWidth, imgHeight, kRGBA_8888_GrPixelConfig, externalTexture);
+ GrPixelConfig pixelConfig;
+ switch (bitmap->colorType()) {
+ case kRGBA_F16_SkColorType:
+ pixelConfig = kRGBA_half_GrPixelConfig;
+ break;
+ case kN32_SkColorType:
+ default:
+ pixelConfig = kRGBA_8888_GrPixelConfig;
+ break;
+ }
+
+ /* Ideally, we would call grContext->caps()->isConfigRenderable(...). We
+ * currently can't do that since some devices (i.e. SwiftShader) supports all
+ * the appropriate half float extensions, but only allow the buffer to be read
+ * back as full floats. We can relax this extension if Skia implements support
+ * for reading back float buffers (skbug.com/6945).
+ */
+ if (pixelConfig == kRGBA_half_GrPixelConfig &&
+ !DeviceInfo::get()->extensions().hasFloatTextures()) {
+ ALOGW("Can't copy surface into bitmap, RGBA_F16 config is not supported");
+ return CopyResult::DestinationInvalid;
+ }
+
+ GrBackendTexture backendTexture(imgWidth, imgHeight, pixelConfig, externalTexture);
CopyResult copyResult = CopyResult::UnknownError;
sk_sp<SkImage> image(SkImage::MakeFromAdoptedTexture(grContext.get(), backendTexture,
kTopLeft_GrSurfaceOrigin));
if (image) {
+ // Convert imgTransform matrix from right to left handed coordinate system.
+ // If we have a matrix transformation in right handed coordinate system
+ //|ScaleX, SkewX, TransX| same transform in left handed is |ScaleX, SkewX, TransX |
+ //|SkewY, ScaleY, TransY| |-SkewY, -ScaleY, 1-TransY|
+ //|0, 0, 1 | |0, 0, 1 |
SkMatrix textureMatrix;
- imgTransform.copyTo(textureMatrix);
-
- // remove the y-flip applied to the matrix
- SkMatrix yFlip = SkMatrix::MakeScale(1, -1);
- yFlip.postTranslate(0,1);
- textureMatrix.preConcat(yFlip);
-
- // multiply by image size, because textureMatrix maps to [0..1] range
- textureMatrix[SkMatrix::kMTransX] *= imgWidth;
- textureMatrix[SkMatrix::kMTransY] *= imgHeight;
-
- // swap rotation and translation part of the matrix, because we convert from
- // right-handed Cartesian to left-handed coordinate system.
- std::swap(textureMatrix[SkMatrix::kMTransX], textureMatrix[SkMatrix::kMTransY]);
- std::swap(textureMatrix[SkMatrix::kMSkewX], textureMatrix[SkMatrix::kMSkewY]);
+ textureMatrix.setIdentity();
+ textureMatrix[SkMatrix::kMScaleX] = imgTransform[Matrix4::kScaleX];
+ textureMatrix[SkMatrix::kMScaleY] = -imgTransform[Matrix4::kScaleY];
+ textureMatrix[SkMatrix::kMSkewX] = imgTransform[Matrix4::kSkewX];
+ textureMatrix[SkMatrix::kMSkewY] = -imgTransform[Matrix4::kSkewY];
+ textureMatrix[SkMatrix::kMTransX] = imgTransform[Matrix4::kTranslateX];
+ textureMatrix[SkMatrix::kMTransY] = 1-imgTransform[Matrix4::kTranslateY];
+
+ // textureMatrix maps 2D texture coordinates of the form (s, t, 1) with s and t in the
+ // inclusive range [0, 1] to the texture (see GLConsumer::getTransformMatrix comments).
+ // Convert textureMatrix to translate in real texture dimensions. Texture width and
+ // height are affected by the orientation (width and height swapped for 90/270 rotation).
+ if (textureMatrix[SkMatrix::kMSkewX] >= 0.5f || textureMatrix[SkMatrix::kMSkewX] <= -0.5f) {
+ textureMatrix[SkMatrix::kMTransX] *= imgHeight;
+ textureMatrix[SkMatrix::kMTransY] *= imgWidth;
+ } else {
+ textureMatrix[SkMatrix::kMTransX] *= imgWidth;
+ textureMatrix[SkMatrix::kMTransY] *= imgHeight;
+ }
// convert to Skia data structures
SkRect skiaSrcRect = srcRect.toSkRect();
@@ -103,7 +136,8 @@ CopyResult SkiaOpenGLReadback::copyImageInto(EGLImageKHR eglImage, const Matrix4
SkPaint paint;
paint.setBlendMode(SkBlendMode::kSrc);
scaledSurface->getCanvas()->concat(textureMatrix);
- scaledSurface->getCanvas()->drawImageRect(image, skiaSrcRect, skiaDestRect, &paint);
+ scaledSurface->getCanvas()->drawImageRect(image, skiaSrcRect, skiaDestRect, &paint,
+ SkCanvas::kFast_SrcRectConstraint);
image = scaledSurface->makeImageSnapshot();
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index 03792e0ed291..a8463ecc44d8 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -134,7 +134,13 @@ bool SkiaPipeline::createOrUpdateLayer(RenderNode* node,
const DamageAccumulator& damageAccumulator, bool wideColorGamut) {
SkSurface* layer = node->getLayerSurface();
if (!layer || layer->width() != node->getWidth() || layer->height() != node->getHeight()) {
- SkImageInfo info = SkImageInfo::MakeN32Premul(node->getWidth(), node->getHeight());
+ SkImageInfo info;
+ if (wideColorGamut) {
+ info = SkImageInfo::Make(node->getWidth(), node->getHeight(), kRGBA_F16_SkColorType,
+ kPremul_SkAlphaType);
+ } else {
+ info = SkImageInfo::MakeN32Premul(node->getWidth(), node->getHeight());
+ }
SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
SkASSERT(mRenderThread.getGrContext() != nullptr);
// TODO: Handle wide color gamut requests
@@ -161,7 +167,8 @@ void SkiaPipeline::prepareToDraw(const RenderThread& thread, Bitmap* bitmap) {
GrContext* context = thread.getGrContext();
if (context) {
ATRACE_FORMAT("Bitmap#prepareToDraw %dx%d", bitmap->width(), bitmap->height());
- auto image = bitmap->makeImage();
+ sk_sp<SkColorFilter> colorFilter;
+ auto image = bitmap->makeImage(&colorFilter);
if (image.get() && !bitmap->isHardware()) {
SkImage_pinAsTexture(image.get(), context);
SkImage_unpinAsTexture(image.get(), context);
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index a0cce98c8d57..0bdf15333647 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -91,10 +91,9 @@ void SkiaRecordingCanvas::insertReorderBarrier(bool enableReorder) {
}
void SkiaRecordingCanvas::drawLayer(uirenderer::DeferredLayerUpdater* layerUpdater) {
- if (layerUpdater != nullptr && layerUpdater->backingLayer() != nullptr) {
- uirenderer::Layer* layer = layerUpdater->backingLayer();
+ if (layerUpdater != nullptr) {
// Create a ref-counted drawable, which is kept alive by sk_sp in SkLiteDL.
- sk_sp<SkDrawable> drawable(new LayerDrawable(layer));
+ sk_sp<SkDrawable> drawable(new LayerDrawable(layerUpdater));
drawDrawable(drawable.get());
}
}
@@ -145,10 +144,23 @@ void SkiaRecordingCanvas::drawVectorDrawable(VectorDrawableRoot* tree) {
// Recording Canvas draw operations: Bitmaps
// ----------------------------------------------------------------------------
-inline static const SkPaint* nonAAPaint(const SkPaint* origPaint, SkPaint* tmpPaint) {
- if (origPaint && origPaint->isAntiAlias()) {
- *tmpPaint = *origPaint;
+inline static const SkPaint* bitmapPaint(const SkPaint* origPaint, SkPaint* tmpPaint,
+ sk_sp<SkColorFilter> colorFilter) {
+ if ((origPaint && origPaint->isAntiAlias()) || colorFilter) {
+ if (origPaint) {
+ *tmpPaint = *origPaint;
+ }
+
+ sk_sp<SkColorFilter> filter;
+ if (colorFilter && tmpPaint->getColorFilter()) {
+ filter = SkColorFilter::MakeComposeFilter(tmpPaint->refColorFilter(), colorFilter);
+ LOG_ALWAYS_FATAL_IF(!filter);
+ } else {
+ filter = colorFilter;
+ }
+
tmpPaint->setAntiAlias(false);
+ tmpPaint->setColorFilter(filter);
return tmpPaint;
} else {
return origPaint;
@@ -156,9 +168,10 @@ inline static const SkPaint* nonAAPaint(const SkPaint* origPaint, SkPaint* tmpPa
}
void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) {
- sk_sp<SkImage> image = bitmap.makeImage();
SkPaint tmpPaint;
- mRecorder.drawImage(image, left, top, nonAAPaint(paint, &tmpPaint));
+ sk_sp<SkColorFilter> colorFilter;
+ sk_sp<SkImage> image = bitmap.makeImage(&colorFilter);
+ mRecorder.drawImage(image, left, top, bitmapPaint(paint, &tmpPaint, colorFilter));
// if image->unique() is true, then mRecorder.drawImage failed for some reason. It also means
// it is not safe to store a raw SkImage pointer, because the image object will be destroyed
// when this function ends.
@@ -167,36 +180,41 @@ void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float left, float top, cons
}
}
-void SkiaRecordingCanvas::drawBitmap(Bitmap& hwuiBitmap, const SkMatrix& matrix,
+void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, const SkMatrix& matrix,
const SkPaint* paint) {
SkAutoCanvasRestore acr(&mRecorder, true);
concat(matrix);
- sk_sp<SkImage> image = hwuiBitmap.makeImage();
+
SkPaint tmpPaint;
- mRecorder.drawImage(image, 0, 0, nonAAPaint(paint, &tmpPaint));
- if (!hwuiBitmap.isImmutable() && image.get() && !image->unique()) {
+ sk_sp<SkColorFilter> colorFilter;
+ sk_sp<SkImage> image = bitmap.makeImage(&colorFilter);
+ mRecorder.drawImage(image, 0, 0, bitmapPaint(paint, &tmpPaint, colorFilter));
+ if (!bitmap.isImmutable() && image.get() && !image->unique()) {
mDisplayList->mMutableImages.push_back(image.get());
}
}
-void SkiaRecordingCanvas::drawBitmap(Bitmap& hwuiBitmap, float srcLeft, float srcTop,
+void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop,
float srcRight, float srcBottom, float dstLeft, float dstTop, float dstRight,
float dstBottom, const SkPaint* paint) {
SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom);
SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
- sk_sp<SkImage> image = hwuiBitmap.makeImage();
+
SkPaint tmpPaint;
- mRecorder.drawImageRect(image, srcRect, dstRect, nonAAPaint(paint, &tmpPaint));
- if (!hwuiBitmap.isImmutable() && image.get() && !image->unique() && !srcRect.isEmpty()
+ sk_sp<SkColorFilter> colorFilter;
+ sk_sp<SkImage> image = bitmap.makeImage(&colorFilter);
+ mRecorder.drawImageRect(image, srcRect, dstRect, bitmapPaint(paint, &tmpPaint, colorFilter),
+ SkCanvas::kFast_SrcRectConstraint);
+ if (!bitmap.isImmutable() && image.get() && !image->unique() && !srcRect.isEmpty()
&& !dstRect.isEmpty()) {
mDisplayList->mMutableImages.push_back(image.get());
}
}
-void SkiaRecordingCanvas::drawNinePatch(Bitmap& hwuiBitmap, const Res_png_9patch& chunk,
+void SkiaRecordingCanvas::drawNinePatch(Bitmap& bitmap, const Res_png_9patch& chunk,
float dstLeft, float dstTop, float dstRight, float dstBottom, const SkPaint* paint) {
SkCanvas::Lattice lattice;
- NinePatchUtils::SetLatticeDivs(&lattice, chunk, hwuiBitmap.width(), hwuiBitmap.height());
+ NinePatchUtils::SetLatticeDivs(&lattice, chunk, bitmap.width(), bitmap.height());
lattice.fFlags = nullptr;
int numFlags = 0;
@@ -213,11 +231,13 @@ void SkiaRecordingCanvas::drawNinePatch(Bitmap& hwuiBitmap, const Res_png_9patch
lattice.fBounds = nullptr;
SkRect dst = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
- sk_sp<SkImage> image = hwuiBitmap.makeImage();
SkPaint tmpPaint;
- mRecorder.drawImageLattice(image.get(), lattice, dst, nonAAPaint(paint, &tmpPaint));
- if (!hwuiBitmap.isImmutable() && image.get() && !image->unique() && !dst.isEmpty()) {
+ sk_sp<SkColorFilter> colorFilter;
+ sk_sp<SkImage> image = bitmap.makeImage(&colorFilter);
+ mRecorder.drawImageLattice(image.get(), lattice, dst,
+ bitmapPaint(paint, &tmpPaint, colorFilter));
+ if (!bitmap.isImmutable() && image.get() && !image->unique() && !dst.isEmpty()) {
mDisplayList->mMutableImages.push_back(image.get());
}
}
diff --git a/libs/hwui/pipeline/skia/VectorDrawableAtlas.cpp b/libs/hwui/pipeline/skia/VectorDrawableAtlas.cpp
index 437653a8dfa8..23969908ff4d 100644
--- a/libs/hwui/pipeline/skia/VectorDrawableAtlas.cpp
+++ b/libs/hwui/pipeline/skia/VectorDrawableAtlas.cpp
@@ -21,6 +21,7 @@
#include <cmath>
#include "utils/TraceUtils.h"
#include "renderthread/RenderProxy.h"
+#include "renderthread/RenderThread.h"
namespace android {
namespace uirenderer {
@@ -228,6 +229,15 @@ AtlasEntry VectorDrawableAtlas::getEntry(AtlasKey atlasKey) {
void VectorDrawableAtlas::releaseEntry(AtlasKey atlasKey) {
if (INVALID_ATLAS_KEY != atlasKey) {
+ if (!renderthread::RenderThread::isCurrent()) {
+ {
+ AutoMutex _lock(mReleaseKeyLock);
+ mKeysForRelease.push_back(atlasKey);
+ }
+ // invoke releaseEntry on the renderthread
+ renderthread::RenderProxy::releaseVDAtlasEntries();
+ return;
+ }
CacheEntry* entry = reinterpret_cast<CacheEntry*>(atlasKey);
if (!entry->surface) {
// Store freed atlas rectangles in "mFreeRects" and try to reuse them later, when atlas
@@ -245,6 +255,14 @@ void VectorDrawableAtlas::releaseEntry(AtlasKey atlasKey) {
}
}
+void VectorDrawableAtlas::delayedReleaseEntries() {
+ AutoMutex _lock(mReleaseKeyLock);
+ for (auto key : mKeysForRelease) {
+ releaseEntry(key);
+ }
+ mKeysForRelease.clear();
+}
+
sk_sp<SkSurface> VectorDrawableAtlas::createSurface(int width, int height, GrContext* context) {
#ifndef ANDROID_ENABLE_LINEAR_BLENDING
sk_sp<SkColorSpace> colorSpace = nullptr;
diff --git a/libs/hwui/pipeline/skia/VectorDrawableAtlas.h b/libs/hwui/pipeline/skia/VectorDrawableAtlas.h
index 496c55742748..0683b3915850 100644
--- a/libs/hwui/pipeline/skia/VectorDrawableAtlas.h
+++ b/libs/hwui/pipeline/skia/VectorDrawableAtlas.h
@@ -20,6 +20,7 @@
#include <SkSurface.h>
#include <utils/FatVector.h>
#include <utils/RefBase.h>
+#include <utils/Thread.h>
#include <list>
class GrRectanizer;
@@ -103,12 +104,19 @@ public:
/**
* "releaseEntry" is invoked when a VectorDrawable is deleted. Passing a non-existing "atlasKey"
- * is causing an undefined behaviour.
+ * is causing an undefined behaviour. This is the only function in the class that can be
+ * invoked from any thread. It will marshal internally to render thread if needed.
*/
void releaseEntry(AtlasKey atlasKey);
void setStorageMode(StorageMode mode);
+ /**
+ * "delayedReleaseEntries" is indirectly invoked by "releaseEntry", when "releaseEntry" is
+ * invoked from a non render thread.
+ */
+ void delayedReleaseEntries();
+
private:
struct CacheEntry {
CacheEntry(const SkRect& newVDrect, const SkRect& newRect,
@@ -182,6 +190,17 @@ private:
*/
StorageMode mStorageMode;
+ /**
+ * mKeysForRelease is used by releaseEntry implementation to pass atlas keys from an arbitrary
+ * calling thread to the render thread.
+ */
+ std::vector<AtlasKey> mKeysForRelease;
+
+ /**
+ * A lock used to protect access to mKeysForRelease.
+ */
+ Mutex mReleaseKeyLock;
+
sk_sp<SkSurface> createSurface(int width, int height, GrContext* context);
inline bool fitInAtlas(int width, int height) {
diff --git a/libs/hwui/renderthread/CacheManager.cpp b/libs/hwui/renderthread/CacheManager.cpp
index 55694d046c2f..f6b23e1a0723 100644
--- a/libs/hwui/renderthread/CacheManager.cpp
+++ b/libs/hwui/renderthread/CacheManager.cpp
@@ -44,7 +44,7 @@ namespace renderthread {
CacheManager::CacheManager(const DisplayInfo& display)
: mMaxSurfaceArea(display.w * display.h) {
mVectorDrawableAtlas = new skiapipeline::VectorDrawableAtlas(mMaxSurfaceArea/2,
- skiapipeline::VectorDrawableAtlas::StorageMode::allowSharedSurface);
+ skiapipeline::VectorDrawableAtlas::StorageMode::disallowSharedSurface);
}
void CacheManager::reset(GrContext* context) {
@@ -62,7 +62,8 @@ void CacheManager::reset(GrContext* context) {
void CacheManager::destroy() {
// cleanup any caches here as the GrContext is about to go away...
mGrContext.reset(nullptr);
- mVectorDrawableAtlas = new skiapipeline::VectorDrawableAtlas(mMaxSurfaceArea/2);
+ mVectorDrawableAtlas = new skiapipeline::VectorDrawableAtlas(mMaxSurfaceArea/2,
+ skiapipeline::VectorDrawableAtlas::StorageMode::disallowSharedSurface);
}
void CacheManager::updateContextCacheSizes() {
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index 16d77364942e..87e5bfdc8ca5 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -138,7 +138,7 @@ void EglManager::initialize() {
LOG_ALWAYS_FATAL_IF(!glInterface.get());
GrContextOptions options;
- options.fGpuPathRenderers &= ~GrContextOptions::GpuPathRenderers::kDistanceField;
+ options.fDisableDistanceFieldPaths = true;
mRenderThread.cacheManager().configureContext(&options);
mRenderThread.setGrContext(GrContext::Create(GrBackend::kOpenGL_GrBackend,
(GrBackendContext)glInterface.get(), options));
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 7fe966dde316..690474376bef 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -732,6 +732,18 @@ void RenderProxy::repackVectorDrawableAtlas() {
thread.queue(task);
}
+CREATE_BRIDGE1(releaseVDAtlasEntries, RenderThread* thread) {
+ args->thread->cacheManager().acquireVectorDrawableAtlas()->delayedReleaseEntries();
+ return nullptr;
+}
+
+void RenderProxy::releaseVDAtlasEntries() {
+ RenderThread& thread = RenderThread::getInstance();
+ SETUP_TASK(releaseVDAtlasEntries);
+ args->thread = &thread;
+ thread.queue(task);
+}
+
void* RenderProxy::postAndWait(MethodInvokeRenderTask* task) {
void* retval;
task->setReturnPtr(&retval);
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 06eaebd066ee..9440b15f6062 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -143,6 +143,8 @@ public:
static void repackVectorDrawableAtlas();
+ static void releaseVDAtlasEntries();
+
private:
RenderThread& mRenderThread;
CanvasContext* mContext;
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index 72a428f1c70c..51e937485fab 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -499,6 +499,10 @@ sk_sp<Bitmap> RenderThread::allocateHardwareBitmap(SkBitmap& skBitmap) {
return nullptr;
}
+bool RenderThread::isCurrent() {
+ return gettid() == getInstance().getTid();
+}
+
} /* namespace renderthread */
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index bef47b3e27c5..30884b571b94 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -111,6 +111,14 @@ public:
sk_sp<Bitmap> allocateHardwareBitmap(SkBitmap& skBitmap);
void dumpGraphicsMemory(int fd);
+ /**
+ * isCurrent provides a way to query, if the caller is running on
+ * the render thread.
+ *
+ * @return true only if isCurrent is invoked from the render thread.
+ */
+ static bool isCurrent();
+
protected:
virtual bool threadLoop() override;
diff --git a/libs/hwui/tests/common/scenes/BitmapShaders.cpp b/libs/hwui/tests/common/scenes/BitmapShaders.cpp
index 4797dec8e89e..0f2dc034d125 100644
--- a/libs/hwui/tests/common/scenes/BitmapShaders.cpp
+++ b/libs/hwui/tests/common/scenes/BitmapShaders.cpp
@@ -46,7 +46,8 @@ public:
});
SkPaint paint;
- sk_sp<SkImage> image = hwuiBitmap->makeImage();
+ sk_sp<SkColorFilter> colorFilter;
+ sk_sp<SkImage> image = hwuiBitmap->makeImage(&colorFilter);
sk_sp<SkShader> repeatShader = image->makeShader(
SkShader::TileMode::kRepeat_TileMode,
SkShader::TileMode::kRepeat_TileMode,
diff --git a/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp b/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp
index c246ebaddcad..960b05340063 100644
--- a/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp
+++ b/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp
@@ -75,7 +75,8 @@ public:
void doFrame(int frameNr) override { }
sk_sp<SkShader> createBitmapShader(Bitmap& bitmap) {
- sk_sp<SkImage> image = bitmap.makeImage();
+ sk_sp<SkColorFilter> colorFilter;
+ sk_sp<SkImage> image = bitmap.makeImage(&colorFilter);
return image->makeShader(SkShader::TileMode::kClamp_TileMode,
SkShader::TileMode::kClamp_TileMode);
}
diff --git a/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp b/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp
index f166c5ceb974..3089447cbfc5 100644
--- a/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp
+++ b/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp
@@ -171,7 +171,6 @@ void BM_DisplayListCanvas_basicViewGroupDraw(benchmark::State& benchState) {
while (benchState.KeepRunning()) {
canvas->resetRecording(200, 200);
- canvas->setHighContrastText(false);
canvas->translate(0, 0); // mScrollX, mScrollY
// Clip to padding
diff --git a/libs/hwui/tests/unit/RecordingCanvasTests.cpp b/libs/hwui/tests/unit/RecordingCanvasTests.cpp
index d36bca031a87..c4e419591a4d 100644
--- a/libs/hwui/tests/unit/RecordingCanvasTests.cpp
+++ b/libs/hwui/tests/unit/RecordingCanvasTests.cpp
@@ -822,8 +822,8 @@ OPENGL_PIPELINE_TEST(RecordingCanvas, drawText) {
}
OPENGL_PIPELINE_TEST(RecordingCanvas, drawTextInHighContrast) {
+ Properties::enableHighContrastText = true;
auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
- canvas.setHighContrastText(true);
Paint paint;
paint.setColor(SK_ColorWHITE);
paint.setAntiAlias(true);
@@ -832,6 +832,7 @@ OPENGL_PIPELINE_TEST(RecordingCanvas, drawTextInHighContrast) {
std::unique_ptr<uint16_t[]> dst = TestUtils::asciiToUtf16("HELLO");
canvas.drawText(dst.get(), 0, 5, 5, 25, 25, minikin::kBidi_Force_LTR, paint, NULL);
});
+ Properties::enableHighContrastText = false;
int count = 0;
playbackOps(*dl, [&count](const RecordedOp& op) {
diff --git a/libs/hwui/tests/unit/SkiaCanvasTests.cpp b/libs/hwui/tests/unit/SkiaCanvasTests.cpp
index c048dda4a2e9..d84b83d3f2dc 100644
--- a/libs/hwui/tests/unit/SkiaCanvasTests.cpp
+++ b/libs/hwui/tests/unit/SkiaCanvasTests.cpp
@@ -45,8 +45,7 @@ OPENGL_PIPELINE_TEST(SkiaCanvasProxy, drawGlyphsViaPicture) {
// record the same text draw into a SkPicture and replay it into a Recording canvas
SkPictureRecorder recorder;
SkCanvas* skCanvas = recorder.beginRecording(200, 200, NULL, 0);
- std::unique_ptr<Canvas> pictCanvas(Canvas::create_canvas(skCanvas,
- Canvas::XformToSRGB::kDefer));
+ std::unique_ptr<Canvas> pictCanvas(Canvas::create_canvas(skCanvas));
TestUtils::drawUtf8ToCanvas(pictCanvas.get(), text, paint, 25, 25);
sk_sp<SkPicture> picture = recorder.finishRecordingAsPicture();
@@ -65,7 +64,7 @@ OPENGL_PIPELINE_TEST(SkiaCanvasProxy, drawGlyphsViaPicture) {
TEST(SkiaCanvas, drawShadowLayer) {
auto surface = SkSurface::MakeRasterN32Premul(10, 10);
- SkiaCanvas canvas(surface->getCanvas(), Canvas::XformToSRGB::kDefer);
+ SkiaCanvas canvas(surface->getCanvas());
// clear to white
canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrc);
@@ -108,27 +107,14 @@ TEST(SkiaCanvas, colorSpaceXform) {
// The result should be less than fully red, since we convert to Adobe RGB at draw time.
ASSERT_EQ(0xFF0000DC, *adobeSkBitmap.getAddr32(0, 0));
- // Now try in kDefer mode. This is a little strange given that, in practice, all software
- // canvases are kImmediate.
- SkCanvas skCanvas(skBitmap);
- SkiaCanvas deferCanvas(&skCanvas, Canvas::XformToSRGB::kDefer);
- deferCanvas.drawBitmap(*adobeBitmap, 0, 0, nullptr);
- // The result should be as before, since we deferred the conversion to sRGB.
- ASSERT_EQ(0xFF0000DC, *skBitmap.getAddr32(0, 0));
-
- // Test picture recording. We will kDefer the xform at recording time, but handle it when
- // we playback to the software canvas.
+ // Test picture recording.
SkPictureRecorder recorder;
SkCanvas* skPicCanvas = recorder.beginRecording(1, 1, NULL, 0);
- SkiaCanvas picCanvas(skPicCanvas, Canvas::XformToSRGB::kDefer);
+ SkiaCanvas picCanvas(skPicCanvas);
picCanvas.drawBitmap(*adobeBitmap, 0, 0, nullptr);
sk_sp<SkPicture> picture = recorder.finishRecordingAsPicture();
- // Playback to a deferred canvas. The result should be as before.
- deferCanvas.asSkCanvas()->drawPicture(picture);
- ASSERT_EQ(0xFF0000DC, *skBitmap.getAddr32(0, 0));
-
- // Playback to an immediate canvas. The result should be fully red.
+ // Playback to an software canvas. The result should be fully red.
canvas.asSkCanvas()->drawPicture(picture);
ASSERT_EQ(0xFF0000FF, *skBitmap.getAddr32(0, 0));
}
@@ -155,7 +141,7 @@ TEST(SkiaCanvas, captureCanvasState) {
// Create a picture canvas.
SkPictureRecorder recorder;
SkCanvas* skPicCanvas = recorder.beginRecording(1, 1, NULL, 0);
- SkiaCanvas picCanvas(skPicCanvas, Canvas::XformToSRGB::kDefer);
+ SkiaCanvas picCanvas(skPicCanvas);
state = picCanvas.captureCanvasState();
// Verify that we cannot get the CanvasState.
diff --git a/libs/hwui/tests/unit/TypefaceTests.cpp b/libs/hwui/tests/unit/TypefaceTests.cpp
index c90b6f0e9cdd..345cfd647b11 100644
--- a/libs/hwui/tests/unit/TypefaceTests.cpp
+++ b/libs/hwui/tests/unit/TypefaceTests.cpp
@@ -70,7 +70,8 @@ TEST(TypefaceTest, resolveDefault_and_setDefaultTest) {
RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE));
EXPECT_EQ(regular.get(), Typeface::resolveDefault(regular.get()));
- Typeface* old = Typeface::resolveDefault(nullptr); // Keep the original to restore it later.
+ // Keep the original to restore it later.
+ const Typeface* old = Typeface::resolveDefault(nullptr);
ASSERT_NE(nullptr, old);
Typeface::setDefault(regular.get());
diff --git a/libs/incident/proto/android/privacy.proto b/libs/incident/proto/android/privacy.proto
index ae5af0e4afa7..5fd75d6f2809 100644
--- a/libs/incident/proto/android/privacy.proto
+++ b/libs/incident/proto/android/privacy.proto
@@ -36,7 +36,7 @@ enum Destination {
// off the device with an explicit user action.
DEST_EXPLICIT = 1;
- // Fields or messages annotated with DEST_LOCAL can be sent by
+ // Fields or messages annotated with DEST_AUTOMATIC can be sent by
// automatic means, without per-sending user consent. The user
// still must have previously accepted a consent to share this
// information.
@@ -47,8 +47,11 @@ enum Destination {
message PrivacyFlags {
optional Destination dest = 1 [
- default = DEST_LOCAL
+ default = DEST_EXPLICIT
];
+
+ // regex to filter pii sensitive info from a string field type
+ repeated string patterns = 2;
}
extend google.protobuf.FieldOptions {
diff --git a/libs/incident/proto/android/section.proto b/libs/incident/proto/android/section.proto
new file mode 100644
index 000000000000..d268cf4fc09a
--- /dev/null
+++ b/libs/incident/proto/android/section.proto
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+
+option java_package = "android";
+option java_multiple_files = true;
+
+import "google/protobuf/descriptor.proto";
+
+package android;
+
+// SectionType defines how incidentd gonna get the field's data
+enum SectionType {
+
+ // Default fields, not available in incidentd
+ SECTION_NONE = 0;
+
+ // incidentd reads a file to get the data for annotated field
+ SECTION_FILE = 1;
+
+ // incidentd executes the given command for annotated field
+ SECTION_COMMAND = 2;
+
+ // incidentd calls dumpsys for annotated field
+ SECTION_DUMPSYS = 3;
+}
+
+message SectionFlags {
+ optional SectionType type = 1 [default = SECTION_NONE];
+ optional string args = 2;
+}
+
+extend google.protobuf.FieldOptions {
+ // Flags for automatically section list generation
+ optional SectionFlags section = 155792027;
+}