Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(288)

Side by Side Diff: src/core/SkDraw.cpp

Issue 1403573002: Simplify draw one glyph (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: merge simplified draw one glyph in. Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2006 The Android Open Source Project 2 * Copyright 2006 The Android Open Source Project
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 #define __STDC_LIMIT_MACROS 7 #define __STDC_LIMIT_MACROS
8 8
9 #include "SkDraw.h" 9 #include "SkDraw.h"
10 #include "SkBlitter.h" 10 #include "SkBlitter.h"
(...skipping 1405 matching lines...) Expand 10 before | Expand all | Expand 10 after
1416 } 1416 }
1417 } 1417 }
1418 1418
1419 // disable warning : local variable used without having been initialized 1419 // disable warning : local variable used without having been initialized
1420 #if defined _WIN32 && _MSC_VER >= 1300 1420 #if defined _WIN32 && _MSC_VER >= 1300
1421 #pragma warning ( push ) 1421 #pragma warning ( push )
1422 #pragma warning ( disable : 4701 ) 1422 #pragma warning ( disable : 4701 )
1423 #endif 1423 #endif
1424 1424
1425 //////////////////////////////////////////////////////////////////////////////// //////////////////// 1425 //////////////////////////////////////////////////////////////////////////////// ////////////////////
1426 struct SkDraw1Glyph {
1427 const SkDraw* fDraw;
1428 const SkRegion* fClip;
1429 const SkAAClip* fAAClip;
1430 SkBlitter* fBlitter;
1431 SkGlyphCache* fCache;
1432 const SkPaint* fPaint;
1433 SkIRect fClipBounds;
1434 /** Half the sampling frequency of the rasterized glyph in x. */
1435 SkScalar fHalfSampleX;
1436 /** Half the sampling frequency of the rasterized glyph in y. */
1437 SkScalar fHalfSampleY;
1438 1426
1439 /** Draws one glyph. 1427 class DrawOneGlyph {
1440 * 1428 public:
1441 * The x and y are pre-biased, so implementations may just truncate them. 1429 DrawOneGlyph(const SkDraw& draw, const SkPaint& paint, SkGlyphCache* cache,
1442 * i.e. half the sampling frequency has been added. 1430 SkBlitter* blitter)
bungeman-skia 2015/11/30 21:42:29 nit: Will this fit on the previous line? It looks
herb_g 2015/11/30 22:11:43 Done.
1443 * e.g. 1/2 or 1/(2^(SkGlyph::kSubBits+1)) has already been added. 1431 : fUseRegionToDraw(UseRegionDrawOneGlyph(draw.fRC))
1444 * This added bias can be found in fHalfSampleX,Y. 1432 , fGlyphCache(cache)
1445 */ 1433 , fBlitter(blitter)
1446 typedef void (*Proc)(const SkDraw1Glyph&, Sk48Dot16 x, Sk48Dot16 y, const Sk Glyph&); 1434 , fClip(fUseRegionToDraw ? &draw.fRC->bwRgn() : nullptr)
1435 , fDraw(draw)
1436 , fPaint(paint) {
1437 const SkRasterClip& rasterClip = *draw.fRC;
1447 1438
1448 Proc init(const SkDraw* draw, SkBlitter* blitter, SkGlyphCache* cache, 1439 if (rasterClip.isBW()) {
1449 const SkPaint&); 1440 fClipBounds = rasterClip.bwRgn().getBounds();
1441 } else {
1442 fClipBounds = rasterClip.aaRgn().getBounds();
1443 }
1444 }
1450 1445
1451 // call this instead of fBlitter->blitMask() since this wrapper will handle 1446 void drawOneGlyph(const SkGlyph& glyph, SkPoint position) {
bungeman-skia 2015/11/30 21:42:29 Is there a reason not to make this void operator(
herb_g 2015/11/30 22:11:43 Done - made it obey the FindAndPlaceGlyph interfac
1452 // the case when the mask is ARGB32_Format 1447 Sk48Dot16 fx = SkScalarTo48Dot16(position.fX);
1453 // 1448 Sk48Dot16 fy = SkScalarTo48Dot16(position.fY);
1449 // Prevent glyphs from being drawn outside of or straddling the edge of device space.
1450 if ((fx >> 16) > INT_MAX - (INT16_MAX + UINT16_MAX) ||
1451 (fx >> 16) < INT_MIN - (INT16_MIN + 0 /*UINT16_MIN*/) ||
1452 (fy >> 16) > INT_MAX - (INT16_MAX + UINT16_MAX) ||
1453 (fy >> 16) < INT_MIN - (INT16_MIN + 0 /*UINT16_MIN*/)) {
1454 return;
1455 }
1456
1457 int left = Sk48Dot16FloorToInt(fx);
1458 int top = Sk48Dot16FloorToInt(fy);
1459 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1460
1461 left += glyph.fLeft;
1462 top += glyph.fTop;
1463
1464 int right = left + glyph.fWidth;
1465 int bottom = top + glyph.fHeight;
1466
1467 SkMask mask;
1468 mask.fBounds.set(left, top, right, bottom);
1469
1470 if (fUseRegionToDraw) {
bungeman-skia 2015/11/30 21:42:29 So essentially, this is trading off a predictable
herb_g 2015/11/30 22:11:43 That is one of two reasons. The second is that the
1471 SkRegion::Cliperator clipper(*fClip, mask.fBounds);
1472
1473 if (!clipper.done() && this->getImageData(glyph, &mask)) {
1474 const SkIRect& cr = clipper.rect();
1475 do {
1476 this->blitMask(mask, cr);
1477 clipper.next();
1478 } while (!clipper.done());
1479 }
1480 } else {
1481 SkIRect storage;
1482 SkIRect* bounds = &mask.fBounds;
1483
1484 // this extra test is worth it, assuming that most of the time it su cceeds
1485 // since we can avoid writing to storage
1486 if (!fClipBounds.containsNoEmptyCheck(mask.fBounds)) {
1487 if (!storage.intersectNoEmptyCheck(mask.fBounds, fClipBounds))
1488 return;
1489 bounds = &storage;
1490 }
1491
1492 if (this->getImageData(glyph, &mask)) {
1493 this->blitMask(mask, *bounds);
1494 }
1495 }
1496 }
1497
1498 private:
1499 static bool UseRegionDrawOneGlyph(const SkRasterClip* rClip) {
bungeman-skia 2015/11/30 21:42:29 Can this just be named 'UseRegionToDraw' so that i
herb_g 2015/11/30 22:11:44 Done.
1500 return rClip->isBW() && !rClip->isRect();
1501 }
1502
1503 bool getImageData(const SkGlyph& glyph, SkMask* mask) {
1504 uint8_t* bits = (uint8_t*)(fGlyphCache->findImage(glyph));
1505 if (nullptr == bits) {
1506 return false; // can't rasterize glyph
1507 }
1508 mask->fImage = bits;
1509 mask->fRowBytes = glyph.rowBytes();
1510 mask->fFormat = static_cast<SkMask::Format>(glyph.fMaskFormat);
1511 return true;
1512 }
1513
1454 void blitMask(const SkMask& mask, const SkIRect& clip) const { 1514 void blitMask(const SkMask& mask, const SkIRect& clip) const {
1455 if (SkMask::kARGB32_Format == mask.fFormat) { 1515 if (SkMask::kARGB32_Format == mask.fFormat) {
1456 this->blitMaskAsSprite(mask); 1516 SkBitmap bm;
1517 bm.installPixels(
1518 SkImageInfo::MakeN32Premul(mask.fBounds.width(), mask.fBounds.he ight()),
1519 (SkPMColor*)mask.fImage, mask.fRowBytes);
1520
1521 fDraw.drawSprite(bm, mask.fBounds.x(), mask.fBounds.y(), fPaint);
1457 } else { 1522 } else {
1458 fBlitter->blitMask(mask, clip); 1523 fBlitter->blitMask(mask, clip);
1459 } 1524 }
1460 } 1525 }
1461 1526
1462 // mask must be kARGB32_Format 1527 const bool fUseRegionToDraw;
1463 void blitMaskAsSprite(const SkMask& mask) const; 1528 SkGlyphCache * const fGlyphCache;
1529 SkBlitter * const fBlitter;
1530 const SkRegion* const fClip;
1531 const SkDraw& fDraw;
1532 const SkPaint& fPaint;
1533 SkIRect fClipBounds;
1464 }; 1534 };
1465 1535
1466 static void D1G_RectClip(const SkDraw1Glyph& state, Sk48Dot16 fx, Sk48Dot16 fy, 1536 //////////////////////////////////////////////////////////////////////////////// ////////////////////
1467 const SkGlyph& glyph) {
1468 // Prevent glyphs from being drawn outside of or straddling the edge of devi ce space.
1469 if ((fx >> 16) > INT_MAX - (INT16_MAX + UINT16_MAX) ||
1470 (fx >> 16) < INT_MIN - (INT16_MIN + 0 /*UINT16_MIN*/) ||
1471 (fy >> 16) > INT_MAX - (INT16_MAX + UINT16_MAX) ||
1472 (fy >> 16) < INT_MIN - (INT16_MIN + 0 /*UINT16_MIN*/))
1473 {
1474 return;
1475 }
1476
1477 int left = Sk48Dot16FloorToInt(fx);
1478 int top = Sk48Dot16FloorToInt(fy);
1479 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1480 SkASSERT((nullptr == state.fClip && state.fAAClip) ||
1481 (state.fClip && nullptr == state.fAAClip && state.fClip->isRect())) ;
1482
1483 left += glyph.fLeft;
1484 top += glyph.fTop;
1485
1486 int right = left + glyph.fWidth;
1487 int bottom = top + glyph.fHeight;
1488
1489 SkMask mask;
1490 SkIRect storage;
1491 SkIRect* bounds = &mask.fBounds;
1492
1493 mask.fBounds.set(left, top, right, bottom);
1494
1495 // this extra test is worth it, assuming that most of the time it succeeds
1496 // since we can avoid writing to storage
1497 if (!state.fClipBounds.containsNoEmptyCheck(left, top, right, bottom)) {
1498 if (!storage.intersectNoEmptyCheck(mask.fBounds, state.fClipBounds))
1499 return;
1500 bounds = &storage;
1501 }
1502
1503 uint8_t* aa = (uint8_t*)glyph.fImage;
1504 if (nullptr == aa) {
1505 aa = (uint8_t*)state.fCache->findImage(glyph);
1506 if (nullptr == aa) {
1507 return; // can't rasterize glyph
1508 }
1509 }
1510
1511 mask.fRowBytes = glyph.rowBytes();
1512 mask.fFormat = static_cast<SkMask::Format>(glyph.fMaskFormat);
1513 mask.fImage = aa;
1514 state.blitMask(mask, *bounds);
1515 }
1516
1517 static void D1G_RgnClip(const SkDraw1Glyph& state, Sk48Dot16 fx, Sk48Dot16 fy,
1518 const SkGlyph& glyph) {
1519 int left = Sk48Dot16FloorToInt(fx);
1520 int top = Sk48Dot16FloorToInt(fy);
1521 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1522 SkASSERT(!state.fClip->isRect());
1523
1524 SkMask mask;
1525
1526 left += glyph.fLeft;
1527 top += glyph.fTop;
1528
1529 mask.fBounds.set(left, top, left + glyph.fWidth, top + glyph.fHeight);
1530 SkRegion::Cliperator clipper(*state.fClip, mask.fBounds);
1531
1532 if (!clipper.done()) {
1533 const SkIRect& cr = clipper.rect();
1534 const uint8_t* aa = (uint8_t*)state.fCache->findImage(glyph);
1535 if (nullptr == aa) {
1536 return;
1537 }
1538
1539 mask.fRowBytes = glyph.rowBytes();
1540 mask.fFormat = static_cast<SkMask::Format>(glyph.fMaskFormat);
1541 mask.fImage = (uint8_t*)aa;
1542 do {
1543 state.blitMask(mask, cr);
1544 clipper.next();
1545 } while (!clipper.done());
1546 }
1547 }
1548
1549 SkDraw1Glyph::Proc SkDraw1Glyph::init(const SkDraw* draw, SkBlitter* blitter, Sk GlyphCache* cache,
1550 const SkPaint& pnt) {
1551 fDraw = draw;
1552 fBlitter = blitter;
1553 fCache = cache;
1554 fPaint = &pnt;
1555
1556 if (cache->isSubpixel()) {
1557 fHalfSampleX = fHalfSampleY = SkFixedToScalar(SkGlyph::kSubpixelRound);
1558 } else {
1559 fHalfSampleX = fHalfSampleY = SK_ScalarHalf;
1560 }
1561
1562 if (draw->fRC->isBW()) {
1563 fAAClip = nullptr;
1564 fClip = &draw->fRC->bwRgn();
1565 fClipBounds = fClip->getBounds();
1566 if (fClip->isRect()) {
1567 return D1G_RectClip;
1568 } else {
1569 return D1G_RgnClip;
1570 }
1571 } else { // aaclip
1572 fAAClip = &draw->fRC->aaRgn();
1573 fClip = nullptr;
1574 fClipBounds = fAAClip->getBounds();
1575 return D1G_RectClip;
1576 }
1577 }
1578
1579 void SkDraw1Glyph::blitMaskAsSprite(const SkMask& mask) const {
1580 SkASSERT(SkMask::kARGB32_Format == mask.fFormat);
1581
1582 SkBitmap bm;
1583 bm.installPixels(SkImageInfo::MakeN32Premul(mask.fBounds.width(), mask.fBoun ds.height()),
1584 (SkPMColor*)mask.fImage, mask.fRowBytes);
1585
1586 fDraw->drawSprite(bm, mask.fBounds.x(), mask.fBounds.y(), *fPaint);
1587 }
1588
1589 ///////////////////////////////////////////////////////////////////////////////
1590 1537
1591 void SkDraw::drawText(const char text[], size_t byteLength, 1538 void SkDraw::drawText(const char text[], size_t byteLength,
1592 SkScalar x, SkScalar y, const SkPaint& paint) const { 1539 SkScalar x, SkScalar y, const SkPaint& paint) const {
1593 SkASSERT(byteLength == 0 || text != nullptr); 1540 SkASSERT(byteLength == 0 || text != nullptr);
1594 1541
1595 SkDEBUGCODE(this->validate();) 1542 SkDEBUGCODE(this->validate();)
1596 1543
1597 // nothing to draw 1544 // nothing to draw
1598 if (text == nullptr || byteLength == 0 || fRC->isEmpty()) { 1545 if (text == nullptr || byteLength == 0 || fRC->isEmpty()) {
1599 return; 1546 return;
1600 } 1547 }
1601 1548
1602 // SkScalarRec doesn't currently have a way of representing hairline stroke and 1549 // SkScalarRec doesn't currently have a way of representing hairline stroke and
1603 // will fill if its frame-width is 0. 1550 // will fill if its frame-width is 0.
1604 if (ShouldDrawTextAsPaths(paint, *fMatrix)) { 1551 if (ShouldDrawTextAsPaths(paint, *fMatrix)) {
1605 this->drawText_asPaths(text, byteLength, x, y, paint); 1552 this->drawText_asPaths(text, byteLength, x, y, paint);
1606 return; 1553 return;
1607 } 1554 }
1608 1555
1609 SkAutoGlyphCache autoCache(paint, &fDevice->surfaceProps(), fMatrix); 1556 SkAutoGlyphCache autoCache(paint, &fDevice->surfaceProps(), fMatrix);
1610 SkGlyphCache* cache = autoCache.getCache(); 1557 SkGlyphCache* cache = autoCache.getCache();
1611 1558
1612
1613 // The Blitter Choose needs to be live while using the blitter below. 1559 // The Blitter Choose needs to be live while using the blitter below.
1614 SkAutoBlitterChoose blitterChooser(fDst, *fMatrix, paint); 1560 SkAutoBlitterChoose blitterChooser(fDst, *fMatrix, paint);
1615 SkAAClipBlitterWrapper wrapper(*fRC, blitterChooser.get()); 1561 SkAAClipBlitterWrapper wrapper(*fRC, blitterChooser.get());
1616 1562
1617 SkDraw1Glyph d1g; 1563 DrawOneGlyph drawOneGlyph(*this, paint, cache, wrapper.getBlitter());
bungeman-skia 2015/11/30 21:42:29 nit: Any reason for the spacing here? It seems to
herb_g 2015/11/30 22:11:43 Done.
1618 SkDraw1Glyph::Proc proc = d1g.init(this, wrapper.getBlitter(), cache, paint );
1619 1564
1620 SkFindAndPlaceGlyph::ProcessText( 1565 SkFindAndPlaceGlyph::ProcessText(
1621 paint.getTextEncoding(), text, byteLength, 1566 paint.getTextEncoding(), text, byteLength,
1622 {x, y}, *fMatrix, paint.getTextAlign(), cache, 1567 {x, y}, *fMatrix, paint.getTextAlign(), cache,
1623 [&](const SkGlyph& glyph, SkPoint position, SkPoint rounding) { 1568 [&](const SkGlyph& glyph, SkPoint position, SkPoint rounding) {
1624 position += rounding; 1569 position += rounding;
1625 proc(d1g, SkScalarTo48Dot16(position.fX), SkScalarTo48Dot16(position .fY), glyph); 1570 drawOneGlyph.drawOneGlyph(glyph, position);
1626 } 1571 }
1627 ); 1572 );
1628 } 1573 }
1629 1574
1630 ////////////////////////////////////////////////////////////////////////////// 1575 //////////////////////////////////////////////////////////////////////////////
1631 1576
1632 void SkDraw::drawPosText_asPaths(const char text[], size_t byteLength, 1577 void SkDraw::drawPosText_asPaths(const char text[], size_t byteLength,
1633 const SkScalar pos[], int scalarsPerPosition, 1578 const SkScalar pos[], int scalarsPerPosition,
1634 const SkPoint& offset, const SkPaint& origPaint ) const { 1579 const SkPoint& offset, const SkPaint& origPaint ) const {
1635 // setup our std paint, in hopes of getting hits in the cache 1580 // setup our std paint, in hopes of getting hits in the cache
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
1689 // nothing to draw 1634 // nothing to draw
1690 if (text == nullptr || byteLength == 0 || fRC->isEmpty()) { 1635 if (text == nullptr || byteLength == 0 || fRC->isEmpty()) {
1691 return; 1636 return;
1692 } 1637 }
1693 1638
1694 if (ShouldDrawTextAsPaths(paint, *fMatrix)) { 1639 if (ShouldDrawTextAsPaths(paint, *fMatrix)) {
1695 this->drawPosText_asPaths(text, byteLength, pos, scalarsPerPosition, off set, paint); 1640 this->drawPosText_asPaths(text, byteLength, pos, scalarsPerPosition, off set, paint);
1696 return; 1641 return;
1697 } 1642 }
1698 1643
1644 SkAutoGlyphCache autoCache(paint, &fDevice->surfaceProps(), fMatrix);
1645 SkGlyphCache* cache = autoCache.getCache();
1646
1699 // The Blitter Choose needs to be live while using the blitter below. 1647 // The Blitter Choose needs to be live while using the blitter below.
1700 SkAutoBlitterChoose blitterChooser(fDst, *fMatrix, paint); 1648 SkAutoBlitterChoose blitterChooser(fDst, *fMatrix, paint);
1701 SkAAClipBlitterWrapper wrapper(*fRC, blitterChooser.get()); 1649 SkAAClipBlitterWrapper wrapper(*fRC, blitterChooser.get());
1702 1650
1703 SkAutoGlyphCache autoCache(paint, &fDevice->surfaceProps(), fMatrix); 1651 DrawOneGlyph drawOneGlyph(*this, paint, cache, wrapper.getBlitter());
1704 SkGlyphCache* cache = autoCache.getCache(); 1652
1705 SkDraw1Glyph d1g;
1706 SkDraw1Glyph::Proc proc = d1g.init(this, wrapper.getBlitter(), cache, paint) ;
1707 SkPaint::Align textAlignment = paint.getTextAlign(); 1653 SkPaint::Align textAlignment = paint.getTextAlign();
1708 1654
1709 SkFindAndPlaceGlyph::ProcessPosText( 1655 SkFindAndPlaceGlyph::ProcessPosText(
1710 paint.getTextEncoding(), text, byteLength, 1656 paint.getTextEncoding(), text, byteLength,
1711 offset, *fMatrix, pos, scalarsPerPosition, textAlignment, cache, 1657 offset, *fMatrix, pos, scalarsPerPosition, textAlignment, cache,
1712 [&](const SkGlyph& glyph, SkPoint position, SkPoint rounding) { 1658 [&](const SkGlyph& glyph, SkPoint position, SkPoint rounding) {
1713 position += rounding; 1659 position += rounding;
1714 proc(d1g, SkScalarTo48Dot16(position.fX), SkScalarTo48Dot16(position .fY), glyph); 1660 drawOneGlyph.drawOneGlyph(glyph, position);
1715 } 1661 }
1716 ); 1662 );
1717 } 1663 }
1718 1664
1719 #if defined _WIN32 && _MSC_VER >= 1300 1665 #if defined _WIN32 && _MSC_VER >= 1300
1720 #pragma warning ( pop ) 1666 #pragma warning ( pop )
1721 #endif 1667 #endif
1722 1668
1723 /////////////////////////////////////////////////////////////////////////////// 1669 ///////////////////////////////////////////////////////////////////////////////
1724 1670
(...skipping 384 matching lines...) Expand 10 before | Expand all | Expand 10 after
2109 mask->fImage = SkMask::AllocImage(size); 2055 mask->fImage = SkMask::AllocImage(size);
2110 memset(mask->fImage, 0, mask->computeImageSize()); 2056 memset(mask->fImage, 0, mask->computeImageSize());
2111 } 2057 }
2112 2058
2113 if (SkMask::kJustComputeBounds_CreateMode != mode) { 2059 if (SkMask::kJustComputeBounds_CreateMode != mode) {
2114 draw_into_mask(*mask, devPath, style); 2060 draw_into_mask(*mask, devPath, style);
2115 } 2061 }
2116 2062
2117 return true; 2063 return true;
2118 } 2064 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698