diff options
author | Steve Block <steveblock@google.com> | 2011-05-06 11:45:16 +0100 |
---|---|---|
committer | Steve Block <steveblock@google.com> | 2011-05-12 13:44:10 +0100 |
commit | cad810f21b803229eb11403f9209855525a25d57 (patch) | |
tree | 29a6fd0279be608e0fe9ffe9841f722f0f4e4269 /Source/WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp | |
parent | 121b0cf4517156d0ac5111caf9830c51b69bae8f (diff) | |
download | external_webkit-cad810f21b803229eb11403f9209855525a25d57.zip external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.gz external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.bz2 |
Merge WebKit at r75315: Initial merge by git.
Change-Id: I570314b346ce101c935ed22a626b48c2af266b84
Diffstat (limited to 'Source/WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp')
-rw-r--r-- | Source/WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp | 239 |
1 files changed, 239 insertions, 0 deletions
diff --git a/Source/WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp b/Source/WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp new file mode 100644 index 0000000..e71f66a --- /dev/null +++ b/Source/WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2008, 2009 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include <windows.h> +#include <vector> + +#include "ChromiumBridge.h" +#include "Font.h" +#include "GlyphPageTreeNode.h" +#include "SimpleFontData.h" +#include "UniscribeHelperTextRun.h" +#include "WindowsVersion.h" + +namespace WebCore { + +// Fills one page of font data pointers with 0 to indicate that there +// are no glyphs for the characters. +static void fillEmptyGlyphs(GlyphPage* page) +{ + for (int i = 0; i < GlyphPage::size; ++i) + page->setGlyphDataForIndex(i, 0, 0); +} + +// Lazily initializes space glyph +static Glyph initSpaceGlyph(HDC dc, Glyph* spaceGlyph) +{ + if (*spaceGlyph) + return *spaceGlyph; + + static wchar_t space = ' '; + GetGlyphIndices(dc, &space, 1, spaceGlyph, 0); + return *spaceGlyph; +} + +// Fills |length| glyphs starting at |offset| in a |page| in the Basic +// Multilingual Plane (<= U+FFFF). The input buffer size should be the +// same as |length|. We can use the standard Windows GDI functions here. +// Returns true if any glyphs were found. +static bool fillBMPGlyphs(unsigned offset, + unsigned length, + UChar* buffer, + GlyphPage* page, + const SimpleFontData* fontData, + bool recurse) +{ + HDC dc = GetDC((HWND)0); + HGDIOBJ oldFont = SelectObject(dc, fontData->platformData().hfont()); + + TEXTMETRIC tm = {0}; + if (!GetTextMetrics(dc, &tm)) { + SelectObject(dc, oldFont); + ReleaseDC(0, dc); + + if (recurse) { + if (ChromiumBridge::ensureFontLoaded(fontData->platformData().hfont())) + return fillBMPGlyphs(offset, length, buffer, page, fontData, false); + else { + fillEmptyGlyphs(page); + return false; + } + } else { + // FIXME: Handle gracefully the error if this call also fails. + // See http://crbug.com/6401 + LOG_ERROR("Unable to get the text metrics after second attempt"); + fillEmptyGlyphs(page); + return false; + } + } + + // FIXME: GetGlyphIndices() sets each item of localGlyphBuffer[] + // with the one of the values listed below. + // * With the GGI_MARK_NONEXISTING_GLYPHS flag + // + If the font has a glyph available for the character, + // localGlyphBuffer[i] > 0x0. + // + If the font does not have glyphs available for the character, + // localGlyphBuffer[i] = 0x1F (TrueType Collection?) or + // 0xFFFF (OpenType?). + // * Without the GGI_MARK_NONEXISTING_GLYPHS flag + // + If the font has a glyph available for the character, + // localGlyphBuffer[i] > 0x0. + // + If the font does not have glyphs available for the character, + // localGlyphBuffer[i] = 0x80. + // (Windows automatically assigns the glyph for a box character to + // prevent ExtTextOut() from returning errors.) + // To avoid from hurting the rendering performance, this code just + // tells WebKit whether or not the all glyph indices for the given + // characters are 0x80 (i.e. a possibly-invalid glyph) and let it + // use alternative fonts for the characters. + // Although this may cause a problem, it seems to work fine as far as I + // have tested. (Obviously, I need more tests.) + WORD localGlyphBuffer[GlyphPage::size]; + + // FIXME: I find some Chinese characters can not be correctly displayed + // when call GetGlyphIndices without flag GGI_MARK_NONEXISTING_GLYPHS, + // because the corresponding glyph index is set as 0x20 when current font + // does not have glyphs available for the character. According a blog post + // http://blogs.msdn.com/michkap/archive/2006/06/28/649791.aspx + // I think we should switch to the way about calling GetGlyphIndices with + // flag GGI_MARK_NONEXISTING_GLYPHS, it should be OK according the + // description of MSDN. + // Also according to Jungshik and Hironori's suggestion and modification + // we treat turetype and raster Font as different way when windows version + // is less than Vista. + GetGlyphIndices(dc, buffer, length, localGlyphBuffer, GGI_MARK_NONEXISTING_GLYPHS); + + // Copy the output to the GlyphPage + bool haveGlyphs = false; + int invalidGlyph = 0xFFFF; + const DWORD cffTableTag = 0x20464643; // 4-byte identifier for OpenType CFF table ('CFF '). + if (!isVistaOrNewer() && !(tm.tmPitchAndFamily & TMPF_TRUETYPE) && (GetFontData(dc, cffTableTag, 0, 0, 0) == GDI_ERROR)) + invalidGlyph = 0x1F; + + Glyph spaceGlyph = 0; // Glyph for a space. Lazily filled. + + for (unsigned i = 0; i < length; i++) { + UChar c = buffer[i]; + Glyph glyph = localGlyphBuffer[i]; + const SimpleFontData* glyphFontData = fontData; + // When this character should be a space, we ignore whatever the font + // says and use a space. Otherwise, if fonts don't map one of these + // space or zero width glyphs, we will get a box. + if (Font::treatAsSpace(c)) { + // Hard code the glyph indices for characters that should be + // treated like spaces. + glyph = initSpaceGlyph(dc, &spaceGlyph); + } else if (glyph == invalidGlyph) { + // WebKit expects both the glyph index and FontData + // pointer to be 0 if the glyph is not present + glyph = 0; + glyphFontData = 0; + } else + haveGlyphs = true; + page->setGlyphDataForCharacter(offset + i, glyph, glyphFontData); + } + + SelectObject(dc, oldFont); + ReleaseDC(0, dc); + return haveGlyphs; +} + +// For non-BMP characters, each is two words (UTF-16) and the input buffer +// size is 2 * |length|. Since GDI doesn't know how to handle non-BMP +// characters, we must use Uniscribe to tell us the glyph indices. +// +// We don't want to call this in the case of "regular" characters since some +// fonts may not have the correct combining rules for accents. See the notes +// at the bottom of ScriptGetCMap. We can't use ScriptGetCMap, though, since +// it doesn't seem to support UTF-16, despite what this blog post says: +// http://blogs.msdn.com/michkap/archive/2006/06/29/650680.aspx +// +// So we fire up the full Uniscribe doohicky, give it our string, and it will +// correctly handle the UTF-16 for us. The hard part is taking this and getting +// the glyph indices back out that correspond to the correct input characters, +// since they may be missing. +// +// Returns true if any glyphs were found. +static bool fillNonBMPGlyphs(unsigned offset, + unsigned length, + UChar* buffer, + GlyphPage* page, + const SimpleFontData* fontData) +{ + bool haveGlyphs = false; + + UniscribeHelperTextRun state(buffer, length * 2, false, + fontData->platformData().hfont(), + fontData->platformData().scriptCache(), + fontData->platformData().scriptFontProperties()); + state.setInhibitLigate(true); + state.setDisableFontFallback(true); + state.init(); + + for (unsigned i = 0; i < length; i++) { + // Each character in this input buffer is a surrogate pair, which + // consists of two UChars. So, the offset for its i-th character is + // (i * 2). + WORD glyph = state.firstGlyphForCharacter(i * 2); + if (glyph) { + haveGlyphs = true; + page->setGlyphDataForIndex(offset + i, glyph, fontData); + } else + // Clear both glyph and fontData fields. + page->setGlyphDataForIndex(offset + i, 0, 0); + } + return haveGlyphs; +} + +// We're supposed to return true if there are any glyphs in the range +// specified by |offset| and |length| in our font, +// false if there are none. +bool GlyphPage::fill(unsigned offset, unsigned length, UChar* characterBuffer, + unsigned bufferLength, const SimpleFontData* fontData) +{ + // We have to handle BMP and non-BMP characters differently. + // FIXME: Add assertions to make sure that buffer is entirely in BMP + // or entirely in non-BMP. + if (bufferLength == length) + return fillBMPGlyphs(offset, length, characterBuffer, this, fontData, true); + + if (bufferLength == 2 * length) { + // A non-BMP input buffer will be twice as long as output glyph buffer + // because each character in the non-BMP input buffer will be + // represented by a surrogate pair (two UChar's). + return fillNonBMPGlyphs(offset, length, characterBuffer, this, fontData); + } + + ASSERT_NOT_REACHED(); + return false; +} + +} // namespace WebCore |