// IDWriteTextRenderer methods virtual HRESULT STDMETHODCALLTYPE DrawGlyphRun( void* clientDrawingContext, FLOAT baselineOriginX, FLOAT baselineOriginY, DWRITE_MEASURING_MODE measuringMode, DWRITE_GLYPH_RUN const* glyphRun, DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription, IUnknown* clientDrawingEffect) override { SkTScopedComPtr<IDWriteFont> font; HRM(fOuter->fFontCollection->GetFontFromFontFace(glyphRun->fontFace, &font), "Could not get font from font face."); // It is possible that the font passed does not actually have the requested character, // due to no font being found and getting the fallback font. // Check that the font actually contains the requested character. BOOL exists; HRM(font->HasCharacter(fCharacter, &exists), "Could not find character."); if (exists) { SkTScopedComPtr<IDWriteFontFamily> fontFamily; HRM(font->GetFontFamily(&fontFamily), "Could not get family."); fResolvedTypeface = fOuter->createTypefaceFromDWriteFont(glyphRun->fontFace, font.get(), fontFamily.get()); } return S_OK; }
SkTypeface* SkFontStyleSet_DirectWrite::matchStyle(const SkFontStyle& pattern) { DWRITE_FONT_STYLE slant; switch (pattern.slant()) { case SkFontStyle::kUpright_Slant: slant = DWRITE_FONT_STYLE_NORMAL; break; case SkFontStyle::kItalic_Slant: slant = DWRITE_FONT_STYLE_ITALIC; break; default: SkASSERT(false); } DWRITE_FONT_WEIGHT weight = (DWRITE_FONT_WEIGHT)pattern.weight(); DWRITE_FONT_STRETCH width = (DWRITE_FONT_STRETCH)pattern.width(); SkTScopedComPtr<IDWriteFont> font; // TODO: perhaps use GetMatchingFonts and get the least simulated? HRNM(fFontFamily->GetFirstMatchingFont(weight, width, slant, &font), "Could not match font in family."); SkTScopedComPtr<IDWriteFontFace> fontFace; HRNM(font->CreateFontFace(&fontFace), "Could not create font face."); return fFontMgr->createTypefaceFromDWriteFont(fontFace.get(), font.get(), fFontFamily.get()); }
SkTypeface* SkFontMgr_DirectWrite::onLegacyCreateTypeface(const char familyName[], SkFontStyle style) const { SkTScopedComPtr<IDWriteFontFamily> fontFamily; if (familyName) { SkSMallocWCHAR wideFamilyName; if (SUCCEEDED(sk_cstring_to_wchar(familyName, &wideFamilyName))) { this->getByFamilyName(wideFamilyName, &fontFamily); } } if (nullptr == fontFamily.get()) { // No family with given name, try default. this->getDefaultFontFamily(&fontFamily); } if (nullptr == fontFamily.get()) { // Could not obtain the default font. HRNM(fFontCollection->GetFontFamily(0, &fontFamily), "Could not get default-default font family."); } SkTScopedComPtr<IDWriteFont> font; DWriteStyle dwStyle(style); HRNM(fontFamily->GetFirstMatchingFont(dwStyle.fWeight, dwStyle.fWidth, dwStyle.fSlant, &font), "Could not get matching font."); SkTScopedComPtr<IDWriteFontFace> fontFace; HRNM(font->CreateFontFace(&fontFace), "Could not create font face."); return this->createTypefaceFromDWriteFont(fontFace.get(), font.get(), fontFamily.get()); }
HRESULT StreamFontFileEnumerator::GetCurrentFontFile(IDWriteFontFile** fontFile) { if (fCurrentFile.get() == nullptr) { *fontFile = nullptr; return E_FAIL; } *fontFile = SkRefComPtr(fCurrentFile.get()); return S_OK; }
SkTypeface* SkFontStyleSet_DirectWrite::createTypeface(int index) { SkTScopedComPtr<IDWriteFont> font; HRNM(fFontFamily->GetFont(index, &font), "Could not get font."); SkTScopedComPtr<IDWriteFontFace> fontFace; HRNM(font->CreateFontFace(&fontFace), "Could not create font face."); return fFontMgr->createTypefaceFromDWriteFont(fontFace.get(), font.get(), fFontFamily.get()); }
static HRESULT are_same(IUnknown* a, IUnknown* b, bool& same) { SkTScopedComPtr<IUnknown> iunkA; HRM(a->QueryInterface(&iunkA), "Failed to QI<IUnknown> for a."); SkTScopedComPtr<IUnknown> iunkB; HRM(b->QueryInterface(&iunkB), "Failed to QI<IUnknown> for b."); same = (iunkA.get() == iunkB.get()); return S_OK; }
SkTypeface* SkFontStyleSet_DirectWrite::matchStyle(const SkFontStyle& pattern) { SkTScopedComPtr<IDWriteFont> font; DWriteStyle dwStyle(pattern); // TODO: perhaps use GetMatchingFonts and get the least simulated? HRNM(fFontFamily->GetFirstMatchingFont(dwStyle.fWeight, dwStyle.fWidth, dwStyle.fSlant, &font), "Could not match font in family."); SkTScopedComPtr<IDWriteFontFace> fontFace; HRNM(font->CreateFontFace(&fontFace), "Could not create font face."); return fFontMgr->createTypefaceFromDWriteFont(fontFace.get(), font.get(), fFontFamily.get()); }
void SkFontStyleSet_DirectWrite::getStyle(int index, SkFontStyle* fs, SkString* styleName) { SkTScopedComPtr<IDWriteFont> font; HRVM(fFontFamily->GetFont(index, &font), "Could not get font."); if (fs) { *fs = get_style(font.get()); } if (styleName) { SkTScopedComPtr<IDWriteLocalizedStrings> faceNames; if (SUCCEEDED(font->GetFaceNames(&faceNames))) { sk_get_locale_string(faceNames.get(), fFontMgr->fLocaleName.get(), styleName); } } }
int FindOrAdd(IDWriteFontFileLoader* fontFileLoader, const void* refKey, UINT32 refKeySize) const { SkTScopedComPtr<IUnknown> fontFileLoaderId; HR_GENERAL(fontFileLoader->QueryInterface(&fontFileLoaderId), "Failed to re-convert to IDWriteFontFileLoader.", SkFontIdentity::kInvalidDataId); SkAutoMutexAcquire ama(fDataIdCacheMutex); int count = fDataIdCache.count(); int i; for (i = 0; i < count; ++i) { const DataId& current = fDataIdCache[i]; if (fontFileLoaderId.get() == current.fLoader && refKeySize == current.fKeySize && 0 == memcmp(refKey, current.fKey, refKeySize)) { return i; } } DataId& added = fDataIdCache.push_back(); added.fLoader = fontFileLoaderId.release(); // Ref is passed. added.fKey = sk_malloc_throw(refKeySize); memcpy(added.fKey, refKey, refKeySize); added.fKeySize = refKeySize; return i; }
SK_API SkFontMgr* SkFontMgr_New_DirectWrite(IDWriteFactory* factory) { if (NULL == factory) { factory = sk_get_dwrite_factory(); if (NULL == factory) { return NULL; } } SkTScopedComPtr<IDWriteFontCollection> sysFontCollection; HRNM(SkFontMgr_GetFontCollectionToUse(&sysFontCollection, factory), "Could not get system font collection."); WCHAR localeNameStorage[LOCALE_NAME_MAX_LENGTH]; WCHAR* localeName = NULL; int localeNameLen = 0; // Dynamically load GetUserDefaultLocaleName function, as it is not available on XP. SkGetUserDefaultLocaleNameProc getUserDefaultLocaleNameProc = NULL; HRESULT hr = SkGetGetUserDefaultLocaleNameProc(&getUserDefaultLocaleNameProc); if (NULL == getUserDefaultLocaleNameProc) { SK_TRACEHR(hr, "Could not get GetUserDefaultLocaleName."); } else { localeNameLen = getUserDefaultLocaleNameProc(localeNameStorage, LOCALE_NAME_MAX_LENGTH); if (localeNameLen) { localeName = localeNameStorage; }; } return SkNEW_ARGS(SkFontMgr_DirectWrite, (factory, sysFontCollection.get(), localeName, localeNameLen)); }
void SkFontStyleSet_DirectWrite::getStyle(int index, SkFontStyle* fs, SkString* styleName) { SkTScopedComPtr<IDWriteFont> font; HRVM(fFontFamily->GetFont(index, &font), "Could not get font."); if (fs) { SkFontStyle::Slant slant; switch (font->GetStyle()) { case DWRITE_FONT_STYLE_NORMAL: slant = SkFontStyle::kUpright_Slant; break; case DWRITE_FONT_STYLE_OBLIQUE: case DWRITE_FONT_STYLE_ITALIC: slant = SkFontStyle::kItalic_Slant; break; default: SkASSERT(false); } int weight = font->GetWeight(); int width = font->GetStretch(); *fs = SkFontStyle(weight, width, slant); } if (styleName) { SkTScopedComPtr<IDWriteLocalizedStrings> faceNames; if (SUCCEEDED(font->GetFaceNames(&faceNames))) { sk_get_locale_string(faceNames.get(), fFontMgr->fLocaleName.get(), styleName); } } }
SkStreamAsset* DWriteFontTypeface::onOpenStream(int* ttcIndex) const { *ttcIndex = fDWriteFontFace->GetIndex(); UINT32 numFiles; HRNM(fDWriteFontFace->GetFiles(&numFiles, nullptr), "Could not get number of font files."); if (numFiles != 1) { return nullptr; } SkTScopedComPtr<IDWriteFontFile> fontFile; HRNM(fDWriteFontFace->GetFiles(&numFiles, &fontFile), "Could not get font files."); const void* fontFileKey; UINT32 fontFileKeySize; HRNM(fontFile->GetReferenceKey(&fontFileKey, &fontFileKeySize), "Could not get font file reference key."); SkTScopedComPtr<IDWriteFontFileLoader> fontFileLoader; HRNM(fontFile->GetLoader(&fontFileLoader), "Could not get font file loader."); SkTScopedComPtr<IDWriteFontFileStream> fontFileStream; HRNM(fontFileLoader->CreateStreamFromKey(fontFileKey, fontFileKeySize, &fontFileStream), "Could not create font file stream."); return new SkDWriteFontFileStream(fontFileStream.get()); }
SK_API SkFontMgr* SkFontMgr_New_DirectWrite(IDWriteFactory* factory, IDWriteFontCollection* collection, IDWriteFontFallback* fallback) { if (nullptr == factory) { factory = sk_get_dwrite_factory(); if (nullptr == factory) { return nullptr; } } SkTScopedComPtr<IDWriteFontCollection> systemFontCollection; if (nullptr == collection) { HRNM(factory->GetSystemFontCollection(&systemFontCollection, FALSE), "Could not get system font collection."); collection = systemFontCollection.get(); } WCHAR localeNameStorage[LOCALE_NAME_MAX_LENGTH]; WCHAR* localeName = nullptr; int localeNameLen = 0; // Dynamically load GetUserDefaultLocaleName function, as it is not available on XP. SkGetUserDefaultLocaleNameProc getUserDefaultLocaleNameProc = nullptr; HRESULT hr = SkGetGetUserDefaultLocaleNameProc(&getUserDefaultLocaleNameProc); if (nullptr == getUserDefaultLocaleNameProc) { SK_TRACEHR(hr, "Could not get GetUserDefaultLocaleName."); } else { localeNameLen = getUserDefaultLocaleNameProc(localeNameStorage, LOCALE_NAME_MAX_LENGTH); if (localeNameLen) { localeName = localeNameStorage; }; } return new SkFontMgr_DirectWrite(factory, collection, fallback, localeName, localeNameLen); }
void SkFontMgr_DirectWrite::onGetFamilyName(int index, SkString* familyName) const { SkTScopedComPtr<IDWriteFontFamily> fontFamily; HRVM(fFontCollection->GetFontFamily(index, &fontFamily), "Could not get requested family."); SkTScopedComPtr<IDWriteLocalizedStrings> familyNames; HRVM(fontFamily->GetFamilyNames(&familyNames), "Could not get family names."); sk_get_locale_string(familyNames.get(), fLocaleName.get(), familyName); }
HRESULT StreamFontCollectionLoader::CreateEnumeratorFromKey( IDWriteFactory* factory, void const* collectionKey, UINT32 collectionKeySize, IDWriteFontFileEnumerator** fontFileEnumerator) { SkTScopedComPtr<StreamFontFileEnumerator> enumerator; HR(StreamFontFileEnumerator::Create(factory, fFontFileLoader.get(), &enumerator)); *fontFileEnumerator = enumerator.release(); return S_OK; }
void DWriteFontTypeface::onGetFontDescriptor(SkFontDescriptor* desc, bool* isLocalStream) const { // Get the family name. SkTScopedComPtr<IDWriteLocalizedStrings> familyNames; HRV(fDWriteFontFamily->GetFamilyNames(&familyNames)); SkString utf8FamilyName; sk_get_locale_string(familyNames.get(), nullptr/*fMgr->fLocaleName.get()*/, &utf8FamilyName); desc->setFamilyName(utf8FamilyName.c_str()); *isLocalStream = SkToBool(fDWriteFontFileLoader.get()); }
SkTypeface* SkFontMgr_DirectWrite::onLegacyCreateTypeface(const char familyName[], unsigned styleBits) const { SkTScopedComPtr<IDWriteFontFamily> fontFamily; if (familyName) { SkSMallocWCHAR wideFamilyName; if (SUCCEEDED(sk_cstring_to_wchar(familyName, &wideFamilyName))) { this->getByFamilyName(wideFamilyName, &fontFamily); } } if (NULL == fontFamily.get()) { // No family with given name, try default. HRNM(this->getDefaultFontFamily(&fontFamily), "Could not get default font family."); } if (NULL == fontFamily.get()) { // Could not obtain the default font. HRNM(fFontCollection->GetFontFamily(0, &fontFamily), "Could not get default-default font family."); } SkTScopedComPtr<IDWriteFont> font; DWRITE_FONT_WEIGHT weight = (styleBits & SkTypeface::kBold) ? DWRITE_FONT_WEIGHT_BOLD : DWRITE_FONT_WEIGHT_NORMAL; DWRITE_FONT_STRETCH stretch = DWRITE_FONT_STRETCH_NORMAL; DWRITE_FONT_STYLE italic = (styleBits & SkTypeface::kItalic) ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL; HRNM(fontFamily->GetFirstMatchingFont(weight, stretch, italic, &font), "Could not get matching font."); SkTScopedComPtr<IDWriteFontFace> fontFace; HRNM(font->CreateFontFace(&fontFace), "Could not create font face."); return this->createTypefaceFromDWriteFont(fontFace.get(), font.get(), fontFamily.get()); }
SkTypeface* SkFontMgr_DirectWrite::createTypefaceFromDWriteFont( IDWriteFontFace* fontFace, IDWriteFont* font, IDWriteFontFamily* fontFamily) const { SkAutoMutexAcquire ama(fTFCacheMutex); ProtoDWriteTypeface spec = { fontFace, font, fontFamily }; SkTypeface* face = fTFCache.findByProcAndRef(FindByDWriteFont, &spec); if (nullptr == face) { face = DWriteFontTypeface::Create(fFactory.get(), fontFace, font, fontFamily); if (face) { fTFCache.add(face); } } return face; }
HRESULT StreamFontFileEnumerator::MoveNext(BOOL* hasCurrentFile) { *hasCurrentFile = FALSE; if (!fHasNext) { return S_OK; } fHasNext = false; UINT32 dummy = 0; HR(fFactory->CreateCustomFontFileReference( &dummy, //cannot be nullptr sizeof(dummy), //even if this is 0 fFontFileLoader.get(), &fCurrentFile)); *hasCurrentFile = TRUE; return S_OK; }
SkImageGenerator* SkImageGeneratorWIC::NewFromEncodedWIC(SkData* data) { // Create Windows Imaging Component ImagingFactory. SkTScopedComPtr<IWICImagingFactory> imagingFactory; HRESULT hr = CoCreateInstance(CLSID_WICImagingFactory, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&imagingFactory)); if (FAILED(hr)) { return nullptr; } // Create an IStream. SkTScopedComPtr<IStream> iStream; // Note that iStream will take ownership of the new memory stream because // we set |deleteOnRelease| to true. hr = SkIStream::CreateFromSkStream(new SkMemoryStream(data), true, &iStream); if (FAILED(hr)) { return nullptr; } // Create the decoder from the stream. SkTScopedComPtr<IWICBitmapDecoder> decoder; hr = imagingFactory->CreateDecoderFromStream(iStream.get(), nullptr, WICDecodeMetadataCacheOnDemand, &decoder); if (FAILED(hr)) { return nullptr; } // Select the first frame from the decoder. SkTScopedComPtr<IWICBitmapFrameDecode> imageFrame; hr = decoder->GetFrame(0, &imageFrame); if (FAILED(hr)) { return nullptr; } // Treat the frame as an image source. SkTScopedComPtr<IWICBitmapSource> imageSource; hr = imageFrame->QueryInterface(IID_PPV_ARGS(&imageSource)); if (FAILED(hr)) { return nullptr; } // Get the size of the image. UINT width; UINT height; hr = imageSource->GetSize(&width, &height); if (FAILED(hr)) { return nullptr; } // Get the encoded pixel format. WICPixelFormatGUID format; hr = imageSource->GetPixelFormat(&format); if (FAILED(hr)) { return nullptr; } // Recommend kOpaque if the image is opaque and kPremul otherwise. // FIXME: We are stuck recommending kPremul for all indexed formats // (Ex: GUID_WICPixelFormat8bppIndexed) because we don't have // a way to check if the image has alpha. SkAlphaType alphaType = kPremul_SkAlphaType; if (GUID_WICPixelFormat16bppBGR555 == format || GUID_WICPixelFormat16bppBGR565 == format || GUID_WICPixelFormat32bppBGR101010 == format || GUID_WICPixelFormatBlackWhite == format || GUID_WICPixelFormat2bppGray == format || GUID_WICPixelFormat4bppGray == format || GUID_WICPixelFormat8bppGray == format || GUID_WICPixelFormat16bppGray == format || GUID_WICPixelFormat16bppGrayFixedPoint == format || GUID_WICPixelFormat16bppGrayHalf == format || GUID_WICPixelFormat32bppGrayFloat == format || GUID_WICPixelFormat32bppGrayFixedPoint == format || GUID_WICPixelFormat32bppRGBE == format || GUID_WICPixelFormat24bppRGB == format || GUID_WICPixelFormat24bppBGR == format || GUID_WICPixelFormat32bppBGR == format || GUID_WICPixelFormat48bppRGB == format || GUID_WICPixelFormat48bppBGR == format || GUID_WICPixelFormat48bppRGBFixedPoint == format || GUID_WICPixelFormat48bppBGRFixedPoint == format || GUID_WICPixelFormat48bppRGBHalf == format || GUID_WICPixelFormat64bppRGBFixedPoint == format || GUID_WICPixelFormat64bppRGBHalf == format || GUID_WICPixelFormat96bppRGBFixedPoint == format || GUID_WICPixelFormat128bppRGBFloat == format || GUID_WICPixelFormat128bppRGBFixedPoint == format || GUID_WICPixelFormat32bppRGB == format || GUID_WICPixelFormat64bppRGB == format || GUID_WICPixelFormat96bppRGBFloat == format || GUID_WICPixelFormat32bppCMYK == format || GUID_WICPixelFormat64bppCMYK == format || GUID_WICPixelFormat8bppY == format || GUID_WICPixelFormat8bppCb == format || GUID_WICPixelFormat8bppCr == format || GUID_WICPixelFormat16bppCbCr == format) { alphaType = kOpaque_SkAlphaType; } // FIXME: If we change the implementation to handle swizzling ourselves, // we can support more output formats. SkImageInfo info = SkImageInfo::MakeN32(width, height, alphaType); return new SkImageGeneratorWIC(info, imagingFactory.release(), imageSource.release(), data); }
bool SkImageEncoder_WIC::onEncode(SkWStream* stream , const SkBitmap& bitmapOrig , int quality) { GUID type; switch (fType) { case kBMP_Type: type = GUID_ContainerFormatBmp; break; case kICO_Type: type = GUID_ContainerFormatIco; break; case kJPEG_Type: type = GUID_ContainerFormatJpeg; break; case kPNG_Type: type = GUID_ContainerFormatPng; break; default: return false; } //Convert to 8888 if needed. const SkBitmap* bitmap; SkBitmap bitmapCopy; if (kN32_SkColorType == bitmapOrig.colorType() && bitmapOrig.isOpaque()) { bitmap = &bitmapOrig; } else { if (!bitmapOrig.copyTo(&bitmapCopy, kN32_SkColorType)) { return false; } bitmap = &bitmapCopy; } // We cannot use PBGRA so we need to unpremultiply ourselves if (!bitmap->isOpaque()) { SkAutoLockPixels alp(*bitmap); uint8_t* pixels = reinterpret_cast<uint8_t*>(bitmap->getPixels()); for (int y = 0; y < bitmap->height(); ++y) { for (int x = 0; x < bitmap->width(); ++x) { uint8_t* bytes = pixels + y * bitmap->rowBytes() + x * bitmap->bytesPerPixel(); SkPMColor* src = reinterpret_cast<SkPMColor*>(bytes); SkColor* dst = reinterpret_cast<SkColor*>(bytes); *dst = SkUnPreMultiply::PMColorToColor(*src); } } } //Initialize COM. SkAutoCoInitialize scopedCo; if (!scopedCo.succeeded()) { return false; } HRESULT hr = S_OK; //Create Windows Imaging Component ImagingFactory. SkTScopedComPtr<IWICImagingFactory> piImagingFactory; if (SUCCEEDED(hr)) { hr = CoCreateInstance( CLSID_WICImagingFactory , nullptr , CLSCTX_INPROC_SERVER , IID_PPV_ARGS(&piImagingFactory) ); } //Convert the SkWStream to an IStream. SkTScopedComPtr<IStream> piStream; if (SUCCEEDED(hr)) { hr = SkWIStream::CreateFromSkWStream(stream, &piStream); } //Create an encode of the appropriate type. SkTScopedComPtr<IWICBitmapEncoder> piEncoder; if (SUCCEEDED(hr)) { hr = piImagingFactory->CreateEncoder(type, nullptr, &piEncoder); } if (SUCCEEDED(hr)) { hr = piEncoder->Initialize(piStream.get(), WICBitmapEncoderNoCache); } //Create a the frame. SkTScopedComPtr<IWICBitmapFrameEncode> piBitmapFrameEncode; SkTScopedComPtr<IPropertyBag2> piPropertybag; if (SUCCEEDED(hr)) { hr = piEncoder->CreateNewFrame(&piBitmapFrameEncode, &piPropertybag); } if (SUCCEEDED(hr)) { PROPBAG2 name = { 0 }; name.dwType = PROPBAG2_TYPE_DATA; name.vt = VT_R4; name.pstrName = L"ImageQuality"; VARIANT value; VariantInit(&value); value.vt = VT_R4; value.fltVal = (FLOAT)(quality / 100.0); //Ignore result code. // This returns E_FAIL if the named property is not in the bag. //TODO(bungeman) enumerate the properties, // write and set hr iff property exists. piPropertybag->Write(1, &name, &value); } if (SUCCEEDED(hr)) { hr = piBitmapFrameEncode->Initialize(piPropertybag.get()); } //Set the size of the frame. const UINT width = bitmap->width(); const UINT height = bitmap->height(); if (SUCCEEDED(hr)) { hr = piBitmapFrameEncode->SetSize(width, height); } //Set the pixel format of the frame. const WICPixelFormatGUID formatDesired = GUID_WICPixelFormat32bppBGRA; WICPixelFormatGUID formatGUID = formatDesired; if (SUCCEEDED(hr)) { hr = piBitmapFrameEncode->SetPixelFormat(&formatGUID); } if (SUCCEEDED(hr)) { //Be sure the image format is the one requested. hr = IsEqualGUID(formatGUID, formatDesired) ? S_OK : E_FAIL; } //Write the pixels into the frame. if (SUCCEEDED(hr)) { SkAutoLockPixels alp(*bitmap); const UINT stride = (UINT) bitmap->rowBytes(); hr = piBitmapFrameEncode->WritePixels( height , stride , stride * height , reinterpret_cast<BYTE*>(bitmap->getPixels())); } if (SUCCEEDED(hr)) { hr = piBitmapFrameEncode->Commit(); } if (SUCCEEDED(hr)) { hr = piEncoder->Commit(); } return SUCCEEDED(hr); }
bool SkImageDecoder_WIC::decodeStream(SkStream* stream, SkBitmap* bm, WICModes wicMode, Format* format) const { //Initialize COM. SkAutoCoInitialize scopedCo; if (!scopedCo.succeeded()) { return false; } HRESULT hr = S_OK; //Create Windows Imaging Component ImagingFactory. SkTScopedComPtr<IWICImagingFactory> piImagingFactory; if (SUCCEEDED(hr)) { hr = CoCreateInstance( CLSID_WICImagingFactory , nullptr , CLSCTX_INPROC_SERVER , IID_PPV_ARGS(&piImagingFactory) ); } //Convert SkStream to IStream. SkTScopedComPtr<IStream> piStream; if (SUCCEEDED(hr)) { hr = SkIStream::CreateFromSkStream(stream, false, &piStream); } //Make sure we're at the beginning of the stream. if (SUCCEEDED(hr)) { LARGE_INTEGER liBeginning = { 0 }; hr = piStream->Seek(liBeginning, STREAM_SEEK_SET, nullptr); } //Create the decoder from the stream content. SkTScopedComPtr<IWICBitmapDecoder> piBitmapDecoder; if (SUCCEEDED(hr)) { hr = piImagingFactory->CreateDecoderFromStream( piStream.get() //Image to be decoded , nullptr //No particular vendor , WICDecodeMetadataCacheOnDemand //Cache metadata when needed , &piBitmapDecoder //Pointer to the decoder ); } if (kDecodeFormat_WICMode == wicMode) { SkASSERT(format != nullptr); //Get the format if (SUCCEEDED(hr)) { GUID guidFormat; hr = piBitmapDecoder->GetContainerFormat(&guidFormat); if (SUCCEEDED(hr)) { *format = GuidContainerFormat_to_Format(guidFormat); return true; } } return false; } //Get the first frame from the decoder. SkTScopedComPtr<IWICBitmapFrameDecode> piBitmapFrameDecode; if (SUCCEEDED(hr)) { hr = piBitmapDecoder->GetFrame(0, &piBitmapFrameDecode); } //Get the BitmapSource interface of the frame. SkTScopedComPtr<IWICBitmapSource> piBitmapSourceOriginal; if (SUCCEEDED(hr)) { hr = piBitmapFrameDecode->QueryInterface( IID_PPV_ARGS(&piBitmapSourceOriginal) ); } //Get the size of the bitmap. UINT width; UINT height; if (SUCCEEDED(hr)) { hr = piBitmapSourceOriginal->GetSize(&width, &height); } //Exit early if we're only looking for the bitmap bounds. if (SUCCEEDED(hr)) { bm->setInfo(SkImageInfo::MakeN32Premul(width, height)); if (kDecodeBounds_WICMode == wicMode) { return true; } if (!this->allocPixelRef(bm, nullptr)) { return false; } } //Create a format converter. SkTScopedComPtr<IWICFormatConverter> piFormatConverter; if (SUCCEEDED(hr)) { hr = piImagingFactory->CreateFormatConverter(&piFormatConverter); } GUID destinationPixelFormat; if (this->getRequireUnpremultipliedColors()) { destinationPixelFormat = GUID_WICPixelFormat32bppBGRA; } else { destinationPixelFormat = GUID_WICPixelFormat32bppPBGRA; } if (SUCCEEDED(hr)) { hr = piFormatConverter->Initialize( piBitmapSourceOriginal.get() //Input bitmap to convert , destinationPixelFormat //Destination pixel format , WICBitmapDitherTypeNone //Specified dither patterm , nullptr //Specify a particular palette , 0.f //Alpha threshold , WICBitmapPaletteTypeCustom //Palette translation type ); } //Get the BitmapSource interface of the format converter. SkTScopedComPtr<IWICBitmapSource> piBitmapSourceConverted; if (SUCCEEDED(hr)) { hr = piFormatConverter->QueryInterface( IID_PPV_ARGS(&piBitmapSourceConverted) ); } //Copy the pixels into the bitmap. if (SUCCEEDED(hr)) { SkAutoLockPixels alp(*bm); bm->eraseColor(SK_ColorTRANSPARENT); const UINT stride = (UINT) bm->rowBytes(); hr = piBitmapSourceConverted->CopyPixels( nullptr, //Get all the pixels stride, stride * height, reinterpret_cast<BYTE *>(bm->getPixels()) ); // Note: we don't need to premultiply here since we specified PBGRA if (SkBitmap::ComputeIsOpaque(*bm)) { bm->setAlphaType(kOpaque_SkAlphaType); } } return SUCCEEDED(hr); }
SkTypeface* SkFontMgr_DirectWrite::onCreateFromStream(SkStreamAsset* stream, int ttcIndex) const { SkTScopedComPtr<StreamFontFileLoader> fontFileLoader; // This transfers ownership of stream to the new object. HRN(StreamFontFileLoader::Create(stream, &fontFileLoader)); HRN(fFactory->RegisterFontFileLoader(fontFileLoader.get())); SkAutoIDWriteUnregister<StreamFontFileLoader> autoUnregisterFontFileLoader( fFactory.get(), fontFileLoader.get()); SkTScopedComPtr<StreamFontCollectionLoader> fontCollectionLoader; HRN(StreamFontCollectionLoader::Create(fontFileLoader.get(), &fontCollectionLoader)); HRN(fFactory->RegisterFontCollectionLoader(fontCollectionLoader.get())); SkAutoIDWriteUnregister<StreamFontCollectionLoader> autoUnregisterFontCollectionLoader( fFactory.get(), fontCollectionLoader.get()); SkTScopedComPtr<IDWriteFontCollection> fontCollection; HRN(fFactory->CreateCustomFontCollection(fontCollectionLoader.get(), nullptr, 0, &fontCollection)); // Find the first non-simulated font which has the given ttc index. UINT32 familyCount = fontCollection->GetFontFamilyCount(); for (UINT32 familyIndex = 0; familyIndex < familyCount; ++familyIndex) { SkTScopedComPtr<IDWriteFontFamily> fontFamily; HRN(fontCollection->GetFontFamily(familyIndex, &fontFamily)); UINT32 fontCount = fontFamily->GetFontCount(); for (UINT32 fontIndex = 0; fontIndex < fontCount; ++fontIndex) { SkTScopedComPtr<IDWriteFont> font; HRN(fontFamily->GetFont(fontIndex, &font)); if (font->GetSimulations() != DWRITE_FONT_SIMULATIONS_NONE) { continue; } SkTScopedComPtr<IDWriteFontFace> fontFace; HRN(font->CreateFontFace(&fontFace)); UINT32 faceIndex = fontFace->GetIndex(); if (faceIndex == ttcIndex) { return DWriteFontTypeface::Create(fFactory.get(), fontFace.get(), font.get(), fontFamily.get(), autoUnregisterFontFileLoader.detatch(), autoUnregisterFontCollectionLoader.detatch()); } } } return nullptr; }
bool SkImageEncoder_WIC::onEncode(SkWStream* stream , const SkBitmap& bm , int quality) { GUID type; switch (fType) { case kJPEG_Type: type = GUID_ContainerFormatJpeg; break; case kPNG_Type: type = GUID_ContainerFormatPng; break; default: return false; } //Initialize COM. AutoCoInitialize scopedCo; HRESULT hr = scopedCo.getHR(); //Create Windows Imaging Component ImagingFactory. SkTScopedComPtr<IWICImagingFactory> piImagingFactory; if (SUCCEEDED(hr)) { hr = CoCreateInstance( CLSID_WICImagingFactory , NULL , CLSCTX_INPROC_SERVER , IID_PPV_ARGS(&piImagingFactory) ); } //Convert the SkWStream to an IStream. SkTScopedComPtr<IStream> piStream; if (SUCCEEDED(hr)) { hr = SkWIStream::CreateFromSkWStream(stream, &piStream); } //Create an encode of the appropriate type. SkTScopedComPtr<IWICBitmapEncoder> piEncoder; if (SUCCEEDED(hr)) { hr = piImagingFactory->CreateEncoder(type, NULL, &piEncoder); } if (SUCCEEDED(hr)) { hr = piEncoder->Initialize(piStream.get(), WICBitmapEncoderNoCache); } //Create a the frame. SkTScopedComPtr<IWICBitmapFrameEncode> piBitmapFrameEncode; SkTScopedComPtr<IPropertyBag2> piPropertybag; if (SUCCEEDED(hr)) { hr = piEncoder->CreateNewFrame(&piBitmapFrameEncode, &piPropertybag); } if (SUCCEEDED(hr)) { PROPBAG2 name = { 0 }; name.dwType = PROPBAG2_TYPE_DATA; name.vt = VT_R4; name.pstrName = L"ImageQuality"; VARIANT value; VariantInit(&value); value.vt = VT_R4; value.fltVal = (FLOAT)(quality / 100.0); //Ignore result code. // This returns E_FAIL if the named property is not in the bag. //TODO(bungeman) enumerate the properties, // write and set hr iff property exists. piPropertybag->Write(1, &name, &value); } if (SUCCEEDED(hr)) { hr = piBitmapFrameEncode->Initialize(piPropertybag.get()); } //Set the size of the frame. const UINT width = bm.width(); const UINT height = bm.height(); if (SUCCEEDED(hr)) { hr = piBitmapFrameEncode->SetSize(width, height); } //Set the pixel format of the frame. const WICPixelFormatGUID formatDesired = GUID_WICPixelFormat32bppBGRA; WICPixelFormatGUID formatGUID = formatDesired; if (SUCCEEDED(hr)) { hr = piBitmapFrameEncode->SetPixelFormat(&formatGUID); } if (SUCCEEDED(hr)) { //Be sure the image format is the one requested. hr = IsEqualGUID(formatGUID, formatDesired) ? S_OK : E_FAIL; } //Write the pixels into the frame. if (SUCCEEDED(hr)) { hr = piBitmapFrameEncode->WritePixels( height , bm.rowBytes() , bm.rowBytes()*height , reinterpret_cast<BYTE*>(bm.getPixels())); } if (SUCCEEDED(hr)) { hr = piBitmapFrameEncode->Commit(); } if (SUCCEEDED(hr)) { hr = piEncoder->Commit(); } return SUCCEEDED(hr); }
SkTypeface* SkFontMgr_DirectWrite::onMatchFamilyStyleCharacter(const char familyName[], const SkFontStyle& style, const char* bcp47[], int bcp47Count, SkUnichar character) const { const DWriteStyle dwStyle(style); const WCHAR* dwFamilyName = nullptr; SkSMallocWCHAR dwFamilyNameLocal; if (familyName) { HRN(sk_cstring_to_wchar(familyName, &dwFamilyNameLocal)); dwFamilyName = dwFamilyNameLocal; } WCHAR str[16]; UINT32 strLen = static_cast<UINT32>( SkUTF16_FromUnichar(character, reinterpret_cast<uint16_t*>(str))); const SkSMallocWCHAR* dwBcp47; SkSMallocWCHAR dwBcp47Local; if (bcp47Count < 1) { dwBcp47 = &fLocaleName; } else { // TODO: support fallback stack. // TODO: DirectWrite supports 'zh-CN' or 'zh-Hans', but 'zh' misses completely // and may produce a Japanese font. HRN(sk_cstring_to_wchar(bcp47[bcp47Count - 1], &dwBcp47Local)); dwBcp47 = &dwBcp47Local; } if (fFactory2.get()) { SkTScopedComPtr<IDWriteFontFallback> systemFontFallback; IDWriteFontFallback* fontFallback = fFontFallback.get(); if (!fontFallback) { HRNM(fFactory2->GetSystemFontFallback(&systemFontFallback), "Could not get system fallback."); fontFallback = systemFontFallback.get(); } SkTScopedComPtr<IDWriteNumberSubstitution> numberSubstitution; HRNM(fFactory2->CreateNumberSubstitution(DWRITE_NUMBER_SUBSTITUTION_METHOD_NONE, nullptr, TRUE, &numberSubstitution), "Could not create number substitution."); SkTScopedComPtr<FontFallbackSource> fontFallbackSource( new FontFallbackSource(str, strLen, *dwBcp47, numberSubstitution.get())); UINT32 mappedLength; SkTScopedComPtr<IDWriteFont> font; FLOAT scale; HRNM(fontFallback->MapCharacters(fontFallbackSource.get(), 0, // textPosition, strLen, fFontCollection.get(), dwFamilyName, dwStyle.fWeight, dwStyle.fSlant, dwStyle.fWidth, &mappedLength, &font, &scale), "Could not map characters"); if (!font.get()) { return nullptr; } SkTScopedComPtr<IDWriteFontFace> fontFace; HRNM(font->CreateFontFace(&fontFace), "Could not get font face from font."); SkTScopedComPtr<IDWriteFontFamily> fontFamily; HRNM(font->GetFontFamily(&fontFamily), "Could not get family from font."); return this->createTypefaceFromDWriteFont(fontFace.get(), font.get(), fontFamily.get()); } SkTScopedComPtr<IDWriteTextFormat> fallbackFormat; HRNM(fFactory->CreateTextFormat(dwFamilyName ? dwFamilyName : L"", fFontCollection.get(), dwStyle.fWeight, dwStyle.fSlant, dwStyle.fWidth, 72.0f, *dwBcp47, &fallbackFormat), "Could not create text format."); SkTScopedComPtr<IDWriteTextLayout> fallbackLayout; HRNM(fFactory->CreateTextLayout(str, strLen, fallbackFormat.get(), 200.0f, 200.0f, &fallbackLayout), "Could not create text layout."); SkTScopedComPtr<FontFallbackRenderer> fontFallbackRenderer( new FontFallbackRenderer(this, character)); HRNM(fallbackLayout->Draw(nullptr, fontFallbackRenderer.get(), 50.0f, 50.0f), "Could not draw layout with renderer."); return fontFallbackRenderer->FallbackTypeface(); }
bool SkImageDecoder_WIC::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) { //Initialize COM. AutoCoInitialize scopedCo; HRESULT hr = scopedCo.getHR(); //Create Windows Imaging Component ImagingFactory. SkTScopedComPtr<IWICImagingFactory> piImagingFactory; if (SUCCEEDED(hr)) { hr = CoCreateInstance( CLSID_WICImagingFactory , NULL , CLSCTX_INPROC_SERVER , IID_PPV_ARGS(&piImagingFactory) ); } //Convert SkStream to IStream. SkTScopedComPtr<IStream> piStream; if (SUCCEEDED(hr)) { hr = SkIStream::CreateFromSkStream(stream, false, &piStream); } //Make sure we're at the beginning of the stream. if (SUCCEEDED(hr)) { LARGE_INTEGER liBeginning = { 0 }; hr = piStream->Seek(liBeginning, STREAM_SEEK_SET, NULL); } //Create the decoder from the stream content. SkTScopedComPtr<IWICBitmapDecoder> piBitmapDecoder; if (SUCCEEDED(hr)) { hr = piImagingFactory->CreateDecoderFromStream( piStream.get() //Image to be decoded , NULL //No particular vendor , WICDecodeMetadataCacheOnDemand //Cache metadata when needed , &piBitmapDecoder //Pointer to the decoder ); } //Get the first frame from the decoder. SkTScopedComPtr<IWICBitmapFrameDecode> piBitmapFrameDecode; if (SUCCEEDED(hr)) { hr = piBitmapDecoder->GetFrame(0, &piBitmapFrameDecode); } //Get the BitmapSource interface of the frame. SkTScopedComPtr<IWICBitmapSource> piBitmapSourceOriginal; if (SUCCEEDED(hr)) { hr = piBitmapFrameDecode->QueryInterface( IID_PPV_ARGS(&piBitmapSourceOriginal) ); } //Get the size of the bitmap. UINT width; UINT height; if (SUCCEEDED(hr)) { hr = piBitmapSourceOriginal->GetSize(&width, &height); } //Exit early if we're only looking for the bitmap bounds. if (SUCCEEDED(hr)) { bm->setConfig(SkBitmap::kARGB_8888_Config, width, height); if (SkImageDecoder::kDecodeBounds_Mode == mode) { return true; } if (!this->allocPixelRef(bm, NULL)) { return false; } } //Create a format converter. SkTScopedComPtr<IWICFormatConverter> piFormatConverter; if (SUCCEEDED(hr)) { hr = piImagingFactory->CreateFormatConverter(&piFormatConverter); } if (SUCCEEDED(hr)) { hr = piFormatConverter->Initialize( piBitmapSourceOriginal.get() //Input bitmap to convert , GUID_WICPixelFormat32bppPBGRA //Destination pixel format , WICBitmapDitherTypeNone //Specified dither patterm , NULL //Specify a particular palette , 0.f //Alpha threshold , WICBitmapPaletteTypeCustom //Palette translation type ); } //Get the BitmapSource interface of the format converter. SkTScopedComPtr<IWICBitmapSource> piBitmapSourceConverted; if (SUCCEEDED(hr)) { hr = piFormatConverter->QueryInterface( IID_PPV_ARGS(&piBitmapSourceConverted) ); } //Copy the pixels into the bitmap. if (SUCCEEDED(hr)) { bm->lockPixels(); bm->eraseColor(0); const int stride = bm->rowBytes(); hr = piBitmapSourceConverted->CopyPixels( NULL, //Get all the pixels stride, stride * height, reinterpret_cast<BYTE *>(bm->getPixels()) ); bm->unlockPixels(); } return SUCCEEDED(hr); }
SkFontStyleSet* SkFontMgr_DirectWrite::onCreateStyleSet(int index) const { SkTScopedComPtr<IDWriteFontFamily> fontFamily; HRNM(fFontCollection->GetFontFamily(index, &fontFamily), "Could not get requested family."); return new SkFontStyleSet_DirectWrite(this, fontFamily.get()); }
void DWriteFontTypeface::onGetFamilyName(SkString* familyName) const { SkTScopedComPtr<IDWriteLocalizedStrings> familyNames; HRV(fDWriteFontFamily->GetFamilyNames(&familyNames)); sk_get_locale_string(familyNames.get(), nullptr/*fMgr->fLocaleName.get()*/, familyName); }
static bool FindByDWriteFont(SkTypeface* cached, void* ctx) { DWriteFontTypeface* cshFace = reinterpret_cast<DWriteFontTypeface*>(cached); ProtoDWriteTypeface* ctxFace = reinterpret_cast<ProtoDWriteTypeface*>(ctx); bool same; //Check to see if the two fonts are identical. HRB(are_same(cshFace->fDWriteFont.get(), ctxFace->fDWriteFont, same)); if (same) { return true; } HRB(are_same(cshFace->fDWriteFontFace.get(), ctxFace->fDWriteFontFace, same)); if (same) { return true; } //Check if the two fonts share the same loader and have the same key. UINT32 cshNumFiles; UINT32 ctxNumFiles; HRB(cshFace->fDWriteFontFace->GetFiles(&cshNumFiles, nullptr)); HRB(ctxFace->fDWriteFontFace->GetFiles(&ctxNumFiles, nullptr)); if (cshNumFiles != ctxNumFiles) { return false; } SkTScopedComPtr<IDWriteFontFile> cshFontFile; SkTScopedComPtr<IDWriteFontFile> ctxFontFile; HRB(cshFace->fDWriteFontFace->GetFiles(&cshNumFiles, &cshFontFile)); HRB(ctxFace->fDWriteFontFace->GetFiles(&ctxNumFiles, &ctxFontFile)); //for (each file) { //we currently only admit fonts from one file. SkTScopedComPtr<IDWriteFontFileLoader> cshFontFileLoader; SkTScopedComPtr<IDWriteFontFileLoader> ctxFontFileLoader; HRB(cshFontFile->GetLoader(&cshFontFileLoader)); HRB(ctxFontFile->GetLoader(&ctxFontFileLoader)); HRB(are_same(cshFontFileLoader.get(), ctxFontFileLoader.get(), same)); if (!same) { return false; } //} const void* cshRefKey; UINT32 cshRefKeySize; const void* ctxRefKey; UINT32 ctxRefKeySize; HRB(cshFontFile->GetReferenceKey(&cshRefKey, &cshRefKeySize)); HRB(ctxFontFile->GetReferenceKey(&ctxRefKey, &ctxRefKeySize)); if (cshRefKeySize != ctxRefKeySize) { return false; } if (0 != memcmp(cshRefKey, ctxRefKey, ctxRefKeySize)) { return false; } //TODO: better means than comparing name strings? //NOTE: .ttc and fake bold/italic will end up here. SkTScopedComPtr<IDWriteLocalizedStrings> cshFamilyNames; SkTScopedComPtr<IDWriteLocalizedStrings> cshFaceNames; HRB(cshFace->fDWriteFontFamily->GetFamilyNames(&cshFamilyNames)); HRB(cshFace->fDWriteFont->GetFaceNames(&cshFaceNames)); UINT32 cshFamilyNameLength; UINT32 cshFaceNameLength; HRB(cshFamilyNames->GetStringLength(0, &cshFamilyNameLength)); HRB(cshFaceNames->GetStringLength(0, &cshFaceNameLength)); SkTScopedComPtr<IDWriteLocalizedStrings> ctxFamilyNames; SkTScopedComPtr<IDWriteLocalizedStrings> ctxFaceNames; HRB(ctxFace->fDWriteFontFamily->GetFamilyNames(&ctxFamilyNames)); HRB(ctxFace->fDWriteFont->GetFaceNames(&ctxFaceNames)); UINT32 ctxFamilyNameLength; UINT32 ctxFaceNameLength; HRB(ctxFamilyNames->GetStringLength(0, &ctxFamilyNameLength)); HRB(ctxFaceNames->GetStringLength(0, &ctxFaceNameLength)); if (cshFamilyNameLength != ctxFamilyNameLength || cshFaceNameLength != ctxFaceNameLength) { return false; } SkSMallocWCHAR cshFamilyName(cshFamilyNameLength+1); SkSMallocWCHAR cshFaceName(cshFaceNameLength+1); HRB(cshFamilyNames->GetString(0, cshFamilyName.get(), cshFamilyNameLength+1)); HRB(cshFaceNames->GetString(0, cshFaceName.get(), cshFaceNameLength+1)); SkSMallocWCHAR ctxFamilyName(ctxFamilyNameLength+1); SkSMallocWCHAR ctxFaceName(ctxFaceNameLength+1); HRB(ctxFamilyNames->GetString(0, ctxFamilyName.get(), ctxFamilyNameLength+1)); HRB(ctxFaceNames->GetString(0, ctxFaceName.get(), ctxFaceNameLength+1)); return wcscmp(cshFamilyName.get(), ctxFamilyName.get()) == 0 && wcscmp(cshFaceName.get(), ctxFaceName.get()) == 0; }