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; |
1426 | 1438 |
1427 class DrawOneGlyph { | 1439 /** Draws one glyph. |
1428 public: | 1440 * |
1429 DrawOneGlyph(const SkDraw& draw, const SkPaint& paint, SkGlyphCache* cache,
SkBlitter* blitter) | 1441 * The x and y are pre-biased, so implementations may just truncate them. |
1430 : fUseRegionToDraw(UsingRegionToDraw(draw.fRC)) | 1442 * i.e. half the sampling frequency has been added. |
1431 , fGlyphCache(cache) | 1443 * e.g. 1/2 or 1/(2^(SkGlyph::kSubBits+1)) has already been added. |
1432 , fBlitter(blitter) | 1444 * This added bias can be found in fHalfSampleX,Y. |
1433 , fClip(fUseRegionToDraw ? &draw.fRC->bwRgn() : nullptr) | 1445 */ |
1434 , fDraw(draw) | 1446 typedef void (*Proc)(const SkDraw1Glyph&, Sk48Dot16 x, Sk48Dot16 y, const Sk
Glyph&); |
1435 , fPaint(paint) | |
1436 , fClipBounds(PickClipBounds(draw)) { } | |
1437 | 1447 |
1438 void operator()(const SkGlyph& glyph, SkPoint position, SkPoint rounding) { | 1448 Proc init(const SkDraw* draw, SkBlitter* blitter, SkGlyphCache* cache, |
1439 position += rounding; | 1449 const SkPaint&); |
1440 Sk48Dot16 fx = SkScalarTo48Dot16(position.fX); | |
1441 Sk48Dot16 fy = SkScalarTo48Dot16(position.fY); | |
1442 // Prevent glyphs from being drawn outside of or straddling the edge of
device space. | |
1443 if ((fx >> 16) > INT_MAX - (INT16_MAX + UINT16_MAX) || | |
1444 (fx >> 16) < INT_MIN - (INT16_MIN + 0 /*UINT16_MIN*/) || | |
1445 (fy >> 16) > INT_MAX - (INT16_MAX + UINT16_MAX) || | |
1446 (fy >> 16) < INT_MIN - (INT16_MIN + 0 /*UINT16_MIN*/)) { | |
1447 return; | |
1448 } | |
1449 | 1450 |
1450 int left = Sk48Dot16FloorToInt(fx); | 1451 // call this instead of fBlitter->blitMask() since this wrapper will handle |
1451 int top = Sk48Dot16FloorToInt(fy); | 1452 // the case when the mask is ARGB32_Format |
1452 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0); | 1453 // |
1453 | |
1454 left += glyph.fLeft; | |
1455 top += glyph.fTop; | |
1456 | |
1457 int right = left + glyph.fWidth; | |
1458 int bottom = top + glyph.fHeight; | |
1459 | |
1460 SkMask mask; | |
1461 mask.fBounds.set(left, top, right, bottom); | |
1462 | |
1463 if (fUseRegionToDraw) { | |
1464 SkRegion::Cliperator clipper(*fClip, mask.fBounds); | |
1465 | |
1466 if (!clipper.done() && this->getImageData(glyph, &mask)) { | |
1467 const SkIRect& cr = clipper.rect(); | |
1468 do { | |
1469 this->blitMask(mask, cr); | |
1470 clipper.next(); | |
1471 } while (!clipper.done()); | |
1472 } | |
1473 } else { | |
1474 SkIRect storage; | |
1475 SkIRect* bounds = &mask.fBounds; | |
1476 | |
1477 // this extra test is worth it, assuming that most of the time it su
cceeds | |
1478 // since we can avoid writing to storage | |
1479 if (!fClipBounds.containsNoEmptyCheck(mask.fBounds)) { | |
1480 if (!storage.intersectNoEmptyCheck(mask.fBounds, fClipBounds)) | |
1481 return; | |
1482 bounds = &storage; | |
1483 } | |
1484 | |
1485 if (this->getImageData(glyph, &mask)) { | |
1486 this->blitMask(mask, *bounds); | |
1487 } | |
1488 } | |
1489 } | |
1490 | |
1491 private: | |
1492 static bool UsingRegionToDraw(const SkRasterClip* rClip) { | |
1493 return rClip->isBW() && !rClip->isRect(); | |
1494 } | |
1495 | |
1496 static SkIRect PickClipBounds(const SkDraw& draw) { | |
1497 const SkRasterClip& rasterClip = *draw.fRC; | |
1498 | |
1499 if (rasterClip.isBW()) { | |
1500 return rasterClip.bwRgn().getBounds(); | |
1501 } else { | |
1502 return rasterClip.aaRgn().getBounds(); | |
1503 } | |
1504 } | |
1505 | |
1506 bool getImageData(const SkGlyph& glyph, SkMask* mask) { | |
1507 uint8_t* bits = (uint8_t*)(fGlyphCache->findImage(glyph)); | |
1508 if (nullptr == bits) { | |
1509 return false; // can't rasterize glyph | |
1510 } | |
1511 mask->fImage = bits; | |
1512 mask->fRowBytes = glyph.rowBytes(); | |
1513 mask->fFormat = static_cast<SkMask::Format>(glyph.fMaskFormat); | |
1514 return true; | |
1515 } | |
1516 | |
1517 void blitMask(const SkMask& mask, const SkIRect& clip) const { | 1454 void blitMask(const SkMask& mask, const SkIRect& clip) const { |
1518 if (SkMask::kARGB32_Format == mask.fFormat) { | 1455 if (SkMask::kARGB32_Format == mask.fFormat) { |
1519 SkBitmap bm; | 1456 this->blitMaskAsSprite(mask); |
1520 bm.installPixels( | |
1521 SkImageInfo::MakeN32Premul(mask.fBounds.width(), mask.fBounds.he
ight()), | |
1522 (SkPMColor*)mask.fImage, mask.fRowBytes); | |
1523 | |
1524 fDraw.drawSprite(bm, mask.fBounds.x(), mask.fBounds.y(), fPaint); | |
1525 } else { | 1457 } else { |
1526 fBlitter->blitMask(mask, clip); | 1458 fBlitter->blitMask(mask, clip); |
1527 } | 1459 } |
1528 } | 1460 } |
1529 | 1461 |
1530 const bool fUseRegionToDraw; | 1462 // mask must be kARGB32_Format |
1531 SkGlyphCache * const fGlyphCache; | 1463 void blitMaskAsSprite(const SkMask& mask) const; |
1532 SkBlitter * const fBlitter; | |
1533 const SkRegion* const fClip; | |
1534 const SkDraw& fDraw; | |
1535 const SkPaint& fPaint; | |
1536 const SkIRect fClipBounds; | |
1537 }; | 1464 }; |
1538 | 1465 |
1539 ////////////////////////////////////////////////////////////////////////////////
//////////////////// | 1466 static void D1G_RectClip(const SkDraw1Glyph& state, Sk48Dot16 fx, Sk48Dot16 fy, |
| 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 /////////////////////////////////////////////////////////////////////////////// |
1540 | 1590 |
1541 void SkDraw::drawText(const char text[], size_t byteLength, | 1591 void SkDraw::drawText(const char text[], size_t byteLength, |
1542 SkScalar x, SkScalar y, const SkPaint& paint) const { | 1592 SkScalar x, SkScalar y, const SkPaint& paint) const { |
1543 SkASSERT(byteLength == 0 || text != nullptr); | 1593 SkASSERT(byteLength == 0 || text != nullptr); |
1544 | 1594 |
1545 SkDEBUGCODE(this->validate();) | 1595 SkDEBUGCODE(this->validate();) |
1546 | 1596 |
1547 // nothing to draw | 1597 // nothing to draw |
1548 if (text == nullptr || byteLength == 0 || fRC->isEmpty()) { | 1598 if (text == nullptr || byteLength == 0 || fRC->isEmpty()) { |
1549 return; | 1599 return; |
1550 } | 1600 } |
1551 | 1601 |
1552 // SkScalarRec doesn't currently have a way of representing hairline stroke
and | 1602 // SkScalarRec doesn't currently have a way of representing hairline stroke
and |
1553 // will fill if its frame-width is 0. | 1603 // will fill if its frame-width is 0. |
1554 if (ShouldDrawTextAsPaths(paint, *fMatrix)) { | 1604 if (ShouldDrawTextAsPaths(paint, *fMatrix)) { |
1555 this->drawText_asPaths(text, byteLength, x, y, paint); | 1605 this->drawText_asPaths(text, byteLength, x, y, paint); |
1556 return; | 1606 return; |
1557 } | 1607 } |
1558 | 1608 |
1559 SkAutoGlyphCache autoCache(paint, &fDevice->surfaceProps(), fMatrix); | 1609 SkAutoGlyphCache autoCache(paint, &fDevice->surfaceProps(), fMatrix); |
1560 SkGlyphCache* cache = autoCache.getCache(); | 1610 SkGlyphCache* cache = autoCache.getCache(); |
| 1611 |
1561 | 1612 |
1562 // The Blitter Choose needs to be live while using the blitter below. | 1613 // The Blitter Choose needs to be live while using the blitter below. |
1563 SkAutoBlitterChoose blitterChooser(fDst, *fMatrix, paint); | 1614 SkAutoBlitterChoose blitterChooser(fDst, *fMatrix, paint); |
1564 SkAAClipBlitterWrapper wrapper(*fRC, blitterChooser.get()); | 1615 SkAAClipBlitterWrapper wrapper(*fRC, blitterChooser.get()); |
1565 DrawOneGlyph drawOneGlyph(*this, paint, cache, wrapper.getBlitter(
)); | 1616 |
| 1617 SkDraw1Glyph d1g; |
| 1618 SkDraw1Glyph::Proc proc = d1g.init(this, wrapper.getBlitter(), cache, paint
); |
1566 | 1619 |
1567 SkFindAndPlaceGlyph::ProcessText( | 1620 SkFindAndPlaceGlyph::ProcessText( |
1568 paint.getTextEncoding(), text, byteLength, | 1621 paint.getTextEncoding(), text, byteLength, |
1569 {x, y}, *fMatrix, paint.getTextAlign(), cache, drawOneGlyph); | 1622 {x, y}, *fMatrix, paint.getTextAlign(), cache, |
| 1623 [&](const SkGlyph& glyph, SkPoint position, SkPoint rounding) { |
| 1624 position += rounding; |
| 1625 proc(d1g, SkScalarTo48Dot16(position.fX), SkScalarTo48Dot16(position
.fY), glyph); |
| 1626 } |
| 1627 ); |
1570 } | 1628 } |
1571 | 1629 |
1572 ////////////////////////////////////////////////////////////////////////////// | 1630 ////////////////////////////////////////////////////////////////////////////// |
1573 | 1631 |
1574 void SkDraw::drawPosText_asPaths(const char text[], size_t byteLength, | 1632 void SkDraw::drawPosText_asPaths(const char text[], size_t byteLength, |
1575 const SkScalar pos[], int scalarsPerPosition, | 1633 const SkScalar pos[], int scalarsPerPosition, |
1576 const SkPoint& offset, const SkPaint& origPaint
) const { | 1634 const SkPoint& offset, const SkPaint& origPaint
) const { |
1577 // setup our std paint, in hopes of getting hits in the cache | 1635 // setup our std paint, in hopes of getting hits in the cache |
1578 SkPaint paint(origPaint); | 1636 SkPaint paint(origPaint); |
1579 SkScalar matrixScale = paint.setupForAsPaths(); | 1637 SkScalar matrixScale = paint.setupForAsPaths(); |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1631 // nothing to draw | 1689 // nothing to draw |
1632 if (text == nullptr || byteLength == 0 || fRC->isEmpty()) { | 1690 if (text == nullptr || byteLength == 0 || fRC->isEmpty()) { |
1633 return; | 1691 return; |
1634 } | 1692 } |
1635 | 1693 |
1636 if (ShouldDrawTextAsPaths(paint, *fMatrix)) { | 1694 if (ShouldDrawTextAsPaths(paint, *fMatrix)) { |
1637 this->drawPosText_asPaths(text, byteLength, pos, scalarsPerPosition, off
set, paint); | 1695 this->drawPosText_asPaths(text, byteLength, pos, scalarsPerPosition, off
set, paint); |
1638 return; | 1696 return; |
1639 } | 1697 } |
1640 | 1698 |
1641 SkAutoGlyphCache autoCache(paint, &fDevice->surfaceProps(), fMatrix); | |
1642 SkGlyphCache* cache = autoCache.getCache(); | |
1643 | |
1644 // The Blitter Choose needs to be live while using the blitter below. | 1699 // The Blitter Choose needs to be live while using the blitter below. |
1645 SkAutoBlitterChoose blitterChooser(fDst, *fMatrix, paint); | 1700 SkAutoBlitterChoose blitterChooser(fDst, *fMatrix, paint); |
1646 SkAAClipBlitterWrapper wrapper(*fRC, blitterChooser.get()); | 1701 SkAAClipBlitterWrapper wrapper(*fRC, blitterChooser.get()); |
1647 DrawOneGlyph drawOneGlyph(*this, paint, cache, wrapper.getBlitter(
)); | 1702 |
1648 SkPaint::Align textAlignment = paint.getTextAlign(); | 1703 SkAutoGlyphCache autoCache(paint, &fDevice->surfaceProps(), fMatrix); |
| 1704 SkGlyphCache* cache = autoCache.getCache(); |
| 1705 SkDraw1Glyph d1g; |
| 1706 SkDraw1Glyph::Proc proc = d1g.init(this, wrapper.getBlitter(), cache, paint)
; |
| 1707 SkPaint::Align textAlignment = paint.getTextAlign(); |
1649 | 1708 |
1650 SkFindAndPlaceGlyph::ProcessPosText( | 1709 SkFindAndPlaceGlyph::ProcessPosText( |
1651 paint.getTextEncoding(), text, byteLength, | 1710 paint.getTextEncoding(), text, byteLength, |
1652 offset, *fMatrix, pos, scalarsPerPosition, textAlignment, cache, drawOne
Glyph); | 1711 offset, *fMatrix, pos, scalarsPerPosition, textAlignment, cache, |
| 1712 [&](const SkGlyph& glyph, SkPoint position, SkPoint rounding) { |
| 1713 position += rounding; |
| 1714 proc(d1g, SkScalarTo48Dot16(position.fX), SkScalarTo48Dot16(position
.fY), glyph); |
| 1715 } |
| 1716 ); |
1653 } | 1717 } |
1654 | 1718 |
1655 #if defined _WIN32 && _MSC_VER >= 1300 | 1719 #if defined _WIN32 && _MSC_VER >= 1300 |
1656 #pragma warning ( pop ) | 1720 #pragma warning ( pop ) |
1657 #endif | 1721 #endif |
1658 | 1722 |
1659 /////////////////////////////////////////////////////////////////////////////// | 1723 /////////////////////////////////////////////////////////////////////////////// |
1660 | 1724 |
1661 static SkScan::HairRCProc ChooseHairProc(bool doAntiAlias) { | 1725 static SkScan::HairRCProc ChooseHairProc(bool doAntiAlias) { |
1662 return doAntiAlias ? SkScan::AntiHairLine : SkScan::HairLine; | 1726 return doAntiAlias ? SkScan::AntiHairLine : SkScan::HairLine; |
(...skipping 382 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2045 mask->fImage = SkMask::AllocImage(size); | 2109 mask->fImage = SkMask::AllocImage(size); |
2046 memset(mask->fImage, 0, mask->computeImageSize()); | 2110 memset(mask->fImage, 0, mask->computeImageSize()); |
2047 } | 2111 } |
2048 | 2112 |
2049 if (SkMask::kJustComputeBounds_CreateMode != mode) { | 2113 if (SkMask::kJustComputeBounds_CreateMode != mode) { |
2050 draw_into_mask(*mask, devPath, style); | 2114 draw_into_mask(*mask, devPath, style); |
2051 } | 2115 } |
2052 | 2116 |
2053 return true; | 2117 return true; |
2054 } | 2118 } |
OLD | NEW |