Exemplo n.º 1
0
bool GrLayerCache::lock(GrCachedLayer* layer, const GrTextureDesc& desc) {

    if (NULL != layer->texture()) {
        // This layer is already locked
#ifdef SK_DEBUG
        if (!layer->rect().isEmpty()) {
            // It claims to be atlased
            SkASSERT(layer->rect().width() == desc.fWidth);
            SkASSERT(layer->rect().height() == desc.fHeight);
        }
#endif
        return true;
    }

#if USE_ATLAS
    SkIPoint16 loc;
    GrPlot* plot = fAtlas->addToAtlas(&fPlotUsage, desc.fWidth, desc.fHeight, NULL, &loc);
    if (NULL != plot) {
        GrIRect16 bounds = GrIRect16::MakeXYWH(loc.fX, loc.fY, 
                                               SkToS16(desc.fWidth), SkToS16(desc.fHeight));
        layer->setTexture(fAtlas->getTexture(), bounds);
        return false;
    }
#endif

    // This path always uses a new scratch texture and (thus) doesn't cache anything.
    // This can yield a lot of re-rendering
    layer->setTexture(fContext->lockAndRefScratchTexture(desc, GrContext::kApprox_ScratchTexMatch),
                      GrIRect16::MakeEmpty());
    return false;
}
/** GetAlphaTextureBounds succeeds but sometimes returns empty bounds like
 *  { 0x80000000, 0x80000000, 0x80000000, 0x80000000 }
 *  for small, but not quite zero, sized glyphs.
 *  Only set as non-empty if the returned bounds are non-empty.
 */
static bool glyph_check_and_set_bounds(SkGlyph* glyph, const RECT& bbox) {
    if (bbox.left >= bbox.right || bbox.top >= bbox.bottom) {
        return false;
    }
    glyph->fWidth = SkToU16(bbox.right - bbox.left);
    glyph->fHeight = SkToU16(bbox.bottom - bbox.top);
    glyph->fLeft = SkToS16(bbox.left);
    glyph->fTop = SkToS16(bbox.top);
    return true;
}
Exemplo n.º 3
0
	DeviceCM(SkDevice* device, int x, int y, const SkPaint* paint)
            : fNext(NULL) {
        if (NULL != device) {
            device->ref();
            device->lockPixels();
        }
        fDevice = device;        
        fX = SkToS16(x);
        fY = SkToS16(y);
        fPaint = paint ? SkNEW_ARGS(SkPaint, (*paint)) : NULL;
	}
Exemplo n.º 4
0
void SkAlphaRuns::Break(int16_t runs[], uint8_t alpha[], int x, int count)
{
    SkASSERT(count > 0 && x >= 0);

//  SkAlphaRuns::BreakAt(runs, alpha, x);
//  SkAlphaRuns::BreakAt(&runs[x], &alpha[x], count);

    int16_t* next_runs = runs + x;
    uint8_t*  next_alpha = alpha + x;

    while (x > 0)
    {
        int n = runs[0];
        SkASSERT(n > 0);

        if (x < n)
        {
            alpha[x] = alpha[0];
            runs[0] = SkToS16(x);
            runs[x] = SkToS16(n - x);
            break;
        }
        runs += n;
        alpha += n;
        x -= n;
    }

    runs = next_runs;
    alpha = next_alpha;
    x = count;

    for (;;)
    {
        int n = runs[0];
        SkASSERT(n > 0);

        if (x < n)
        {
            alpha[x] = alpha[0];
            runs[0] = SkToS16(x);
            runs[x] = SkToS16(n - x);
            break;
        }
        x -= n;
        if (x <= 0)
            break;

        runs += n;
        alpha += n;
    }
}
Exemplo n.º 5
0
void SkTime::GetDateTime(DateTime* dt)
{
    if (dt)
    {
        SYSTEMTIME      st;
        TIME_ZONE_INFORMATION timeZoneInfo;
        int tz_bias;
        GetLocalTime(&st);
        // https://gist.github.com/wrl/8924636
        switch (GetTimeZoneInformation(&timeZoneInfo)) {
            case TIME_ZONE_ID_STANDARD:
                tz_bias = -timeZoneInfo.Bias - timeZoneInfo.StandardBias;
                break;
            case TIME_ZONE_ID_DAYLIGHT:
                tz_bias = -timeZoneInfo.Bias - timeZoneInfo.DaylightBias;
                break;
            default:
                tz_bias = -timeZoneInfo.Bias;
                break;
        }
        dt->fTimeZoneMinutes = SkToS16(tz_bias);
        dt->fYear       = st.wYear;
        dt->fMonth      = SkToU8(st.wMonth);
        dt->fDayOfWeek  = SkToU8(st.wDayOfWeek);
        dt->fDay        = SkToU8(st.wDay);
        dt->fHour       = SkToU8(st.wHour);
        dt->fMinute     = SkToU8(st.wMinute);
        dt->fSecond     = SkToU8(st.wSecond);
    }
}
Exemplo n.º 6
0
void SkScalerContext_CairoFT::generateMetrics(SkGlyph* glyph)
{
    SkASSERT(fScaledFont != NULL);
    cairo_text_extents_t extents;
    cairo_glyph_t cairoGlyph = { glyph->getGlyphID(), 0.0, 0.0 };
    cairo_scaled_font_glyph_extents(fScaledFont, &cairoGlyph, 1, &extents);

    glyph->fAdvanceX = SkDoubleToFixed(extents.x_advance);
    glyph->fAdvanceY = SkDoubleToFixed(extents.y_advance);
    glyph->fWidth = SkToU16(SkScalarCeilToInt(extents.width));
    glyph->fHeight = SkToU16(SkScalarCeilToInt(extents.height));
    glyph->fLeft = SkToS16(SkScalarCeilToInt(extents.x_bearing));
    glyph->fTop = SkToS16(SkScalarCeilToInt(extents.y_bearing));
    glyph->fLsbDelta = 0;
    glyph->fRsbDelta = 0;
}
Exemplo n.º 7
0
const SkAdvancedTypefaceMetrics* SkPDFFont::GetMetrics(SkTypeface* typeface,
                                                       SkPDFCanon* canon) {
    SkASSERT(typeface);
    SkFontID id = typeface->uniqueID();
    if (std::unique_ptr<SkAdvancedTypefaceMetrics>* ptr = canon->fTypefaceMetrics.find(id)) {
        return ptr->get();  // canon retains ownership.
    }
    int count = typeface->countGlyphs();
    if (count <= 0 || count > 1 + SK_MaxU16) {
        // Cache nullptr to skip this check.  Use SkSafeUnref().
        canon->fTypefaceMetrics.set(id, nullptr);
        return nullptr;
    }
    std::unique_ptr<SkAdvancedTypefaceMetrics> metrics = typeface->getAdvancedMetrics();
    if (!metrics) {
        metrics = skstd::make_unique<SkAdvancedTypefaceMetrics>();
    }

    if (0 == metrics->fStemV || 0 == metrics->fCapHeight) {
        SkPaint tmpPaint;
        tmpPaint.setHinting(SkPaint::kNo_Hinting);
        tmpPaint.setTypeface(sk_ref_sp(typeface));
        tmpPaint.setTextSize(1000);  // glyph coordinate system
        if (0 == metrics->fStemV) {
            // Figure out a good guess for StemV - Min width of i, I, !, 1.
            // This probably isn't very good with an italic font.
            int16_t stemV = SHRT_MAX;
            for (char c : {'i', 'I', '!', '1'}) {
                SkRect bounds;
                tmpPaint.measureText(&c, 1, &bounds);
                stemV = SkTMin(stemV, SkToS16(SkScalarRoundToInt(bounds.width())));
            }
            metrics->fStemV = stemV;
        }
        if (0 == metrics->fCapHeight) {
            // Figure out a good guess for CapHeight: average the height of M and X.
            SkScalar capHeight = 0;
            for (char c : {'M', 'X'}) {
                SkRect bounds;
                tmpPaint.measureText(&c, 1, &bounds);
                capHeight += bounds.height();
            }
            metrics->fCapHeight = SkToS16(SkScalarRoundToInt(capHeight / 2));
        }
    }
    return canon->fTypefaceMetrics.set(id, std::move(metrics))->get();
}
Exemplo n.º 8
0
void SkAlphaRuns::reset(int width)
{
    SkASSERT(width > 0);

    fRuns[0] = SkToS16(width);
    fRuns[width] = 0;
    fAlpha[0] = 0;

    SkDEBUGCODE(fWidth = width;)
Exemplo n.º 9
0
static void generate_bitmap_cache_id(const SkBitmap& bitmap, GrCacheID* id) {
    // Our id includes the offset, width, and height so that bitmaps created by extractSubset()
    // are unique.
    uint32_t genID = bitmap.getGenerationID();
    SkIPoint origin = bitmap.pixelRefOrigin();
    int16_t width = SkToS16(bitmap.width());
    int16_t height = SkToS16(bitmap.height());

    GrCacheID::Key key;
    memcpy(key.fData8 +  0, &genID,     4);
    memcpy(key.fData8 +  4, &origin.fX, 4);
    memcpy(key.fData8 +  8, &origin.fY, 4);
    memcpy(key.fData8 + 12, &width,     2);
    memcpy(key.fData8 + 14, &height,    2);
    static const size_t kKeyDataSize = 16;
    memset(key.fData8 + kKeyDataSize, 0, sizeof(key) - kKeyDataSize);
    GR_STATIC_ASSERT(sizeof(key) >= kKeyDataSize);
    static const GrCacheID::Domain gBitmapTextureDomain = GrCacheID::GenerateDomain();
    id->reset(gBitmapTextureDomain, key);
}
Exemplo n.º 10
0
void SkAlphaRuns::reset(int width) {
    SkASSERT(width > 0);

#ifdef SK_DEBUG
    sk_memset16((uint16_t*)fRuns, (uint16_t)(-42), width);
#endif
    fRuns[0] = SkToS16(width);
    fRuns[width] = 0;
    fAlpha[0] = 0;

    SkDEBUGCODE(fWidth = width;)
Exemplo n.º 11
0
void SkInterpolatorBase::reset(int elemCount, int frameCount) {
    fFlags = 0;
    fElemCount = SkToU8(elemCount);
    fFrameCount = SkToS16(frameCount);
    fRepeat = SK_Scalar1;
    if (fStorage) {
        sk_free(fStorage);
        fStorage = NULL;
        fTimes = NULL;
        SkDEBUGCODE(fTimesArray = NULL);
    }
}
Exemplo n.º 12
0
void SkTime::GetDateTime(DateTime* dt)
{
    if (dt)
    {
        tzset();  // initialize timezone variable;
        time_t m_time;
        time(&m_time);
        struct tm* tstruct;
        tstruct = localtime(&m_time);
        int offset = tstruct->tm_isdst == 1 ? 60 : 0;

        // http://pubs.opengroup.org/onlinepubs/009695399/basedefs/time.h.html
        dt->fTimeZoneMinutes = SkToS16(offset - timezone / 60);
        dt->fYear       = tstruct->tm_year + 1900;
        dt->fMonth      = SkToU8(tstruct->tm_mon + 1);
        dt->fDayOfWeek  = SkToU8(tstruct->tm_wday);
        dt->fDay        = SkToU8(tstruct->tm_mday);
        dt->fHour       = SkToU8(tstruct->tm_hour);
        dt->fMinute     = SkToU8(tstruct->tm_min);
        dt->fSecond     = SkToU8(tstruct->tm_sec);
    }
}
Exemplo n.º 13
0
SkAdvancedTypefaceMetrics* DWriteFontTypeface::onGetAdvancedTypefaceMetrics(
        PerGlyphInfo perGlyphInfo,
        const uint32_t* glyphIDs,
        uint32_t glyphIDsCount) const {

    SkAdvancedTypefaceMetrics* info = nullptr;

    HRESULT hr = S_OK;

    const unsigned glyphCount = fDWriteFontFace->GetGlyphCount();

    DWRITE_FONT_METRICS dwfm;
    fDWriteFontFace->GetMetrics(&dwfm);

    info = new SkAdvancedTypefaceMetrics;
    info->fEmSize = dwfm.designUnitsPerEm;
    info->fLastGlyphID = SkToU16(glyphCount - 1);

    info->fAscent = SkToS16(dwfm.ascent);
    info->fDescent = SkToS16(dwfm.descent);
    info->fCapHeight = SkToS16(dwfm.capHeight);

    // SkAdvancedTypefaceMetrics::fFontName is in theory supposed to be
    // the PostScript name of the font. However, due to the way it is currently
    // used, it must actually be a family name.
    SkTScopedComPtr<IDWriteLocalizedStrings> familyNames;
    hr = fDWriteFontFamily->GetFamilyNames(&familyNames);

    UINT32 familyNameLen;
    hr = familyNames->GetStringLength(0, &familyNameLen);

    SkSMallocWCHAR familyName(familyNameLen+1);
    hr = familyNames->GetString(0, familyName.get(), familyNameLen+1);

    hr = sk_wchar_to_skstring(familyName.get(), familyNameLen, &info->fFontName);

    if (perGlyphInfo & kToUnicode_PerGlyphInfo) {
        populate_glyph_to_unicode(fDWriteFontFace.get(), glyphCount, &(info->fGlyphToUnicode));
    }

    DWRITE_FONT_FACE_TYPE fontType = fDWriteFontFace->GetType();
    if (fontType != DWRITE_FONT_FACE_TYPE_TRUETYPE &&
        fontType != DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION)
    {
        return info;
    }

    // Simulated fonts aren't really TrueType fonts.
    if (fDWriteFontFace->GetSimulations() == DWRITE_FONT_SIMULATIONS_NONE) {
        info->fType = SkAdvancedTypefaceMetrics::kTrueType_Font;
    }

    AutoTDWriteTable<SkOTTableHead> headTable(fDWriteFontFace.get());
    AutoTDWriteTable<SkOTTablePostScript> postTable(fDWriteFontFace.get());
    AutoTDWriteTable<SkOTTableHorizontalHeader> hheaTable(fDWriteFontFace.get());
    AutoTDWriteTable<SkOTTableOS2> os2Table(fDWriteFontFace.get());
    if (!headTable.fExists || !postTable.fExists || !hheaTable.fExists || !os2Table.fExists) {
        return info;
    }

    //There exist CJK fonts which set the IsFixedPitch and Monospace bits,
    //but have full width, latin half-width, and half-width kana.
    bool fixedWidth = (postTable->isFixedPitch &&
                      (1 == SkEndian_SwapBE16(hheaTable->numberOfHMetrics)));
    //Monospace
    if (fixedWidth) {
        info->fStyle |= SkAdvancedTypefaceMetrics::kFixedPitch_Style;
    }
    //Italic
    if (os2Table->version.v0.fsSelection.field.Italic) {
        info->fStyle |= SkAdvancedTypefaceMetrics::kItalic_Style;
    }
    //Serif
    using SerifStyle = SkPanose::Data::TextAndDisplay::SerifStyle;
    SerifStyle serifStyle = os2Table->version.v0.panose.data.textAndDisplay.bSerifStyle;
    if (SkPanose::FamilyType::TextAndDisplay == os2Table->version.v0.panose.bFamilyType) {
        if (SerifStyle::Cove == serifStyle ||
            SerifStyle::ObtuseCove == serifStyle ||
            SerifStyle::SquareCove == serifStyle ||
            SerifStyle::ObtuseSquareCove == serifStyle ||
            SerifStyle::Square == serifStyle ||
            SerifStyle::Thin == serifStyle ||
            SerifStyle::Bone == serifStyle ||
            SerifStyle::Exaggerated == serifStyle ||
            SerifStyle::Triangle == serifStyle)
        {
            info->fStyle |= SkAdvancedTypefaceMetrics::kSerif_Style;
        }
    //Script
    } else if (SkPanose::FamilyType::Script == os2Table->version.v0.panose.bFamilyType) {
        info->fStyle |= SkAdvancedTypefaceMetrics::kScript_Style;
    }

    info->fItalicAngle = SkEndian_SwapBE32(postTable->italicAngle) >> 16;

    info->fBBox = SkIRect::MakeLTRB((int32_t)SkEndian_SwapBE16((uint16_t)headTable->xMin),
                                    (int32_t)SkEndian_SwapBE16((uint16_t)headTable->yMax),
                                    (int32_t)SkEndian_SwapBE16((uint16_t)headTable->xMax),
                                    (int32_t)SkEndian_SwapBE16((uint16_t)headTable->yMin));
    return info;
}
Exemplo n.º 14
0
// TODO(egouriou): Take advantage of periods in the convolution.
// Practical resizing filters are periodic outside of the border area.
// For Lanczos, a scaling by a (reduced) factor of p/q (q pixels in the
// source become p pixels in the destination) will have a period of p.
// A nice consequence is a period of 1 when downscaling by an integral
// factor. Downscaling from typical display resolutions is also bound
// to produce interesting periods as those are chosen to have multiple
// small factors.
// Small periods reduce computational load and improve cache usage if
// the coefficients can be shared. For periods of 1 we can consider
// loading the factors only once outside the borders.
void SkResizeFilter::computeFilters(int srcSize,
                                  float destSubsetLo, float destSubsetSize,
                                  float scale,
                                  SkConvolutionFilter1D* output,
                                  const SkConvolutionProcs& convolveProcs) {
  float destSubsetHi = destSubsetLo + destSubsetSize;  // [lo, hi)

  // When we're doing a magnification, the scale will be larger than one. This
  // means the destination pixels are much smaller than the source pixels, and
  // that the range covered by the filter won't necessarily cover any source
  // pixel boundaries. Therefore, we use these clamped values (max of 1) for
  // some computations.
  float clampedScale = SkTMin(1.0f, scale);

  // This is how many source pixels from the center we need to count
  // to support the filtering function.
  float srcSupport = fBitmapFilter->width() / clampedScale;

  float invScale = 1.0f / scale;

  SkSTArray<64, float, true> filterValuesArray;
  SkSTArray<64, SkConvolutionFilter1D::ConvolutionFixed, true> fixedFilterValuesArray;

  // Loop over all pixels in the output range. We will generate one set of
  // filter values for each one. Those values will tell us how to blend the
  // source pixels to compute the destination pixel.

  // This is the pixel in the source directly under the pixel in the dest.
  // Note that we base computations on the "center" of the pixels. To see
  // why, observe that the destination pixel at coordinates (0, 0) in a 5.0x
  // downscale should "cover" the pixels around the pixel with *its center*
  // at coordinates (2.5, 2.5) in the source, not those around (0, 0).
  // Hence we need to scale coordinates (0.5, 0.5), not (0, 0).
  destSubsetLo = SkScalarFloorToScalar(destSubsetLo);
  destSubsetHi = SkScalarCeilToScalar(destSubsetHi);
  float srcPixel = (destSubsetLo + 0.5f) * invScale;
  int destLimit = SkScalarTruncToInt(destSubsetHi - destSubsetLo);
  output->reserveAdditional(destLimit, SkScalarCeilToInt(destLimit * srcSupport * 2));
  for (int destI = 0; destI < destLimit; srcPixel += invScale, destI++)
  {
    // Compute the (inclusive) range of source pixels the filter covers.
    float srcBegin = SkTMax(0.f, SkScalarFloorToScalar(srcPixel - srcSupport));
    float srcEnd = SkTMin(srcSize - 1.f, SkScalarCeilToScalar(srcPixel + srcSupport));

    // Compute the unnormalized filter value at each location of the source
    // it covers.

    // Sum of the filter values for normalizing.
    // Distance from the center of the filter, this is the filter coordinate
    // in source space. We also need to consider the center of the pixel
    // when comparing distance against 'srcPixel'. In the 5x downscale
    // example used above the distance from the center of the filter to
    // the pixel with coordinates (2, 2) should be 0, because its center
    // is at (2.5, 2.5).
    float destFilterDist = (srcBegin + 0.5f - srcPixel) * clampedScale;
    int filterCount = SkScalarTruncToInt(srcEnd - srcBegin) + 1;
    if (filterCount <= 0) {
        // true when srcSize is equal to srcPixel - srcSupport; this may be a bug
        return;
    }
    filterValuesArray.reset(filterCount);
    float filterSum = fBitmapFilter->evaluate_n(destFilterDist, clampedScale, filterCount,
                                                filterValuesArray.begin());

    // The filter must be normalized so that we don't affect the brightness of
    // the image. Convert to normalized fixed point.
    int fixedSum = 0;
    fixedFilterValuesArray.reset(filterCount);
    const float* filterValues = filterValuesArray.begin();
    SkConvolutionFilter1D::ConvolutionFixed* fixedFilterValues = fixedFilterValuesArray.begin();
    float invFilterSum = 1 / filterSum;
    for (int fixedI = 0; fixedI < filterCount; fixedI++) {
      int curFixed = SkConvolutionFilter1D::FloatToFixed(filterValues[fixedI] * invFilterSum);
      fixedSum += curFixed;
      fixedFilterValues[fixedI] = SkToS16(curFixed);
    }
    SkASSERT(fixedSum <= 0x7FFF);

    // The conversion to fixed point will leave some rounding errors, which
    // we add back in to avoid affecting the brightness of the image. We
    // arbitrarily add this to the center of the filter array (this won't always
    // be the center of the filter function since it could get clipped on the
    // edges, but it doesn't matter enough to worry about that case).
    int leftovers = SkConvolutionFilter1D::FloatToFixed(1) - fixedSum;
    fixedFilterValues[filterCount / 2] += leftovers;

    // Now it's ready to go.
    output->AddFilter(SkScalarFloorToInt(srcBegin), fixedFilterValues, filterCount);
  }

  if (convolveProcs.fApplySIMDPadding) {
      convolveProcs.fApplySIMDPadding(output);
  }
}
Exemplo n.º 15
0
void SkPDFType0Font::getFontSubset(SkPDFCanon* canon) {
    const SkAdvancedTypefaceMetrics* metricsPtr =
        SkPDFFont::GetMetrics(this->typeface(), canon);
    SkASSERT(metricsPtr);
    if (!metricsPtr) { return; }
    const SkAdvancedTypefaceMetrics& metrics = *metricsPtr;
    SkASSERT(can_embed(metrics));
    SkAdvancedTypefaceMetrics::FontType type = this->getType();
    SkTypeface* face = this->typeface();
    SkASSERT(face);

    auto descriptor = sk_make_sp<SkPDFDict>("FontDescriptor");
    uint16_t emSize = SkToU16(this->typeface()->getUnitsPerEm());
    add_common_font_descriptor_entries(descriptor.get(), metrics, emSize , 0);

    int ttcIndex;
    std::unique_ptr<SkStreamAsset> fontAsset(face->openStream(&ttcIndex));
    size_t fontSize = fontAsset ? fontAsset->getLength() : 0;
    if (0 == fontSize) {
        SkDebugf("Error: (SkTypeface)(%p)::openStream() returned "
                 "empty stream (%p) when identified as kType1CID_Font "
                 "or kTrueType_Font.\n", face, fontAsset.get());
    } else {
        switch (type) {
            case SkAdvancedTypefaceMetrics::kTrueType_Font: {
                #ifdef SK_PDF_USE_SFNTLY
                if (!SkToBool(metrics.fFlags &
                              SkAdvancedTypefaceMetrics::kNotSubsettable_FontFlag)) {
                    sk_sp<SkPDFStream> subsetStream = get_subset_font_stream(
                            std::move(fontAsset), this->glyphUsage(),
                            metrics.fFontName.c_str(), ttcIndex);
                    if (subsetStream) {
                        descriptor->insertObjRef("FontFile2", std::move(subsetStream));
                        break;
                    }
                    // If subsetting fails, fall back to original font data.
                    fontAsset.reset(face->openStream(&ttcIndex));
                    SkASSERT(fontAsset);
                    SkASSERT(fontAsset->getLength() == fontSize);
                    if (!fontAsset || fontAsset->getLength() == 0) { break; }
                }
                #endif  // SK_PDF_USE_SFNTLY
                auto fontStream = sk_make_sp<SkPDFSharedStream>(std::move(fontAsset));
                fontStream->dict()->insertInt("Length1", fontSize);
                descriptor->insertObjRef("FontFile2", std::move(fontStream));
                break;
            }
            case SkAdvancedTypefaceMetrics::kType1CID_Font: {
                auto fontStream = sk_make_sp<SkPDFSharedStream>(std::move(fontAsset));
                fontStream->dict()->insertName("Subtype", "CIDFontType0C");
                descriptor->insertObjRef("FontFile3", std::move(fontStream));
                break;
            }
            default:
                SkASSERT(false);
        }
    }

    auto newCIDFont = sk_make_sp<SkPDFDict>("Font");
    newCIDFont->insertObjRef("FontDescriptor", std::move(descriptor));
    newCIDFont->insertName("BaseFont", metrics.fPostScriptName);

    switch (type) {
        case SkAdvancedTypefaceMetrics::kType1CID_Font:
            newCIDFont->insertName("Subtype", "CIDFontType0");
            break;
        case SkAdvancedTypefaceMetrics::kTrueType_Font:
            newCIDFont->insertName("Subtype", "CIDFontType2");
            newCIDFont->insertName("CIDToGIDMap", "Identity");
            break;
        default:
            SkASSERT(false);
    }
    auto sysInfo = sk_make_sp<SkPDFDict>();
    sysInfo->insertString("Registry", "Adobe");
    sysInfo->insertString("Ordering", "Identity");
    sysInfo->insertInt("Supplement", 0);
    newCIDFont->insertObject("CIDSystemInfo", std::move(sysInfo));

    int16_t defaultWidth = 0;
    {
        int emSize;
        auto glyphCache = SkPDFFont::MakeVectorCache(face, &emSize);
        sk_sp<SkPDFArray> widths = SkPDFMakeCIDGlyphWidthsArray(
                glyphCache.get(), &this->glyphUsage(), SkToS16(emSize), &defaultWidth);
        if (widths && widths->size() > 0) {
            newCIDFont->insertObject("W", std::move(widths));
        }
        newCIDFont->insertScalar(
                "DW", scaleFromFontUnits(defaultWidth, SkToS16(emSize)));
    }

    ////////////////////////////////////////////////////////////////////////////

    this->insertName("Subtype", "Type0");
    this->insertName("BaseFont", metrics.fPostScriptName);
    this->insertName("Encoding", "Identity-H");
    auto descendantFonts = sk_make_sp<SkPDFArray>();
    descendantFonts->appendObjRef(std::move(newCIDFont));
    this->insertObject("DescendantFonts", std::move(descendantFonts));

    if (metrics.fGlyphToUnicode.count() > 0) {
        this->insertObjRef("ToUnicode",
                           SkPDFMakeToUnicodeCmap(metrics.fGlyphToUnicode,
                                                  &this->glyphUsage(),
                                                  multiByteGlyphs(),
                                                  firstGlyphID(),
                                                  lastGlyphID()));
    }
    SkDEBUGCODE(fPopulated = true);
    return;
}
Exemplo n.º 16
0
void SkScalerContext_CairoFT::generateMetrics(SkGlyph* glyph)
{
    SkASSERT(fScaledFont != nullptr);

    glyph->zeroMetrics();

    CairoLockedFTFace faceLock(fScaledFont);
    FT_Face face = faceLock.getFace();

    FT_Error err = FT_Load_Glyph( face, glyph->getGlyphID(), fLoadGlyphFlags );
    if (err != 0) {
        return;
    }

    prepareGlyph(face->glyph);

    switch (face->glyph->format) {
    case FT_GLYPH_FORMAT_OUTLINE:
        if (!face->glyph->outline.n_contours) {
            break;
        }

        FT_BBox bbox;
        FT_Outline_Get_CBox(&face->glyph->outline, &bbox);
        bbox.xMin &= ~63;
        bbox.yMin &= ~63;
        bbox.xMax = (bbox.xMax + 63) & ~63;
        bbox.yMax = (bbox.yMax + 63) & ~63;
        glyph->fWidth  = SkToU16(SkFDot6Floor(bbox.xMax - bbox.xMin));
        glyph->fHeight = SkToU16(SkFDot6Floor(bbox.yMax - bbox.yMin));
        glyph->fTop    = -SkToS16(SkFDot6Floor(bbox.yMax));
        glyph->fLeft   = SkToS16(SkFDot6Floor(bbox.xMin));

        if (isLCD(fRec) &&
            gSetLcdFilter &&
            (fLcdFilter == FT_LCD_FILTER_DEFAULT ||
             fLcdFilter == FT_LCD_FILTER_LIGHT)) {
            if (fRec.fFlags & kLCD_Vertical_Flag) {
                glyph->fTop -= 1;
                glyph->fHeight += 2;
            } else {
                glyph->fLeft -= 1;
                glyph->fWidth += 2;
            }
        }
        break;
    case FT_GLYPH_FORMAT_BITMAP:
#ifdef FT_LOAD_COLOR
        if (face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_BGRA) {
            glyph->fMaskFormat = SkMask::kARGB32_Format;
        }
#endif

        if (isLCD(fRec)) {
            fRec.fMaskFormat = SkMask::kA8_Format;
        }

        if (fHaveShape) {
            // Apply the shape matrix to the glyph's bounding box.
            SkMatrix matrix;
            fRec.getSingleMatrix(&matrix);
            matrix.preScale(SkScalarInvert(fScaleX), SkScalarInvert(fScaleY));
            SkRect srcRect = SkRect::MakeXYWH(
                SkIntToScalar(face->glyph->bitmap_left),
                -SkIntToScalar(face->glyph->bitmap_top),
                SkIntToScalar(face->glyph->bitmap.width),
                SkIntToScalar(face->glyph->bitmap.rows));
            SkRect destRect;
            matrix.mapRect(&destRect, srcRect);
            SkIRect glyphRect = destRect.roundOut();
            glyph->fWidth  = SkToU16(glyphRect.width());
            glyph->fHeight = SkToU16(glyphRect.height());
            glyph->fTop    = SkToS16(SkScalarRoundToInt(destRect.fTop));
            glyph->fLeft   = SkToS16(SkScalarRoundToInt(destRect.fLeft));
        } else {
            glyph->fWidth  = SkToU16(face->glyph->bitmap.width);
            glyph->fHeight = SkToU16(face->glyph->bitmap.rows);
            glyph->fTop    = -SkToS16(face->glyph->bitmap_top);
            glyph->fLeft   = SkToS16(face->glyph->bitmap_left);
        }
        break;
    default:
        SkDEBUGFAIL("unknown glyph format");
        return;
    }

    if (fRec.fFlags & SkScalerContext::kVertical_Flag) {
        glyph->fAdvanceX = -SkFDot6ToFloat(face->glyph->advance.x);
        glyph->fAdvanceY = SkFDot6ToFloat(face->glyph->advance.y);
    } else {
        glyph->fAdvanceX = SkFDot6ToFloat(face->glyph->advance.x);
        glyph->fAdvanceY = -SkFDot6ToFloat(face->glyph->advance.y);
    }
}
Exemplo n.º 17
0
SkAdvancedTypefaceMetrics* DWriteFontTypeface::onGetAdvancedTypefaceMetrics(
        PerGlyphInfo perGlyphInfo,
        const uint32_t* glyphIDs,
        uint32_t glyphIDsCount) const {

    SkAdvancedTypefaceMetrics* info = nullptr;

    HRESULT hr = S_OK;

    const unsigned glyphCount = fDWriteFontFace->GetGlyphCount();

    DWRITE_FONT_METRICS dwfm;
    fDWriteFontFace->GetMetrics(&dwfm);

    info = new SkAdvancedTypefaceMetrics;
    info->fEmSize = dwfm.designUnitsPerEm;
    info->fLastGlyphID = SkToU16(glyphCount - 1);

    // SkAdvancedTypefaceMetrics::fFontName is in theory supposed to be
    // the PostScript name of the font. However, due to the way it is currently
    // used, it must actually be a family name.
    SkTScopedComPtr<IDWriteLocalizedStrings> familyNames;
    hr = fDWriteFontFamily->GetFamilyNames(&familyNames);

    UINT32 familyNameLen;
    hr = familyNames->GetStringLength(0, &familyNameLen);

    SkSMallocWCHAR familyName(familyNameLen+1);
    hr = familyNames->GetString(0, familyName.get(), familyNameLen+1);

    hr = sk_wchar_to_skstring(familyName.get(), familyNameLen, &info->fFontName);

    if (perGlyphInfo & kToUnicode_PerGlyphInfo) {
        populate_glyph_to_unicode(fDWriteFontFace.get(), glyphCount, &(info->fGlyphToUnicode));
    }

    DWRITE_FONT_FACE_TYPE fontType = fDWriteFontFace->GetType();
    if (fontType == DWRITE_FONT_FACE_TYPE_TRUETYPE ||
        fontType == DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION) {
        info->fType = SkAdvancedTypefaceMetrics::kTrueType_Font;
    } else {
        info->fAscent = dwfm.ascent;
        info->fDescent = dwfm.descent;
        info->fCapHeight = dwfm.capHeight;
        return info;
    }

    AutoTDWriteTable<SkOTTableHead> headTable(fDWriteFontFace.get());
    AutoTDWriteTable<SkOTTablePostScript> postTable(fDWriteFontFace.get());
    AutoTDWriteTable<SkOTTableHorizontalHeader> hheaTable(fDWriteFontFace.get());
    AutoTDWriteTable<SkOTTableOS2> os2Table(fDWriteFontFace.get());
    if (!headTable.fExists || !postTable.fExists || !hheaTable.fExists || !os2Table.fExists) {
        info->fAscent = dwfm.ascent;
        info->fDescent = dwfm.descent;
        info->fCapHeight = dwfm.capHeight;
        return info;
    }

    //There exist CJK fonts which set the IsFixedPitch and Monospace bits,
    //but have full width, latin half-width, and half-width kana.
    bool fixedWidth = (postTable->isFixedPitch &&
                      (1 == SkEndian_SwapBE16(hheaTable->numberOfHMetrics)));
    //Monospace
    if (fixedWidth) {
        info->fStyle |= SkAdvancedTypefaceMetrics::kFixedPitch_Style;
    }
    //Italic
    if (os2Table->version.v0.fsSelection.field.Italic) {
        info->fStyle |= SkAdvancedTypefaceMetrics::kItalic_Style;
    }
    //Script
    if (SkPanose::FamilyType::Script == os2Table->version.v0.panose.bFamilyType.value) {
        info->fStyle |= SkAdvancedTypefaceMetrics::kScript_Style;
    //Serif
    } else if (SkPanose::FamilyType::TextAndDisplay == os2Table->version.v0.panose.bFamilyType.value &&
               SkPanose::Data::TextAndDisplay::SerifStyle::Triangle <= os2Table->version.v0.panose.data.textAndDisplay.bSerifStyle.value &&
               SkPanose::Data::TextAndDisplay::SerifStyle::NoFit != os2Table->version.v0.panose.data.textAndDisplay.bSerifStyle.value) {
        info->fStyle |= SkAdvancedTypefaceMetrics::kSerif_Style;
    }

    info->fItalicAngle = SkEndian_SwapBE32(postTable->italicAngle) >> 16;

    info->fAscent = SkToS16(dwfm.ascent);
    info->fDescent = SkToS16(dwfm.descent);
    info->fCapHeight = SkToS16(dwfm.capHeight);

    info->fBBox = SkIRect::MakeLTRB((int32_t)SkEndian_SwapBE16((uint16_t)headTable->xMin),
                                    (int32_t)SkEndian_SwapBE16((uint16_t)headTable->yMax),
                                    (int32_t)SkEndian_SwapBE16((uint16_t)headTable->xMax),
                                    (int32_t)SkEndian_SwapBE16((uint16_t)headTable->yMin));

    //TODO: is this even desired? It seems PDF only wants this value for Type1
    //fonts, and we only get here for TrueType fonts.
    info->fStemV = 0;
    /*
    // Figure out a good guess for StemV - Min width of i, I, !, 1.
    // This probably isn't very good with an italic font.
    int16_t min_width = SHRT_MAX;
    info->fStemV = 0;
    char stem_chars[] = {'i', 'I', '!', '1'};
    for (size_t i = 0; i < SK_ARRAY_COUNT(stem_chars); i++) {
        ABC abcWidths;
        if (GetCharABCWidths(hdc, stem_chars[i], stem_chars[i], &abcWidths)) {
            int16_t width = abcWidths.abcB;
            if (width > 0 && width < min_width) {
                min_width = width;
                info->fStemV = min_width;
            }
        }
    }
    */

    if (perGlyphInfo & kHAdvance_PerGlyphInfo) {
        if (fixedWidth) {
            SkAdvancedTypefaceMetrics::WidthRange range(0);
            int16_t advance;
            getWidthAdvance(fDWriteFontFace.get(), 1, &advance);
            range.fAdvance.append(1, &advance);
            SkAdvancedTypefaceMetrics::FinishRange(
                    &range, 0, SkAdvancedTypefaceMetrics::WidthRange::kDefault);
            info->fGlyphWidths.emplace_back(std::move(range));
        } else {
            IDWriteFontFace* borrowedFontFace = fDWriteFontFace.get();
            info->setGlyphWidths(
                glyphCount,
                glyphIDs,
                glyphIDsCount,
                SkAdvancedTypefaceMetrics::GetAdvance([borrowedFontFace](int gId, int16_t* data) {
                    return getWidthAdvance(borrowedFontFace, gId, data);
                })
            );
        }
    }

    return info;
}