1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2018 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "src/core/SkGlyph.h" 9cb93a386Sopenharmony_ci 10cb93a386Sopenharmony_ci#include "src/core/SkArenaAlloc.h" 11cb93a386Sopenharmony_ci#include "src/core/SkScalerContext.h" 12cb93a386Sopenharmony_ci#include "src/pathops/SkPathOpsCubic.h" 13cb93a386Sopenharmony_ci#include "src/pathops/SkPathOpsQuad.h" 14cb93a386Sopenharmony_ci 15cb93a386Sopenharmony_ciSkMask SkGlyph::mask() const { 16cb93a386Sopenharmony_ci SkMask mask; 17cb93a386Sopenharmony_ci mask.fImage = (uint8_t*)fImage; 18cb93a386Sopenharmony_ci mask.fBounds.setXYWH(fLeft, fTop, fWidth, fHeight); 19cb93a386Sopenharmony_ci mask.fRowBytes = this->rowBytes(); 20cb93a386Sopenharmony_ci mask.fFormat = fMaskFormat; 21cb93a386Sopenharmony_ci return mask; 22cb93a386Sopenharmony_ci} 23cb93a386Sopenharmony_ci 24cb93a386Sopenharmony_ciSkMask SkGlyph::mask(SkPoint position) const { 25cb93a386Sopenharmony_ci SkMask answer = this->mask(); 26cb93a386Sopenharmony_ci answer.fBounds.offset(SkScalarFloorToInt(position.x()), SkScalarFloorToInt(position.y())); 27cb93a386Sopenharmony_ci return answer; 28cb93a386Sopenharmony_ci} 29cb93a386Sopenharmony_ci 30cb93a386Sopenharmony_civoid SkGlyph::zeroMetrics() { 31cb93a386Sopenharmony_ci fAdvanceX = 0; 32cb93a386Sopenharmony_ci fAdvanceY = 0; 33cb93a386Sopenharmony_ci fWidth = 0; 34cb93a386Sopenharmony_ci fHeight = 0; 35cb93a386Sopenharmony_ci fTop = 0; 36cb93a386Sopenharmony_ci fLeft = 0; 37cb93a386Sopenharmony_ci} 38cb93a386Sopenharmony_ci 39cb93a386Sopenharmony_cistatic size_t bits_to_bytes(size_t bits) { 40cb93a386Sopenharmony_ci return (bits + 7) >> 3; 41cb93a386Sopenharmony_ci} 42cb93a386Sopenharmony_ci 43cb93a386Sopenharmony_cistatic size_t format_alignment(SkMask::Format format) { 44cb93a386Sopenharmony_ci switch (format) { 45cb93a386Sopenharmony_ci case SkMask::kBW_Format: 46cb93a386Sopenharmony_ci case SkMask::kA8_Format: 47cb93a386Sopenharmony_ci case SkMask::k3D_Format: 48cb93a386Sopenharmony_ci case SkMask::kSDF_Format: 49cb93a386Sopenharmony_ci return alignof(uint8_t); 50cb93a386Sopenharmony_ci case SkMask::kARGB32_Format: 51cb93a386Sopenharmony_ci return alignof(uint32_t); 52cb93a386Sopenharmony_ci case SkMask::kLCD16_Format: 53cb93a386Sopenharmony_ci return alignof(uint16_t); 54cb93a386Sopenharmony_ci default: 55cb93a386Sopenharmony_ci SK_ABORT("Unknown mask format."); 56cb93a386Sopenharmony_ci break; 57cb93a386Sopenharmony_ci } 58cb93a386Sopenharmony_ci return 0; 59cb93a386Sopenharmony_ci} 60cb93a386Sopenharmony_ci 61cb93a386Sopenharmony_cistatic size_t format_rowbytes(int width, SkMask::Format format) { 62cb93a386Sopenharmony_ci return format == SkMask::kBW_Format ? bits_to_bytes(width) 63cb93a386Sopenharmony_ci : width * format_alignment(format); 64cb93a386Sopenharmony_ci} 65cb93a386Sopenharmony_ci 66cb93a386Sopenharmony_cisize_t SkGlyph::formatAlignment() const { 67cb93a386Sopenharmony_ci return format_alignment(this->maskFormat()); 68cb93a386Sopenharmony_ci} 69cb93a386Sopenharmony_ci 70cb93a386Sopenharmony_cisize_t SkGlyph::allocImage(SkArenaAlloc* alloc) { 71cb93a386Sopenharmony_ci SkASSERT(!this->isEmpty()); 72cb93a386Sopenharmony_ci auto size = this->imageSize(); 73cb93a386Sopenharmony_ci fImage = alloc->makeBytesAlignedTo(size, this->formatAlignment()); 74cb93a386Sopenharmony_ci 75cb93a386Sopenharmony_ci return size; 76cb93a386Sopenharmony_ci} 77cb93a386Sopenharmony_ci 78cb93a386Sopenharmony_cibool SkGlyph::setImage(SkArenaAlloc* alloc, SkScalerContext* scalerContext) { 79cb93a386Sopenharmony_ci if (!this->setImageHasBeenCalled()) { 80cb93a386Sopenharmony_ci // It used to be that getImage() could change the fMaskFormat. Extra checking to make 81cb93a386Sopenharmony_ci // sure there are no regressions. 82cb93a386Sopenharmony_ci SkDEBUGCODE(SkMask::Format oldFormat = this->maskFormat()); 83cb93a386Sopenharmony_ci this->allocImage(alloc); 84cb93a386Sopenharmony_ci scalerContext->getImage(*this); 85cb93a386Sopenharmony_ci SkASSERT(oldFormat == this->maskFormat()); 86cb93a386Sopenharmony_ci return true; 87cb93a386Sopenharmony_ci } 88cb93a386Sopenharmony_ci return false; 89cb93a386Sopenharmony_ci} 90cb93a386Sopenharmony_ci 91cb93a386Sopenharmony_cibool SkGlyph::setImage(SkArenaAlloc* alloc, const void* image) { 92cb93a386Sopenharmony_ci if (!this->setImageHasBeenCalled()) { 93cb93a386Sopenharmony_ci this->allocImage(alloc); 94cb93a386Sopenharmony_ci memcpy(fImage, image, this->imageSize()); 95cb93a386Sopenharmony_ci return true; 96cb93a386Sopenharmony_ci } 97cb93a386Sopenharmony_ci return false; 98cb93a386Sopenharmony_ci} 99cb93a386Sopenharmony_ci 100cb93a386Sopenharmony_cisize_t SkGlyph::setMetricsAndImage(SkArenaAlloc* alloc, const SkGlyph& from) { 101cb93a386Sopenharmony_ci // Since the code no longer tries to find replacement glyphs, the image should always be 102cb93a386Sopenharmony_ci // nullptr. 103cb93a386Sopenharmony_ci SkASSERT(fImage == nullptr); 104cb93a386Sopenharmony_ci 105cb93a386Sopenharmony_ci // TODO(herb): remove "if" when we are sure there are no colliding glyphs. 106cb93a386Sopenharmony_ci if (fImage == nullptr) { 107cb93a386Sopenharmony_ci fAdvanceX = from.fAdvanceX; 108cb93a386Sopenharmony_ci fAdvanceY = from.fAdvanceY; 109cb93a386Sopenharmony_ci fWidth = from.fWidth; 110cb93a386Sopenharmony_ci fHeight = from.fHeight; 111cb93a386Sopenharmony_ci fTop = from.fTop; 112cb93a386Sopenharmony_ci fLeft = from.fLeft; 113cb93a386Sopenharmony_ci fForceBW = from.fForceBW; 114cb93a386Sopenharmony_ci fMaskFormat = from.fMaskFormat; 115cb93a386Sopenharmony_ci 116cb93a386Sopenharmony_ci // From glyph may not have an image because the glyph is too large. 117cb93a386Sopenharmony_ci if (from.fImage != nullptr && this->setImage(alloc, from.image())) { 118cb93a386Sopenharmony_ci return this->imageSize(); 119cb93a386Sopenharmony_ci } 120cb93a386Sopenharmony_ci } 121cb93a386Sopenharmony_ci return 0; 122cb93a386Sopenharmony_ci} 123cb93a386Sopenharmony_ci 124cb93a386Sopenharmony_cisize_t SkGlyph::rowBytes() const { 125cb93a386Sopenharmony_ci return format_rowbytes(fWidth, fMaskFormat); 126cb93a386Sopenharmony_ci} 127cb93a386Sopenharmony_ci 128cb93a386Sopenharmony_cisize_t SkGlyph::rowBytesUsingFormat(SkMask::Format format) const { 129cb93a386Sopenharmony_ci return format_rowbytes(fWidth, format); 130cb93a386Sopenharmony_ci} 131cb93a386Sopenharmony_ci 132cb93a386Sopenharmony_cisize_t SkGlyph::imageSize() const { 133cb93a386Sopenharmony_ci if (this->isEmpty() || this->imageTooLarge()) { return 0; } 134cb93a386Sopenharmony_ci 135cb93a386Sopenharmony_ci size_t size = this->rowBytes() * fHeight; 136cb93a386Sopenharmony_ci 137cb93a386Sopenharmony_ci if (fMaskFormat == SkMask::k3D_Format) { 138cb93a386Sopenharmony_ci size *= 3; 139cb93a386Sopenharmony_ci } 140cb93a386Sopenharmony_ci 141cb93a386Sopenharmony_ci return size; 142cb93a386Sopenharmony_ci} 143cb93a386Sopenharmony_ci 144cb93a386Sopenharmony_civoid SkGlyph::installPath(SkArenaAlloc* alloc, const SkPath* path) { 145cb93a386Sopenharmony_ci SkASSERT(fPathData == nullptr); 146cb93a386Sopenharmony_ci SkASSERT(!this->setPathHasBeenCalled()); 147cb93a386Sopenharmony_ci fPathData = alloc->make<SkGlyph::PathData>(); 148cb93a386Sopenharmony_ci if (path != nullptr) { 149cb93a386Sopenharmony_ci fPathData->fPath = *path; 150cb93a386Sopenharmony_ci fPathData->fPath.updateBoundsCache(); 151cb93a386Sopenharmony_ci fPathData->fPath.getGenerationID(); 152cb93a386Sopenharmony_ci fPathData->fHasPath = true; 153cb93a386Sopenharmony_ci } 154cb93a386Sopenharmony_ci} 155cb93a386Sopenharmony_ci 156cb93a386Sopenharmony_cibool SkGlyph::setPath(SkArenaAlloc* alloc, SkScalerContext* scalerContext) { 157cb93a386Sopenharmony_ci if (!this->setPathHasBeenCalled()) { 158cb93a386Sopenharmony_ci SkPath path; 159cb93a386Sopenharmony_ci if (scalerContext->getPath(this->getPackedID(), &path)) { 160cb93a386Sopenharmony_ci this->installPath(alloc, &path); 161cb93a386Sopenharmony_ci } else { 162cb93a386Sopenharmony_ci this->installPath(alloc, nullptr); 163cb93a386Sopenharmony_ci } 164cb93a386Sopenharmony_ci return this->path() != nullptr; 165cb93a386Sopenharmony_ci } 166cb93a386Sopenharmony_ci 167cb93a386Sopenharmony_ci return false; 168cb93a386Sopenharmony_ci} 169cb93a386Sopenharmony_ci 170cb93a386Sopenharmony_cibool SkGlyph::setPath(SkArenaAlloc* alloc, const SkPath* path) { 171cb93a386Sopenharmony_ci if (!this->setPathHasBeenCalled()) { 172cb93a386Sopenharmony_ci this->installPath(alloc, path); 173cb93a386Sopenharmony_ci return this->path() != nullptr; 174cb93a386Sopenharmony_ci } 175cb93a386Sopenharmony_ci return false; 176cb93a386Sopenharmony_ci} 177cb93a386Sopenharmony_ci 178cb93a386Sopenharmony_ciconst SkPath* SkGlyph::path() const { 179cb93a386Sopenharmony_ci // setPath must have been called previously. 180cb93a386Sopenharmony_ci SkASSERT(this->setPathHasBeenCalled()); 181cb93a386Sopenharmony_ci if (fPathData->fHasPath) { 182cb93a386Sopenharmony_ci return &fPathData->fPath; 183cb93a386Sopenharmony_ci } 184cb93a386Sopenharmony_ci return nullptr; 185cb93a386Sopenharmony_ci} 186cb93a386Sopenharmony_ci 187cb93a386Sopenharmony_cistatic std::tuple<SkScalar, SkScalar> calculate_path_gap( 188cb93a386Sopenharmony_ci SkScalar topOffset, SkScalar bottomOffset, const SkPath& path) { 189cb93a386Sopenharmony_ci 190cb93a386Sopenharmony_ci // Left and Right of an ever expanding gap around the path. 191cb93a386Sopenharmony_ci SkScalar left = SK_ScalarMax, 192cb93a386Sopenharmony_ci right = SK_ScalarMin; 193cb93a386Sopenharmony_ci auto expandGap = [&left, &right](SkScalar v) { 194cb93a386Sopenharmony_ci left = std::min(left, v); 195cb93a386Sopenharmony_ci right = std::max(right, v); 196cb93a386Sopenharmony_ci }; 197cb93a386Sopenharmony_ci 198cb93a386Sopenharmony_ci // Handle all the different verbs for the path. 199cb93a386Sopenharmony_ci SkPoint pts[4]; 200cb93a386Sopenharmony_ci auto addLine = [&expandGap, &pts](SkScalar offset) { 201cb93a386Sopenharmony_ci SkScalar t = sk_ieee_float_divide(offset - pts[0].fY, pts[1].fY - pts[0].fY); 202cb93a386Sopenharmony_ci if (0 <= t && t < 1) { // this handles divide by zero above 203cb93a386Sopenharmony_ci expandGap(pts[0].fX + t * (pts[1].fX - pts[0].fX)); 204cb93a386Sopenharmony_ci } 205cb93a386Sopenharmony_ci }; 206cb93a386Sopenharmony_ci 207cb93a386Sopenharmony_ci auto addQuad = [&expandGap, &pts](SkScalar offset) { 208cb93a386Sopenharmony_ci SkDQuad quad; 209cb93a386Sopenharmony_ci quad.set(pts); 210cb93a386Sopenharmony_ci double roots[2]; 211cb93a386Sopenharmony_ci int count = quad.horizontalIntersect(offset, roots); 212cb93a386Sopenharmony_ci while (--count >= 0) { 213cb93a386Sopenharmony_ci expandGap(quad.ptAtT(roots[count]).asSkPoint().fX); 214cb93a386Sopenharmony_ci } 215cb93a386Sopenharmony_ci }; 216cb93a386Sopenharmony_ci 217cb93a386Sopenharmony_ci auto addCubic = [&expandGap, &pts](SkScalar offset) { 218cb93a386Sopenharmony_ci SkDCubic cubic; 219cb93a386Sopenharmony_ci cubic.set(pts); 220cb93a386Sopenharmony_ci double roots[3]; 221cb93a386Sopenharmony_ci int count = cubic.horizontalIntersect(offset, roots); 222cb93a386Sopenharmony_ci while (--count >= 0) { 223cb93a386Sopenharmony_ci expandGap(cubic.ptAtT(roots[count]).asSkPoint().fX); 224cb93a386Sopenharmony_ci } 225cb93a386Sopenharmony_ci }; 226cb93a386Sopenharmony_ci 227cb93a386Sopenharmony_ci // Handle when a verb's points are in the gap between top and bottom. 228cb93a386Sopenharmony_ci auto addPts = [&expandGap, &pts, topOffset, bottomOffset](int ptCount) { 229cb93a386Sopenharmony_ci for (int i = 0; i < ptCount; ++i) { 230cb93a386Sopenharmony_ci if (topOffset < pts[i].fY && pts[i].fY < bottomOffset) { 231cb93a386Sopenharmony_ci expandGap(pts[i].fX); 232cb93a386Sopenharmony_ci } 233cb93a386Sopenharmony_ci } 234cb93a386Sopenharmony_ci }; 235cb93a386Sopenharmony_ci 236cb93a386Sopenharmony_ci SkPath::Iter iter(path, false); 237cb93a386Sopenharmony_ci SkPath::Verb verb; 238cb93a386Sopenharmony_ci while (SkPath::kDone_Verb != (verb = iter.next(pts))) { 239cb93a386Sopenharmony_ci switch (verb) { 240cb93a386Sopenharmony_ci case SkPath::kMove_Verb: { 241cb93a386Sopenharmony_ci break; 242cb93a386Sopenharmony_ci } 243cb93a386Sopenharmony_ci case SkPath::kLine_Verb: { 244cb93a386Sopenharmony_ci addLine(topOffset); 245cb93a386Sopenharmony_ci addLine(bottomOffset); 246cb93a386Sopenharmony_ci addPts(2); 247cb93a386Sopenharmony_ci break; 248cb93a386Sopenharmony_ci } 249cb93a386Sopenharmony_ci case SkPath::kQuad_Verb: { 250cb93a386Sopenharmony_ci SkScalar quadTop = std::min(std::min(pts[0].fY, pts[1].fY), pts[2].fY); 251cb93a386Sopenharmony_ci if (bottomOffset < quadTop) { break; } 252cb93a386Sopenharmony_ci SkScalar quadBottom = std::max(std::max(pts[0].fY, pts[1].fY), pts[2].fY); 253cb93a386Sopenharmony_ci if (topOffset > quadBottom) { break; } 254cb93a386Sopenharmony_ci addQuad(topOffset); 255cb93a386Sopenharmony_ci addQuad(bottomOffset); 256cb93a386Sopenharmony_ci addPts(3); 257cb93a386Sopenharmony_ci break; 258cb93a386Sopenharmony_ci } 259cb93a386Sopenharmony_ci case SkPath::kConic_Verb: { 260cb93a386Sopenharmony_ci SkASSERT(0); // no support for text composed of conics 261cb93a386Sopenharmony_ci break; 262cb93a386Sopenharmony_ci } 263cb93a386Sopenharmony_ci case SkPath::kCubic_Verb: { 264cb93a386Sopenharmony_ci SkScalar quadTop = 265cb93a386Sopenharmony_ci std::min(std::min(std::min(pts[0].fY, pts[1].fY), pts[2].fY), pts[3].fY); 266cb93a386Sopenharmony_ci if (bottomOffset < quadTop) { break; } 267cb93a386Sopenharmony_ci SkScalar quadBottom = 268cb93a386Sopenharmony_ci std::max(std::max(std::max(pts[0].fY, pts[1].fY), pts[2].fY), pts[3].fY); 269cb93a386Sopenharmony_ci if (topOffset > quadBottom) { break; } 270cb93a386Sopenharmony_ci addCubic(topOffset); 271cb93a386Sopenharmony_ci addCubic(bottomOffset); 272cb93a386Sopenharmony_ci addPts(4); 273cb93a386Sopenharmony_ci break; 274cb93a386Sopenharmony_ci } 275cb93a386Sopenharmony_ci case SkPath::kClose_Verb: { 276cb93a386Sopenharmony_ci break; 277cb93a386Sopenharmony_ci } 278cb93a386Sopenharmony_ci default: { 279cb93a386Sopenharmony_ci SkASSERT(0); 280cb93a386Sopenharmony_ci break; 281cb93a386Sopenharmony_ci } 282cb93a386Sopenharmony_ci } 283cb93a386Sopenharmony_ci } 284cb93a386Sopenharmony_ci 285cb93a386Sopenharmony_ci return std::tie(left, right); 286cb93a386Sopenharmony_ci} 287cb93a386Sopenharmony_ci 288cb93a386Sopenharmony_civoid SkGlyph::ensureIntercepts(const SkScalar* bounds, SkScalar scale, SkScalar xPos, 289cb93a386Sopenharmony_ci SkScalar* array, int* count, SkArenaAlloc* alloc) { 290cb93a386Sopenharmony_ci 291cb93a386Sopenharmony_ci auto offsetResults = [scale, xPos]( 292cb93a386Sopenharmony_ci const SkGlyph::Intercept* intercept,SkScalar* array, int* count) { 293cb93a386Sopenharmony_ci if (array) { 294cb93a386Sopenharmony_ci array += *count; 295cb93a386Sopenharmony_ci for (int index = 0; index < 2; index++) { 296cb93a386Sopenharmony_ci *array++ = intercept->fInterval[index] * scale + xPos; 297cb93a386Sopenharmony_ci } 298cb93a386Sopenharmony_ci } 299cb93a386Sopenharmony_ci *count += 2; 300cb93a386Sopenharmony_ci }; 301cb93a386Sopenharmony_ci 302cb93a386Sopenharmony_ci const SkGlyph::Intercept* match = 303cb93a386Sopenharmony_ci [this](const SkScalar bounds[2]) -> const SkGlyph::Intercept* { 304cb93a386Sopenharmony_ci if (!fPathData) { 305cb93a386Sopenharmony_ci return nullptr; 306cb93a386Sopenharmony_ci } 307cb93a386Sopenharmony_ci const SkGlyph::Intercept* intercept = fPathData->fIntercept; 308cb93a386Sopenharmony_ci while (intercept) { 309cb93a386Sopenharmony_ci if (bounds[0] == intercept->fBounds[0] && bounds[1] == intercept->fBounds[1]) { 310cb93a386Sopenharmony_ci return intercept; 311cb93a386Sopenharmony_ci } 312cb93a386Sopenharmony_ci intercept = intercept->fNext; 313cb93a386Sopenharmony_ci } 314cb93a386Sopenharmony_ci return nullptr; 315cb93a386Sopenharmony_ci }(bounds); 316cb93a386Sopenharmony_ci 317cb93a386Sopenharmony_ci if (match) { 318cb93a386Sopenharmony_ci if (match->fInterval[0] < match->fInterval[1]) { 319cb93a386Sopenharmony_ci offsetResults(match, array, count); 320cb93a386Sopenharmony_ci } 321cb93a386Sopenharmony_ci return; 322cb93a386Sopenharmony_ci } 323cb93a386Sopenharmony_ci 324cb93a386Sopenharmony_ci SkGlyph::Intercept* intercept = alloc->make<SkGlyph::Intercept>(); 325cb93a386Sopenharmony_ci intercept->fNext = fPathData->fIntercept; 326cb93a386Sopenharmony_ci intercept->fBounds[0] = bounds[0]; 327cb93a386Sopenharmony_ci intercept->fBounds[1] = bounds[1]; 328cb93a386Sopenharmony_ci intercept->fInterval[0] = SK_ScalarMax; 329cb93a386Sopenharmony_ci intercept->fInterval[1] = SK_ScalarMin; 330cb93a386Sopenharmony_ci fPathData->fIntercept = intercept; 331cb93a386Sopenharmony_ci const SkPath* path = &(fPathData->fPath); 332cb93a386Sopenharmony_ci const SkRect& pathBounds = path->getBounds(); 333cb93a386Sopenharmony_ci if (pathBounds.fBottom < bounds[0] || bounds[1] < pathBounds.fTop) { 334cb93a386Sopenharmony_ci return; 335cb93a386Sopenharmony_ci } 336cb93a386Sopenharmony_ci 337cb93a386Sopenharmony_ci std::tie(intercept->fInterval[0], intercept->fInterval[1]) 338cb93a386Sopenharmony_ci = calculate_path_gap(bounds[0], bounds[1], *path); 339cb93a386Sopenharmony_ci 340cb93a386Sopenharmony_ci if (intercept->fInterval[0] >= intercept->fInterval[1]) { 341cb93a386Sopenharmony_ci intercept->fInterval[0] = SK_ScalarMax; 342cb93a386Sopenharmony_ci intercept->fInterval[1] = SK_ScalarMin; 343cb93a386Sopenharmony_ci return; 344cb93a386Sopenharmony_ci } 345cb93a386Sopenharmony_ci offsetResults(intercept, array, count); 346cb93a386Sopenharmony_ci} 347