OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 } |
OLD | NEW |