Canvas.cpp revision bad99183916ba2bac6659efc8a28273e344ba511
1dccca44ffda4836b56a21da95a046c9708ffd49csergeyv/* 2dccca44ffda4836b56a21da95a046c9708ffd49csergeyv * Copyright (C) 2015 The Android Open Source Project 3dccca44ffda4836b56a21da95a046c9708ffd49csergeyv * 4dccca44ffda4836b56a21da95a046c9708ffd49csergeyv * Licensed under the Apache License, Version 2.0 (the "License"); 5dccca44ffda4836b56a21da95a046c9708ffd49csergeyv * you may not use this file except in compliance with the License. 6dccca44ffda4836b56a21da95a046c9708ffd49csergeyv * You may obtain a copy of the License at 7dccca44ffda4836b56a21da95a046c9708ffd49csergeyv * 8dccca44ffda4836b56a21da95a046c9708ffd49csergeyv * http://www.apache.org/licenses/LICENSE-2.0 9dccca44ffda4836b56a21da95a046c9708ffd49csergeyv * 10dccca44ffda4836b56a21da95a046c9708ffd49csergeyv * Unless required by applicable law or agreed to in writing, software 11dccca44ffda4836b56a21da95a046c9708ffd49csergeyv * distributed under the License is distributed on an "AS IS" BASIS, 12dccca44ffda4836b56a21da95a046c9708ffd49csergeyv * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13dccca44ffda4836b56a21da95a046c9708ffd49csergeyv * See the License for the specific language governing permissions and 14dccca44ffda4836b56a21da95a046c9708ffd49csergeyv * limitations under the License. 15dccca44ffda4836b56a21da95a046c9708ffd49csergeyv */ 16dccca44ffda4836b56a21da95a046c9708ffd49csergeyv 17dccca44ffda4836b56a21da95a046c9708ffd49csergeyv#include "Canvas.h" 18dccca44ffda4836b56a21da95a046c9708ffd49csergeyv 19dccca44ffda4836b56a21da95a046c9708ffd49csergeyv#include "DisplayListCanvas.h" 20dccca44ffda4836b56a21da95a046c9708ffd49csergeyv#include "RecordingCanvas.h" 21dccca44ffda4836b56a21da95a046c9708ffd49csergeyv#include "MinikinUtils.h" 22dccca44ffda4836b56a21da95a046c9708ffd49csergeyv#include "Paint.h" 23bad99183916ba2bac6659efc8a28273e344ba511sergeyv#include "Typeface.h" 24dccca44ffda4836b56a21da95a046c9708ffd49csergeyv 25dccca44ffda4836b56a21da95a046c9708ffd49csergeyv#include <SkDrawFilter.h> 26dccca44ffda4836b56a21da95a046c9708ffd49csergeyv 27dccca44ffda4836b56a21da95a046c9708ffd49csergeyvnamespace android { 28dccca44ffda4836b56a21da95a046c9708ffd49csergeyv 29dccca44ffda4836b56a21da95a046c9708ffd49csergeyvCanvas* Canvas::create_recording_canvas(int width, int height) { 30dccca44ffda4836b56a21da95a046c9708ffd49csergeyv#if HWUI_NEW_OPS 31dccca44ffda4836b56a21da95a046c9708ffd49csergeyv return new uirenderer::RecordingCanvas(width, height); 32dccca44ffda4836b56a21da95a046c9708ffd49csergeyv#else 33dccca44ffda4836b56a21da95a046c9708ffd49csergeyv return new uirenderer::DisplayListCanvas(width, height); 34dccca44ffda4836b56a21da95a046c9708ffd49csergeyv#endif 35dccca44ffda4836b56a21da95a046c9708ffd49csergeyv} 36dccca44ffda4836b56a21da95a046c9708ffd49csergeyv 37dccca44ffda4836b56a21da95a046c9708ffd49csergeyvvoid Canvas::drawTextDecorations(float x, float y, float length, const SkPaint& paint) { 38dccca44ffda4836b56a21da95a046c9708ffd49csergeyv uint32_t flags; 39dccca44ffda4836b56a21da95a046c9708ffd49csergeyv SkDrawFilter* drawFilter = getDrawFilter(); 40dccca44ffda4836b56a21da95a046c9708ffd49csergeyv if (drawFilter) { 41dccca44ffda4836b56a21da95a046c9708ffd49csergeyv SkPaint paintCopy(paint); 42dccca44ffda4836b56a21da95a046c9708ffd49csergeyv drawFilter->filter(&paintCopy, SkDrawFilter::kText_Type); 43dccca44ffda4836b56a21da95a046c9708ffd49csergeyv flags = paintCopy.getFlags(); 44dccca44ffda4836b56a21da95a046c9708ffd49csergeyv } else { 45dccca44ffda4836b56a21da95a046c9708ffd49csergeyv flags = paint.getFlags(); 46dccca44ffda4836b56a21da95a046c9708ffd49csergeyv } 47dccca44ffda4836b56a21da95a046c9708ffd49csergeyv if (flags & (SkPaint::kUnderlineText_Flag | SkPaint::kStrikeThruText_Flag)) { 48dccca44ffda4836b56a21da95a046c9708ffd49csergeyv // Same values used by Skia 49dccca44ffda4836b56a21da95a046c9708ffd49csergeyv const float kStdStrikeThru_Offset = (-6.0f / 21.0f); 50dccca44ffda4836b56a21da95a046c9708ffd49csergeyv const float kStdUnderline_Offset = (1.0f / 9.0f); 51dccca44ffda4836b56a21da95a046c9708ffd49csergeyv const float kStdUnderline_Thickness = (1.0f / 18.0f); 52dccca44ffda4836b56a21da95a046c9708ffd49csergeyv 53dccca44ffda4836b56a21da95a046c9708ffd49csergeyv SkScalar left = x; 54dccca44ffda4836b56a21da95a046c9708ffd49csergeyv SkScalar right = x + length; 55dccca44ffda4836b56a21da95a046c9708ffd49csergeyv float textSize = paint.getTextSize(); 56dccca44ffda4836b56a21da95a046c9708ffd49csergeyv float strokeWidth = fmax(textSize * kStdUnderline_Thickness, 1.0f); 57dccca44ffda4836b56a21da95a046c9708ffd49csergeyv if (flags & SkPaint::kUnderlineText_Flag) { 58dccca44ffda4836b56a21da95a046c9708ffd49csergeyv SkScalar top = y + textSize * kStdUnderline_Offset - 0.5f * strokeWidth; 59dccca44ffda4836b56a21da95a046c9708ffd49csergeyv SkScalar bottom = y + textSize * kStdUnderline_Offset + 0.5f * strokeWidth; 60dccca44ffda4836b56a21da95a046c9708ffd49csergeyv drawRect(left, top, right, bottom, paint); 61dccca44ffda4836b56a21da95a046c9708ffd49csergeyv } 62dccca44ffda4836b56a21da95a046c9708ffd49csergeyv if (flags & SkPaint::kStrikeThruText_Flag) { 63dccca44ffda4836b56a21da95a046c9708ffd49csergeyv SkScalar top = y + textSize * kStdStrikeThru_Offset - 0.5f * strokeWidth; 64dccca44ffda4836b56a21da95a046c9708ffd49csergeyv SkScalar bottom = y + textSize * kStdStrikeThru_Offset + 0.5f * strokeWidth; 65dccca44ffda4836b56a21da95a046c9708ffd49csergeyv drawRect(left, top, right, bottom, paint); 66dccca44ffda4836b56a21da95a046c9708ffd49csergeyv } 67dccca44ffda4836b56a21da95a046c9708ffd49csergeyv } 68dccca44ffda4836b56a21da95a046c9708ffd49csergeyv} 69dccca44ffda4836b56a21da95a046c9708ffd49csergeyv 70dccca44ffda4836b56a21da95a046c9708ffd49csergeyvstatic void simplifyPaint(int color, SkPaint* paint) { 71dccca44ffda4836b56a21da95a046c9708ffd49csergeyv paint->setColor(color); 72dccca44ffda4836b56a21da95a046c9708ffd49csergeyv paint->setShader(nullptr); 73dccca44ffda4836b56a21da95a046c9708ffd49csergeyv paint->setColorFilter(nullptr); 74dccca44ffda4836b56a21da95a046c9708ffd49csergeyv paint->setLooper(nullptr); 75dccca44ffda4836b56a21da95a046c9708ffd49csergeyv paint->setStrokeWidth(4 + 0.04 * paint->getTextSize()); 76dccca44ffda4836b56a21da95a046c9708ffd49csergeyv paint->setStrokeJoin(SkPaint::kRound_Join); 77dccca44ffda4836b56a21da95a046c9708ffd49csergeyv paint->setLooper(nullptr); 78dccca44ffda4836b56a21da95a046c9708ffd49csergeyv} 79dccca44ffda4836b56a21da95a046c9708ffd49csergeyv 80dccca44ffda4836b56a21da95a046c9708ffd49csergeyvclass DrawTextFunctor { 81dccca44ffda4836b56a21da95a046c9708ffd49csergeyvpublic: 82dccca44ffda4836b56a21da95a046c9708ffd49csergeyv DrawTextFunctor(const Layout& layout, Canvas* canvas, uint16_t* glyphs, float* pos, 83dccca44ffda4836b56a21da95a046c9708ffd49csergeyv const SkPaint& paint, float x, float y, MinikinRect& bounds, float totalAdvance) 84dccca44ffda4836b56a21da95a046c9708ffd49csergeyv : layout(layout) 85dccca44ffda4836b56a21da95a046c9708ffd49csergeyv , canvas(canvas) 86dccca44ffda4836b56a21da95a046c9708ffd49csergeyv , glyphs(glyphs) 87dccca44ffda4836b56a21da95a046c9708ffd49csergeyv , pos(pos) 88dccca44ffda4836b56a21da95a046c9708ffd49csergeyv , paint(paint) 89dccca44ffda4836b56a21da95a046c9708ffd49csergeyv , x(x) 90dccca44ffda4836b56a21da95a046c9708ffd49csergeyv , y(y) 91dccca44ffda4836b56a21da95a046c9708ffd49csergeyv , bounds(bounds) 92dccca44ffda4836b56a21da95a046c9708ffd49csergeyv , totalAdvance(totalAdvance) { 93dccca44ffda4836b56a21da95a046c9708ffd49csergeyv } 94dccca44ffda4836b56a21da95a046c9708ffd49csergeyv 95dccca44ffda4836b56a21da95a046c9708ffd49csergeyv void operator()(size_t start, size_t end) { 96dccca44ffda4836b56a21da95a046c9708ffd49csergeyv if (canvas->drawTextAbsolutePos()) { 97dccca44ffda4836b56a21da95a046c9708ffd49csergeyv for (size_t i = start; i < end; i++) { 98dccca44ffda4836b56a21da95a046c9708ffd49csergeyv glyphs[i] = layout.getGlyphId(i); 99dccca44ffda4836b56a21da95a046c9708ffd49csergeyv pos[2 * i] = x + layout.getX(i); 100dccca44ffda4836b56a21da95a046c9708ffd49csergeyv pos[2 * i + 1] = y + layout.getY(i); 101dccca44ffda4836b56a21da95a046c9708ffd49csergeyv } 102dccca44ffda4836b56a21da95a046c9708ffd49csergeyv } else { 103dccca44ffda4836b56a21da95a046c9708ffd49csergeyv for (size_t i = start; i < end; i++) { 104dccca44ffda4836b56a21da95a046c9708ffd49csergeyv glyphs[i] = layout.getGlyphId(i); 105dccca44ffda4836b56a21da95a046c9708ffd49csergeyv pos[2 * i] = layout.getX(i); 106dccca44ffda4836b56a21da95a046c9708ffd49csergeyv pos[2 * i + 1] = layout.getY(i); 107dccca44ffda4836b56a21da95a046c9708ffd49csergeyv } 108dccca44ffda4836b56a21da95a046c9708ffd49csergeyv } 109dccca44ffda4836b56a21da95a046c9708ffd49csergeyv 110dccca44ffda4836b56a21da95a046c9708ffd49csergeyv size_t glyphCount = end - start; 111dccca44ffda4836b56a21da95a046c9708ffd49csergeyv 112dccca44ffda4836b56a21da95a046c9708ffd49csergeyv if (CC_UNLIKELY(canvas->isHighContrastText() && paint.getAlpha() != 0)) { 113dccca44ffda4836b56a21da95a046c9708ffd49csergeyv // high contrast draw path 114dccca44ffda4836b56a21da95a046c9708ffd49csergeyv int color = paint.getColor(); 115dccca44ffda4836b56a21da95a046c9708ffd49csergeyv int channelSum = SkColorGetR(color) + SkColorGetG(color) + SkColorGetB(color); 116dccca44ffda4836b56a21da95a046c9708ffd49csergeyv bool darken = channelSum < (128 * 3); 117dccca44ffda4836b56a21da95a046c9708ffd49csergeyv 118dccca44ffda4836b56a21da95a046c9708ffd49csergeyv // outline 119dccca44ffda4836b56a21da95a046c9708ffd49csergeyv SkPaint outlinePaint(paint); 120dccca44ffda4836b56a21da95a046c9708ffd49csergeyv simplifyPaint(darken ? SK_ColorWHITE : SK_ColorBLACK, &outlinePaint); 121dccca44ffda4836b56a21da95a046c9708ffd49csergeyv outlinePaint.setStyle(SkPaint::kStrokeAndFill_Style); 122dccca44ffda4836b56a21da95a046c9708ffd49csergeyv canvas->drawGlyphs(glyphs + start, pos + (2 * start), glyphCount, outlinePaint, x, y, 123dccca44ffda4836b56a21da95a046c9708ffd49csergeyv bounds.mLeft, bounds.mTop, bounds.mRight, bounds.mBottom, totalAdvance); 124dccca44ffda4836b56a21da95a046c9708ffd49csergeyv 125dccca44ffda4836b56a21da95a046c9708ffd49csergeyv // inner 126dccca44ffda4836b56a21da95a046c9708ffd49csergeyv SkPaint innerPaint(paint); 127dccca44ffda4836b56a21da95a046c9708ffd49csergeyv simplifyPaint(darken ? SK_ColorBLACK : SK_ColorWHITE, &innerPaint); 128dccca44ffda4836b56a21da95a046c9708ffd49csergeyv innerPaint.setStyle(SkPaint::kFill_Style); 129dccca44ffda4836b56a21da95a046c9708ffd49csergeyv canvas->drawGlyphs(glyphs + start, pos + (2 * start), glyphCount, innerPaint, x, y, 130dccca44ffda4836b56a21da95a046c9708ffd49csergeyv bounds.mLeft, bounds.mTop, bounds.mRight, bounds.mBottom, totalAdvance); 131dccca44ffda4836b56a21da95a046c9708ffd49csergeyv } else { 132dccca44ffda4836b56a21da95a046c9708ffd49csergeyv // standard draw path 133dccca44ffda4836b56a21da95a046c9708ffd49csergeyv canvas->drawGlyphs(glyphs + start, pos + (2 * start), glyphCount, paint, x, y, 134dccca44ffda4836b56a21da95a046c9708ffd49csergeyv bounds.mLeft, bounds.mTop, bounds.mRight, bounds.mBottom, totalAdvance); 135dccca44ffda4836b56a21da95a046c9708ffd49csergeyv } 136dccca44ffda4836b56a21da95a046c9708ffd49csergeyv } 137dccca44ffda4836b56a21da95a046c9708ffd49csergeyvprivate: 138dccca44ffda4836b56a21da95a046c9708ffd49csergeyv const Layout& layout; 139dccca44ffda4836b56a21da95a046c9708ffd49csergeyv Canvas* canvas; 140dccca44ffda4836b56a21da95a046c9708ffd49csergeyv uint16_t* glyphs; 141dccca44ffda4836b56a21da95a046c9708ffd49csergeyv float* pos; 142dccca44ffda4836b56a21da95a046c9708ffd49csergeyv const SkPaint& paint; 143dccca44ffda4836b56a21da95a046c9708ffd49csergeyv float x; 144dccca44ffda4836b56a21da95a046c9708ffd49csergeyv float y; 145dccca44ffda4836b56a21da95a046c9708ffd49csergeyv MinikinRect& bounds; 146dccca44ffda4836b56a21da95a046c9708ffd49csergeyv float totalAdvance; 147dccca44ffda4836b56a21da95a046c9708ffd49csergeyv}; 148dccca44ffda4836b56a21da95a046c9708ffd49csergeyv 149dccca44ffda4836b56a21da95a046c9708ffd49csergeyvvoid Canvas::drawText(const uint16_t* text, int start, int count, int contextCount, 150bad99183916ba2bac6659efc8a28273e344ba511sergeyv float x, float y, int bidiFlags, const Paint& origPaint, Typeface* typeface) { 151dccca44ffda4836b56a21da95a046c9708ffd49csergeyv // minikin may modify the original paint 152dccca44ffda4836b56a21da95a046c9708ffd49csergeyv Paint paint(origPaint); 153dccca44ffda4836b56a21da95a046c9708ffd49csergeyv 154dccca44ffda4836b56a21da95a046c9708ffd49csergeyv Layout layout; 155dccca44ffda4836b56a21da95a046c9708ffd49csergeyv MinikinUtils::doLayout(&layout, &paint, bidiFlags, typeface, text, start, count, contextCount); 156dccca44ffda4836b56a21da95a046c9708ffd49csergeyv 157dccca44ffda4836b56a21da95a046c9708ffd49csergeyv size_t nGlyphs = layout.nGlyphs(); 158dccca44ffda4836b56a21da95a046c9708ffd49csergeyv std::unique_ptr<uint16_t[]> glyphs(new uint16_t[nGlyphs]); 159dccca44ffda4836b56a21da95a046c9708ffd49csergeyv std::unique_ptr<float[]> pos(new float[nGlyphs * 2]); 160dccca44ffda4836b56a21da95a046c9708ffd49csergeyv 161dccca44ffda4836b56a21da95a046c9708ffd49csergeyv x += MinikinUtils::xOffsetForTextAlign(&paint, layout); 162dccca44ffda4836b56a21da95a046c9708ffd49csergeyv 163dccca44ffda4836b56a21da95a046c9708ffd49csergeyv MinikinRect bounds; 164dccca44ffda4836b56a21da95a046c9708ffd49csergeyv layout.getBounds(&bounds); 165dccca44ffda4836b56a21da95a046c9708ffd49csergeyv if (!drawTextAbsolutePos()) { 166dccca44ffda4836b56a21da95a046c9708ffd49csergeyv bounds.offset(x, y); 167dccca44ffda4836b56a21da95a046c9708ffd49csergeyv } 168dccca44ffda4836b56a21da95a046c9708ffd49csergeyv 169dccca44ffda4836b56a21da95a046c9708ffd49csergeyv DrawTextFunctor f(layout, this, glyphs.get(), pos.get(), 170dccca44ffda4836b56a21da95a046c9708ffd49csergeyv paint, x, y, bounds, layout.getAdvance()); 171dccca44ffda4836b56a21da95a046c9708ffd49csergeyv MinikinUtils::forFontRun(layout, &paint, f); 172dccca44ffda4836b56a21da95a046c9708ffd49csergeyv} 173dccca44ffda4836b56a21da95a046c9708ffd49csergeyv 174dccca44ffda4836b56a21da95a046c9708ffd49csergeyvclass DrawTextOnPathFunctor { 175dccca44ffda4836b56a21da95a046c9708ffd49csergeyvpublic: 176dccca44ffda4836b56a21da95a046c9708ffd49csergeyv DrawTextOnPathFunctor(const Layout& layout, Canvas* canvas, float hOffset, 177dccca44ffda4836b56a21da95a046c9708ffd49csergeyv float vOffset, const Paint& paint, const SkPath& path) 178dccca44ffda4836b56a21da95a046c9708ffd49csergeyv : layout(layout) 179dccca44ffda4836b56a21da95a046c9708ffd49csergeyv , canvas(canvas) 180dccca44ffda4836b56a21da95a046c9708ffd49csergeyv , hOffset(hOffset) 181dccca44ffda4836b56a21da95a046c9708ffd49csergeyv , vOffset(vOffset) 182dccca44ffda4836b56a21da95a046c9708ffd49csergeyv , paint(paint) 183dccca44ffda4836b56a21da95a046c9708ffd49csergeyv , path(path) { 184dccca44ffda4836b56a21da95a046c9708ffd49csergeyv } 185dccca44ffda4836b56a21da95a046c9708ffd49csergeyv 186dccca44ffda4836b56a21da95a046c9708ffd49csergeyv void operator()(size_t start, size_t end) { 187dccca44ffda4836b56a21da95a046c9708ffd49csergeyv uint16_t glyphs[1]; 188dccca44ffda4836b56a21da95a046c9708ffd49csergeyv for (size_t i = start; i < end; i++) { 189dccca44ffda4836b56a21da95a046c9708ffd49csergeyv glyphs[0] = layout.getGlyphId(i); 190dccca44ffda4836b56a21da95a046c9708ffd49csergeyv float x = hOffset + layout.getX(i); 191dccca44ffda4836b56a21da95a046c9708ffd49csergeyv float y = vOffset + layout.getY(i); 192dccca44ffda4836b56a21da95a046c9708ffd49csergeyv canvas->drawGlyphsOnPath(glyphs, 1, path, x, y, paint); 193dccca44ffda4836b56a21da95a046c9708ffd49csergeyv } 194dccca44ffda4836b56a21da95a046c9708ffd49csergeyv } 195dccca44ffda4836b56a21da95a046c9708ffd49csergeyvprivate: 196dccca44ffda4836b56a21da95a046c9708ffd49csergeyv const Layout& layout; 197dccca44ffda4836b56a21da95a046c9708ffd49csergeyv Canvas* canvas; 198dccca44ffda4836b56a21da95a046c9708ffd49csergeyv float hOffset; 199dccca44ffda4836b56a21da95a046c9708ffd49csergeyv float vOffset; 200dccca44ffda4836b56a21da95a046c9708ffd49csergeyv const Paint& paint; 201dccca44ffda4836b56a21da95a046c9708ffd49csergeyv const SkPath& path; 202dccca44ffda4836b56a21da95a046c9708ffd49csergeyv}; 203dccca44ffda4836b56a21da95a046c9708ffd49csergeyv 204dccca44ffda4836b56a21da95a046c9708ffd49csergeyvvoid Canvas::drawTextOnPath(const uint16_t* text, int count, int bidiFlags, const SkPath& path, 205bad99183916ba2bac6659efc8a28273e344ba511sergeyv float hOffset, float vOffset, const Paint& paint, Typeface* typeface) { 206dccca44ffda4836b56a21da95a046c9708ffd49csergeyv Paint paintCopy(paint); 207dccca44ffda4836b56a21da95a046c9708ffd49csergeyv Layout layout; 208dccca44ffda4836b56a21da95a046c9708ffd49csergeyv MinikinUtils::doLayout(&layout, &paintCopy, bidiFlags, typeface, text, 0, count, count); 209dccca44ffda4836b56a21da95a046c9708ffd49csergeyv hOffset += MinikinUtils::hOffsetForTextAlign(&paintCopy, layout, path); 210dccca44ffda4836b56a21da95a046c9708ffd49csergeyv 211dccca44ffda4836b56a21da95a046c9708ffd49csergeyv // Set align to left for drawing, as we don't want individual 212dccca44ffda4836b56a21da95a046c9708ffd49csergeyv // glyphs centered or right-aligned; the offset above takes 213dccca44ffda4836b56a21da95a046c9708ffd49csergeyv // care of all alignment. 214dccca44ffda4836b56a21da95a046c9708ffd49csergeyv paintCopy.setTextAlign(Paint::kLeft_Align); 215dccca44ffda4836b56a21da95a046c9708ffd49csergeyv 216dccca44ffda4836b56a21da95a046c9708ffd49csergeyv DrawTextOnPathFunctor f(layout, this, hOffset, vOffset, paintCopy, path); 217dccca44ffda4836b56a21da95a046c9708ffd49csergeyv MinikinUtils::forFontRun(layout, &paintCopy, f); 218dccca44ffda4836b56a21da95a046c9708ffd49csergeyv} 219dccca44ffda4836b56a21da95a046c9708ffd49csergeyv 220dccca44ffda4836b56a21da95a046c9708ffd49csergeyv} // namespace android 221