michael@0: /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: //#define FORCE_PR_LOG michael@0: michael@0: #include "gfxGDIShaper.h" michael@0: michael@0: /********************************************************************** michael@0: * michael@0: * class gfxGDIShaper michael@0: * michael@0: **********************************************************************/ michael@0: michael@0: bool michael@0: gfxGDIShaper::ShapeText(gfxContext *aContext, michael@0: const char16_t *aText, michael@0: uint32_t aOffset, michael@0: uint32_t aLength, michael@0: int32_t aScript, michael@0: gfxShapedText *aShapedText) michael@0: { michael@0: DCFromContext dc(aContext); michael@0: AutoSelectFont selectFont(dc, static_cast(mFont)->GetHFONT()); michael@0: michael@0: uint32_t length = aLength; michael@0: AutoFallibleTArray glyphArray; michael@0: if (!glyphArray.SetLength(length)) { michael@0: return false; michael@0: } michael@0: WORD *glyphs = glyphArray.Elements(); michael@0: michael@0: DWORD ret = ::GetGlyphIndicesW(dc, char16ptr_t(aText), length, michael@0: glyphs, GGI_MARK_NONEXISTING_GLYPHS); michael@0: if (ret == GDI_ERROR) { michael@0: return false; michael@0: } michael@0: michael@0: for (int k = 0; k < length; k++) { michael@0: if (glyphs[k] == 0xFFFF) michael@0: return false; michael@0: } michael@0: michael@0: SIZE size; michael@0: AutoFallibleTArray partialWidthArray; michael@0: if (!partialWidthArray.SetLength(length)) { michael@0: return false; michael@0: } michael@0: michael@0: BOOL success = ::GetTextExtentExPointI(dc, michael@0: glyphs, michael@0: length, michael@0: INT_MAX, michael@0: nullptr, michael@0: partialWidthArray.Elements(), michael@0: &size); michael@0: if (!success) { michael@0: return false; michael@0: } michael@0: michael@0: gfxTextRun::CompressedGlyph g; michael@0: gfxTextRun::CompressedGlyph *charGlyphs = michael@0: aShapedText->GetCharacterGlyphs(); michael@0: uint32_t i; michael@0: int32_t lastWidth = 0; michael@0: int32_t appUnitsPerDevPixel = aShapedText->GetAppUnitsPerDevUnit(); michael@0: for (i = 0; i < length; ++i) { michael@0: uint32_t offset = aOffset + i; michael@0: int32_t advancePixels = partialWidthArray[i] - lastWidth; michael@0: lastWidth = partialWidthArray[i]; michael@0: int32_t advanceAppUnits = advancePixels * appUnitsPerDevPixel; michael@0: WCHAR glyph = glyphs[i]; michael@0: NS_ASSERTION(!gfxFontGroup::IsInvalidChar(aText[i]), michael@0: "Invalid character detected!"); michael@0: bool atClusterStart = charGlyphs[offset].IsClusterStart(); michael@0: if (advanceAppUnits >= 0 && michael@0: gfxShapedWord::CompressedGlyph::IsSimpleAdvance(advanceAppUnits) && michael@0: gfxShapedWord::CompressedGlyph::IsSimpleGlyphID(glyph) && michael@0: atClusterStart) michael@0: { michael@0: charGlyphs[offset].SetSimpleGlyph(advanceAppUnits, glyph); michael@0: } else { michael@0: gfxShapedText::DetailedGlyph details; michael@0: details.mGlyphID = glyph; michael@0: details.mAdvance = advanceAppUnits; michael@0: details.mXOffset = 0; michael@0: details.mYOffset = 0; michael@0: aShapedText->SetGlyphs(offset, michael@0: g.SetComplex(atClusterStart, true, 1), michael@0: &details); michael@0: } michael@0: } michael@0: michael@0: return true; michael@0: }