summaryrefslogtreecommitdiffstats
path: root/WebCore/platform/graphics/mac
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/platform/graphics/mac')
-rw-r--r--WebCore/platform/graphics/mac/ComplexTextController.cpp (renamed from WebCore/platform/graphics/mac/CoreTextController.cpp)273
-rw-r--r--WebCore/platform/graphics/mac/ComplexTextController.h162
-rw-r--r--WebCore/platform/graphics/mac/ComplexTextControllerATSUI.cpp341
-rw-r--r--WebCore/platform/graphics/mac/ComplexTextControllerCoreText.cpp144
-rw-r--r--WebCore/platform/graphics/mac/CoreTextController.h116
-rw-r--r--WebCore/platform/graphics/mac/FontComplexTextMac.cpp (renamed from WebCore/platform/graphics/mac/FontMacCoreText.cpp)38
-rw-r--r--WebCore/platform/graphics/mac/FontCustomPlatformData.cpp9
-rw-r--r--WebCore/platform/graphics/mac/FontMac.mm7
-rw-r--r--WebCore/platform/graphics/mac/FontMacATSUI.mm635
-rw-r--r--WebCore/platform/graphics/mac/GraphicsContext3DMac.cpp733
-rw-r--r--WebCore/platform/graphics/mac/GraphicsLayerCA.h1
-rw-r--r--WebCore/platform/graphics/mac/GraphicsLayerCA.mm57
-rw-r--r--WebCore/platform/graphics/mac/IconMac.mm35
-rw-r--r--WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h3
-rw-r--r--WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm32
15 files changed, 991 insertions, 1595 deletions
diff --git a/WebCore/platform/graphics/mac/CoreTextController.cpp b/WebCore/platform/graphics/mac/ComplexTextController.cpp
index b2682e4..265b2c3 100644
--- a/WebCore/platform/graphics/mac/CoreTextController.cpp
+++ b/WebCore/platform/graphics/mac/ComplexTextController.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007, 2008 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,30 +10,24 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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.
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "CoreTextController.h"
-
-#if USE(CORE_TEXT)
+#include "ComplexTextController.h"
#include "CharacterNames.h"
#include "Font.h"
-#include "FontCache.h"
-#include "SimpleFontData.h"
#include "TextBreakIterator.h"
-#include <wtf/MathExtras.h>
using namespace std;
@@ -53,54 +47,7 @@ static inline CGFloat ceilCGFloat(CGFloat f)
return static_cast<CGFloat>(ceil(f));
}
-CoreTextController::CoreTextRun::CoreTextRun(CTRunRef ctRun, const SimpleFontData* fontData, const UChar* characters, unsigned stringLocation, size_t stringLength)
- : m_CTRun(ctRun)
- , m_fontData(fontData)
- , m_characters(characters)
- , m_stringLocation(stringLocation)
- , m_stringLength(stringLength)
-{
- m_glyphCount = CTRunGetGlyphCount(ctRun);
- m_indices = CTRunGetStringIndicesPtr(ctRun);
- if (!m_indices) {
- m_indicesData.adoptCF(CFDataCreateMutable(kCFAllocatorDefault, m_glyphCount * sizeof(CFIndex)));
- CFDataIncreaseLength(m_indicesData.get(), m_glyphCount * sizeof(CFIndex));
- m_indices = reinterpret_cast<const CFIndex*>(CFDataGetMutableBytePtr(m_indicesData.get()));
- CTRunGetStringIndices(ctRun, CFRangeMake(0, 0), const_cast<CFIndex*>(m_indices));
- }
-}
-
-// Missing glyphs run constructor. Core Text will not generate a run of missing glyphs, instead falling back on
-// glyphs from LastResort. We want to use the primary font's missing glyph in order to match the fast text code path.
-CoreTextController::CoreTextRun::CoreTextRun(const SimpleFontData* fontData, const UChar* characters, unsigned stringLocation, size_t stringLength, bool ltr)
- : m_fontData(fontData)
- , m_characters(characters)
- , m_stringLocation(stringLocation)
- , m_stringLength(stringLength)
-{
- Vector<CFIndex, 16> indices;
- unsigned r = 0;
- while (r < stringLength) {
- indices.append(r);
- if (U_IS_SURROGATE(characters[r])) {
- ASSERT(r + 1 < stringLength);
- ASSERT(U_IS_SURROGATE_LEAD(characters[r]));
- ASSERT(U_IS_TRAIL(characters[r + 1]));
- r += 2;
- } else
- r++;
- }
- m_glyphCount = indices.size();
- if (!ltr) {
- for (unsigned r = 0, end = m_glyphCount - 1; r < m_glyphCount / 2; ++r, --end)
- std::swap(indices[r], indices[end]);
- }
- m_indicesData.adoptCF(CFDataCreateMutable(kCFAllocatorDefault, m_glyphCount * sizeof(CFIndex)));
- CFDataAppendBytes(m_indicesData.get(), reinterpret_cast<const UInt8*>(indices.data()), m_glyphCount * sizeof(CFIndex));
- m_indices = reinterpret_cast<const CFIndex*>(CFDataGetBytePtr(m_indicesData.get()));
-}
-
-CoreTextController::CoreTextController(const Font* font, const TextRun& run, bool mayUseNaturalWritingDirection, HashSet<const SimpleFontData*>* fallbackFonts)
+ComplexTextController::ComplexTextController(const Font* font, const TextRun& run, bool mayUseNaturalWritingDirection, HashSet<const SimpleFontData*>* fallbackFonts)
: m_font(*font)
, m_run(run)
, m_mayUseNaturalWritingDirection(mayUseNaturalWritingDirection)
@@ -111,6 +58,7 @@ CoreTextController::CoreTextController(const Font* font, const TextRun& run, boo
, m_numGlyphsSoFar(0)
, m_currentRun(0)
, m_glyphInCurrentRun(0)
+ , m_characterInCurrentGlyph(0)
, m_finalRoundingWidth(0)
, m_fallbackFonts(fallbackFonts)
, m_lastRoundingGlyph(0)
@@ -130,16 +78,12 @@ CoreTextController::CoreTextController(const Font* font, const TextRun& run, boo
m_padPerSpace = ceilf(m_run.padding() / numSpaces);
}
- collectCoreTextRuns();
+ collectComplexTextRuns();
adjustGlyphsAndAdvances();
}
-int CoreTextController::offsetForPosition(int h, bool includePartialGlyphs)
+int ComplexTextController::offsetForPosition(int h, bool includePartialGlyphs)
{
- // FIXME: For positions occurring within a ligature, we should return the closest "ligature caret" or
- // approximate it by dividing the width of the ligature by the number of characters it encompasses.
- // However, Core Text does not expose a low-level API for directly finding
- // out how many characters a ligature encompasses (the "attachment count").
if (h >= m_totalWidth)
return m_run.ltr() ? m_end : 0;
if (h < 0)
@@ -147,17 +91,27 @@ int CoreTextController::offsetForPosition(int h, bool includePartialGlyphs)
CGFloat x = h;
- size_t runCount = m_coreTextRuns.size();
+ size_t runCount = m_complexTextRuns.size();
size_t offsetIntoAdjustedGlyphs = 0;
for (size_t r = 0; r < runCount; ++r) {
- const CoreTextRun& coreTextRun = m_coreTextRuns[r];
- for (unsigned j = 0; j < coreTextRun.glyphCount(); ++j) {
+ const ComplexTextRun& complexTextRun = *m_complexTextRuns[r];
+ for (unsigned j = 0; j < complexTextRun.glyphCount(); ++j) {
CGFloat adjustedAdvance = m_adjustedAdvances[offsetIntoAdjustedGlyphs + j].width;
- if (x <= adjustedAdvance) {
- CFIndex hitIndex = coreTextRun.indexAt(j);
- int stringLength = coreTextRun.stringLength();
- TextBreakIterator* cursorPositionIterator = cursorMovementIterator(coreTextRun.characters(), stringLength);
+ if (x < adjustedAdvance) {
+ CFIndex hitGlyphStart = complexTextRun.indexAt(j);
+ CFIndex hitGlyphEnd;
+ if (m_run.ltr())
+ hitGlyphEnd = max<CFIndex>(hitGlyphStart, j + 1 < complexTextRun.glyphCount() ? complexTextRun.indexAt(j + 1) : complexTextRun.stringLength());
+ else
+ hitGlyphEnd = max<CFIndex>(hitGlyphStart, j > 0 ? complexTextRun.indexAt(j - 1) : complexTextRun.stringLength());
+
+ // FIXME: Instead of dividing the glyph's advance equially between the characters, this
+ // could use the glyph's "ligature carets". However, there is no Core Text API to get the
+ // ligature carets.
+ CFIndex hitIndex = hitGlyphStart + (hitGlyphEnd - hitGlyphStart) * (m_run.ltr() ? x / adjustedAdvance : 1 - x / adjustedAdvance);
+ int stringLength = complexTextRun.stringLength();
+ TextBreakIterator* cursorPositionIterator = cursorMovementIterator(complexTextRun.characters(), stringLength);
int clusterStart;
if (isTextBreak(cursorPositionIterator, hitIndex))
clusterStart = hitIndex;
@@ -168,45 +122,49 @@ int CoreTextController::offsetForPosition(int h, bool includePartialGlyphs)
}
if (!includePartialGlyphs)
- return coreTextRun.stringLocation() + clusterStart;
+ return complexTextRun.stringLocation() + clusterStart;
int clusterEnd = textBreakFollowing(cursorPositionIterator, hitIndex);
if (clusterEnd == TextBreakDone)
clusterEnd = stringLength;
- CGFloat clusterWidth = adjustedAdvance;
- // FIXME: The search stops at the boundaries of coreTextRun. In theory, it should go on into neighboring CoreTextRuns
+ CGFloat clusterWidth;
+ // FIXME: The search stops at the boundaries of complexTextRun. In theory, it should go on into neighboring ComplexTextRuns
// derived from the same CTLine. In practice, we do not expect there to be more than one CTRun in a CTLine, as no
// reordering and on font fallback should occur within a CTLine.
if (clusterEnd - clusterStart > 1) {
+ clusterWidth = adjustedAdvance;
int firstGlyphBeforeCluster = j - 1;
- while (firstGlyphBeforeCluster >= 0 && coreTextRun.indexAt(firstGlyphBeforeCluster) >= clusterStart && coreTextRun.indexAt(firstGlyphBeforeCluster) < clusterEnd) {
+ while (firstGlyphBeforeCluster >= 0 && complexTextRun.indexAt(firstGlyphBeforeCluster) >= clusterStart && complexTextRun.indexAt(firstGlyphBeforeCluster) < clusterEnd) {
CGFloat width = m_adjustedAdvances[offsetIntoAdjustedGlyphs + firstGlyphBeforeCluster].width;
clusterWidth += width;
x += width;
firstGlyphBeforeCluster--;
}
unsigned firstGlyphAfterCluster = j + 1;
- while (firstGlyphAfterCluster < coreTextRun.glyphCount() && coreTextRun.indexAt(firstGlyphAfterCluster) >= clusterStart && coreTextRun.indexAt(firstGlyphAfterCluster) < clusterEnd) {
+ while (firstGlyphAfterCluster < complexTextRun.glyphCount() && complexTextRun.indexAt(firstGlyphAfterCluster) >= clusterStart && complexTextRun.indexAt(firstGlyphAfterCluster) < clusterEnd) {
clusterWidth += m_adjustedAdvances[offsetIntoAdjustedGlyphs + firstGlyphAfterCluster].width;
firstGlyphAfterCluster++;
}
+ } else {
+ clusterWidth = adjustedAdvance / (hitGlyphEnd - hitGlyphStart);
+ x -= clusterWidth * (m_run.ltr() ? hitIndex - hitGlyphStart : hitGlyphEnd - hitIndex - 1);
}
if (x <= clusterWidth / 2)
- return coreTextRun.stringLocation() + (m_run.ltr() ? clusterStart : clusterEnd);
+ return complexTextRun.stringLocation() + (m_run.ltr() ? clusterStart : clusterEnd);
else
- return coreTextRun.stringLocation() + (m_run.ltr() ? clusterEnd : clusterStart);
+ return complexTextRun.stringLocation() + (m_run.ltr() ? clusterEnd : clusterStart);
}
x -= adjustedAdvance;
}
- offsetIntoAdjustedGlyphs += coreTextRun.glyphCount();
+ offsetIntoAdjustedGlyphs += complexTextRun.glyphCount();
}
ASSERT_NOT_REACHED();
return 0;
}
-void CoreTextController::collectCoreTextRuns()
+void ComplexTextController::collectComplexTextRuns()
{
if (!m_end)
return;
@@ -227,7 +185,7 @@ void CoreTextController::collectCoreTextRuns()
static const UChar hyphen = '-';
if (hasTrailingSoftHyphen && m_run.rtl()) {
- collectCoreTextRunsForCharacters(&hyphen, 1, m_end - 1, m_font.glyphDataForCharacter(hyphen, false).fontData);
+ collectComplexTextRunsForCharacters(&hyphen, 1, m_end - 1, m_font.glyphDataForCharacter(hyphen, false).fontData);
indexOfFontTransition--;
curr--;
}
@@ -290,7 +248,7 @@ void CoreTextController::collectCoreTextRuns()
if (nextGlyphData.fontData != glyphData.fontData || nextIsSmallCaps != isSmallCaps || !nextGlyphData.glyph != !glyphData.glyph) {
int itemStart = m_run.rtl() ? index + 1 : indexOfFontTransition;
int itemLength = m_run.rtl() ? indexOfFontTransition - index : index - indexOfFontTransition;
- collectCoreTextRunsForCharacters((isSmallCaps ? m_smallCapsBuffer.data() : cp) + itemStart, itemLength, itemStart, glyphData.glyph ? glyphData.fontData : 0);
+ collectComplexTextRunsForCharacters((isSmallCaps ? m_smallCapsBuffer.data() : cp) + itemStart, itemLength, itemStart, glyphData.glyph ? glyphData.fontData : 0);
indexOfFontTransition = index;
}
}
@@ -298,19 +256,15 @@ void CoreTextController::collectCoreTextRuns()
int itemLength = m_run.rtl() ? indexOfFontTransition + 1 : m_end - indexOfFontTransition - (hasTrailingSoftHyphen ? 1 : 0);
if (itemLength) {
int itemStart = m_run.rtl() ? 0 : indexOfFontTransition;
- collectCoreTextRunsForCharacters((nextIsSmallCaps ? m_smallCapsBuffer.data() : cp) + itemStart, itemLength, itemStart, nextGlyphData.glyph ? nextGlyphData.fontData : 0);
+ collectComplexTextRunsForCharacters((nextIsSmallCaps ? m_smallCapsBuffer.data() : cp) + itemStart, itemLength, itemStart, nextGlyphData.glyph ? nextGlyphData.fontData : 0);
}
if (hasTrailingSoftHyphen && m_run.ltr())
- collectCoreTextRunsForCharacters(&hyphen, 1, m_end - 1, m_font.glyphDataForCharacter(hyphen, false).fontData);
+ collectComplexTextRunsForCharacters(&hyphen, 1, m_end - 1, m_font.glyphDataForCharacter(hyphen, false).fontData);
}
-void CoreTextController::advance(unsigned offset, GlyphBuffer* glyphBuffer)
+void ComplexTextController::advance(unsigned offset, GlyphBuffer* glyphBuffer)
{
- // FIXME: For offsets falling inside a ligature, we should advance only as far as the appropriate "ligature caret"
- // or divide the width of the ligature by the number of offsets it encompasses and make an advance proportional
- // to the offsets into the ligature. However, Core Text does not expose a low-level API for
- // directly finding out how many characters a ligature encompasses (the "attachment count").
if (static_cast<int>(offset) > m_end)
offset = m_end;
@@ -319,24 +273,44 @@ void CoreTextController::advance(unsigned offset, GlyphBuffer* glyphBuffer)
m_currentCharacter = offset;
- size_t runCount = m_coreTextRuns.size();
+ size_t runCount = m_complexTextRuns.size();
bool ltr = m_run.ltr();
unsigned k = ltr ? m_numGlyphsSoFar : m_adjustedGlyphs.size() - 1 - m_numGlyphsSoFar;
while (m_currentRun < runCount) {
- const CoreTextRun& coreTextRun = m_coreTextRuns[ltr ? m_currentRun : runCount - 1 - m_currentRun];
- size_t glyphCount = coreTextRun.glyphCount();
+ const ComplexTextRun& complexTextRun = *m_complexTextRuns[ltr ? m_currentRun : runCount - 1 - m_currentRun];
+ size_t glyphCount = complexTextRun.glyphCount();
unsigned g = ltr ? m_glyphInCurrentRun : glyphCount - 1 - m_glyphInCurrentRun;
while (m_glyphInCurrentRun < glyphCount) {
- if (coreTextRun.indexAt(g) + coreTextRun.stringLocation() >= m_currentCharacter)
- return;
+ unsigned glyphStartOffset = complexTextRun.indexAt(g);
+ unsigned glyphEndOffset;
+ if (ltr)
+ glyphEndOffset = max<unsigned>(glyphStartOffset, g + 1 < glyphCount ? complexTextRun.indexAt(g + 1) : complexTextRun.stringLength());
+ else
+ glyphEndOffset = max<unsigned>(glyphStartOffset, g > 0 ? complexTextRun.indexAt(g - 1) : complexTextRun.stringLength());
+
CGSize adjustedAdvance = m_adjustedAdvances[k];
- if (glyphBuffer)
- glyphBuffer->add(m_adjustedGlyphs[k], coreTextRun.fontData(), adjustedAdvance);
- m_runWidthSoFar += adjustedAdvance.width;
+
+ if (glyphStartOffset + complexTextRun.stringLocation() >= m_currentCharacter)
+ return;
+
+ if (glyphBuffer && !m_characterInCurrentGlyph)
+ glyphBuffer->add(m_adjustedGlyphs[k], complexTextRun.fontData(), adjustedAdvance);
+
+ unsigned oldCharacterInCurrentGlyph = m_characterInCurrentGlyph;
+ m_characterInCurrentGlyph = min(m_currentCharacter - complexTextRun.stringLocation(), glyphEndOffset) - glyphStartOffset;
+ // FIXME: Instead of dividing the glyph's advance equially between the characters, this
+ // could use the glyph's "ligature carets". However, there is no Core Text API to get the
+ // ligature carets.
+ m_runWidthSoFar += adjustedAdvance.width * (m_characterInCurrentGlyph - oldCharacterInCurrentGlyph) / (glyphEndOffset - glyphStartOffset);
+
+ if (glyphEndOffset + complexTextRun.stringLocation() > m_currentCharacter)
+ return;
+
m_numGlyphsSoFar++;
m_glyphInCurrentRun++;
+ m_characterInCurrentGlyph = 0;
if (ltr) {
g++;
k++;
@@ -352,100 +326,35 @@ void CoreTextController::advance(unsigned offset, GlyphBuffer* glyphBuffer)
m_runWidthSoFar += m_finalRoundingWidth;
}
-void CoreTextController::collectCoreTextRunsForCharacters(const UChar* cp, unsigned length, unsigned stringLocation, const SimpleFontData* fontData)
-{
- if (!fontData) {
- // Create a run of missing glyphs from the primary font.
- m_coreTextRuns.append(CoreTextRun(m_font.primaryFont(), cp, stringLocation, length, m_run.ltr()));
- return;
- }
-
- if (m_fallbackFonts && fontData != m_font.primaryFont())
- m_fallbackFonts->add(fontData);
-
- RetainPtr<CFStringRef> string(AdoptCF, CFStringCreateWithCharactersNoCopy(NULL, cp, length, kCFAllocatorNull));
-
- RetainPtr<CFAttributedStringRef> attributedString(AdoptCF, CFAttributedStringCreate(NULL, string.get(), fontData->getCFStringAttributes(m_font.fontDescription().textRenderingMode())));
-
- RetainPtr<CTTypesetterRef> typesetter;
-
- if (!m_mayUseNaturalWritingDirection || m_run.directionalOverride()) {
- static const void* optionKeys[] = { kCTTypesetterOptionForcedEmbeddingLevel };
- static const void* ltrOptionValues[] = { kCFBooleanFalse };
- static const void* rtlOptionValues[] = { kCFBooleanTrue };
- static CFDictionaryRef ltrTypesetterOptions = CFDictionaryCreate(kCFAllocatorDefault, optionKeys, ltrOptionValues, sizeof(optionKeys) / sizeof(*optionKeys), &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
- static CFDictionaryRef rtlTypesetterOptions = CFDictionaryCreate(kCFAllocatorDefault, optionKeys, rtlOptionValues, sizeof(optionKeys) / sizeof(*optionKeys), &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
- typesetter.adoptCF(CTTypesetterCreateWithAttributedStringAndOptions(attributedString.get(), m_run.ltr() ? ltrTypesetterOptions : rtlTypesetterOptions));
- } else
- typesetter.adoptCF(CTTypesetterCreateWithAttributedString(attributedString.get()));
-
- RetainPtr<CTLineRef> line(AdoptCF, CTTypesetterCreateLine(typesetter.get(), CFRangeMake(0, 0)));
-
- CFArrayRef runArray = CTLineGetGlyphRuns(line.get());
-
- CFIndex runCount = CFArrayGetCount(runArray);
-
- for (CFIndex r = 0; r < runCount; r++) {
- CTRunRef ctRun = static_cast<CTRunRef>(CFArrayGetValueAtIndex(runArray, r));
- ASSERT(CFGetTypeID(ctRun) == CTRunGetTypeID());
- m_coreTextRuns.append(CoreTextRun(ctRun, fontData, cp, stringLocation, length));
- }
-}
-
-void CoreTextController::adjustGlyphsAndAdvances()
+void ComplexTextController::adjustGlyphsAndAdvances()
{
- size_t runCount = m_coreTextRuns.size();
+ size_t runCount = m_complexTextRuns.size();
for (size_t r = 0; r < runCount; ++r) {
- const CoreTextRun& coreTextRun = m_coreTextRuns[r];
- unsigned glyphCount = coreTextRun.glyphCount();
- const SimpleFontData* fontData = coreTextRun.fontData();
-
- Vector<CGGlyph, 256> glyphsVector;
- const CGGlyph* glyphs;
-
- Vector<CGSize, 256> advancesVector;
- const CGSize* advances;
-
- if (coreTextRun.ctRun()) {
- glyphs = CTRunGetGlyphsPtr(coreTextRun.ctRun());
- if (!glyphs) {
- glyphsVector.grow(glyphCount);
- CTRunGetGlyphs(coreTextRun.ctRun(), CFRangeMake(0, 0), glyphsVector.data());
- glyphs = glyphsVector.data();
- }
+ const ComplexTextRun& complexTextRun = *m_complexTextRuns[r];
+ unsigned glyphCount = complexTextRun.glyphCount();
+ const SimpleFontData* fontData = complexTextRun.fontData();
- advances = CTRunGetAdvancesPtr(coreTextRun.ctRun());
- if (!advances) {
- advancesVector.grow(glyphCount);
- CTRunGetAdvances(coreTextRun.ctRun(), CFRangeMake(0, 0), advancesVector.data());
- advances = advancesVector.data();
- }
- } else {
- // Synthesize a run of missing glyphs.
- glyphsVector.fill(0, glyphCount);
- glyphs = glyphsVector.data();
- advancesVector.fill(CGSizeMake(fontData->widthForGlyph(0), 0), glyphCount);
- advances = advancesVector.data();
- }
+ const CGGlyph* glyphs = complexTextRun.glyphs();
+ const CGSize* advances = complexTextRun.advances();
bool lastRun = r + 1 == runCount;
- const UChar* cp = coreTextRun.characters();
+ const UChar* cp = complexTextRun.characters();
CGFloat roundedSpaceWidth = roundCGFloat(fontData->spaceWidth());
bool roundsAdvances = !m_font.isPrinterFont() && fontData->platformData().roundsGlyphAdvances();
bool hasExtraSpacing = (m_font.letterSpacing() || m_font.wordSpacing() || m_padding) && !m_run.spacingDisabled();
for (unsigned i = 0; i < glyphCount; i++) {
- CFIndex characterIndex = coreTextRun.indexAt(i);
+ CFIndex characterIndex = complexTextRun.indexAt(i);
UChar ch = *(cp + characterIndex);
bool lastGlyph = lastRun && i + 1 == glyphCount;
UChar nextCh;
if (lastGlyph)
nextCh = ' ';
else if (i + 1 < glyphCount)
- nextCh = *(cp + coreTextRun.indexAt(i + 1));
+ nextCh = *(cp + complexTextRun.indexAt(i + 1));
else
- nextCh = *(m_coreTextRuns[r + 1].characters() + m_coreTextRuns[r + 1].indexAt(0));
+ nextCh = *(m_complexTextRuns[r + 1]->characters() + m_complexTextRuns[r + 1]->indexAt(0));
bool treatAsSpace = Font::treatAsSpace(ch);
CGGlyph glyph = treatAsSpace ? fontData->spaceGlyph() : glyphs[i];
@@ -533,5 +442,3 @@ void CoreTextController::adjustGlyphsAndAdvances()
}
} // namespace WebCore
-
-#endif // USE(CORE_TEXT)
diff --git a/WebCore/platform/graphics/mac/ComplexTextController.h b/WebCore/platform/graphics/mac/ComplexTextController.h
new file mode 100644
index 0000000..7a915e2
--- /dev/null
+++ b/WebCore/platform/graphics/mac/ComplexTextController.h
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2007, 2008, 2009 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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.
+ */
+
+#ifndef ComplexTextController_h
+#define ComplexTextController_h
+
+#include "GlyphBuffer.h"
+#include <wtf/HashSet.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RetainPtr.h>
+#include <wtf/Vector.h>
+#include <wtf/unicode/Unicode.h>
+
+namespace WebCore {
+
+class Font;
+class SimpleFontData;
+class TextRun;
+
+class ComplexTextController {
+public:
+ ComplexTextController(const Font*, const TextRun&, bool mayUseNaturalWritingDirection = false, HashSet<const SimpleFontData*>* fallbackFonts = 0);
+
+ // Advance and emit glyphs up to the specified character.
+ void advance(unsigned to, GlyphBuffer* = 0);
+
+ // Compute the character offset for a given x coordinate.
+ int offsetForPosition(int x, bool includePartialGlyphs);
+
+ // Returns the width of everything we've consumed so far.
+ float runWidthSoFar() const { return m_runWidthSoFar; }
+
+ float totalWidth() const { return m_totalWidth; }
+
+ // Extra width to the left of the leftmost glyph.
+ float finalRoundingWidth() const { return m_finalRoundingWidth; }
+
+private:
+ class ComplexTextRun : public RefCounted<ComplexTextRun> {
+ public:
+#if USE(CORE_TEXT)
+ static PassRefPtr<ComplexTextRun> create(CTRunRef ctRun, const SimpleFontData* fontData, const UChar* characters, unsigned stringLocation, size_t stringLength)
+ {
+ return adoptRef(new ComplexTextRun(ctRun, fontData, characters, stringLocation, stringLength));
+ }
+#elif USE(ATSUI)
+ static PassRefPtr<ComplexTextRun> create(ATSUTextLayout atsuTextLayout, const SimpleFontData* fontData, const UChar* characters, unsigned stringLocation, size_t stringLength, bool ltr, bool directionalOverride)
+ {
+ return adoptRef(new ComplexTextRun(atsuTextLayout, fontData, characters, stringLocation, stringLength, ltr, directionalOverride));
+ }
+#endif
+ static PassRefPtr<ComplexTextRun> create(const SimpleFontData* fontData, const UChar* characters, unsigned stringLocation, size_t stringLength, bool ltr)
+ {
+ return adoptRef(new ComplexTextRun(fontData, characters, stringLocation, stringLength, ltr));
+ }
+
+ unsigned glyphCount() const { return m_glyphCount; }
+ const SimpleFontData* fontData() const { return m_fontData; }
+ const UChar* characters() const { return m_characters; }
+ unsigned stringLocation() const { return m_stringLocation; }
+ size_t stringLength() const { return m_stringLength; }
+ CFIndex indexAt(size_t i) const { return m_indices[i]; }
+ const CGGlyph* glyphs() const { return m_glyphs; }
+ const CGSize* advances() const { return m_advances; }
+
+ private:
+#if USE(CORE_TEXT)
+ ComplexTextRun(CTRunRef, const SimpleFontData*, const UChar* characters, unsigned stringLocation, size_t stringLength);
+#elif USE(ATSUI)
+ ComplexTextRun(ATSUTextLayout, const SimpleFontData*, const UChar* characters, unsigned stringLocation, size_t stringLength, bool ltr, bool directionalOverride);
+#endif
+ ComplexTextRun(const SimpleFontData*, const UChar* characters, unsigned stringLocation, size_t stringLength, bool ltr);
+
+#if USE(ATSUI)
+#ifdef BUILDING_ON_TIGER
+ typedef UInt32 URefCon;
+#endif
+ static OSStatus overrideLayoutOperation(ATSULayoutOperationSelector, ATSULineRef, URefCon, void*, ATSULayoutOperationCallbackStatus*);
+#endif
+
+#if USE(CORE_TEXT)
+ RetainPtr<CTRunRef> m_CTRun;
+#endif
+ unsigned m_glyphCount;
+ const SimpleFontData* m_fontData;
+ const UChar* m_characters;
+ unsigned m_stringLocation;
+ size_t m_stringLength;
+#if USE(CORE_TEXT)
+ RetainPtr<CFMutableDataRef> m_indicesData;
+ const CFIndex* m_indices;
+#elif USE(ATSUI)
+ Vector<CFIndex, 64> m_indices;
+#endif
+ Vector<CGGlyph, 64> m_glyphsVector;
+ const CGGlyph* m_glyphs;
+ Vector<CGSize, 64> m_advancesVector;
+ const CGSize* m_advances;
+#if USE(ATSUI)
+ bool m_ltr;
+ bool m_directionalOverride;
+#endif
+ };
+
+ void collectComplexTextRuns();
+ void collectComplexTextRunsForCharacters(const UChar*, unsigned length, unsigned stringLocation, const SimpleFontData*);
+ void adjustGlyphsAndAdvances();
+
+ const Font& m_font;
+ const TextRun& m_run;
+ bool m_mayUseNaturalWritingDirection;
+
+ Vector<UChar, 256> m_smallCapsBuffer;
+
+ Vector<RefPtr<ComplexTextRun>, 16> m_complexTextRuns;
+ Vector<CGSize, 256> m_adjustedAdvances;
+ Vector<CGGlyph, 256> m_adjustedGlyphs;
+
+ unsigned m_currentCharacter;
+ int m_end;
+
+ CGFloat m_totalWidth;
+
+ float m_runWidthSoFar;
+ unsigned m_numGlyphsSoFar;
+ size_t m_currentRun;
+ unsigned m_glyphInCurrentRun;
+ unsigned m_characterInCurrentGlyph;
+ float m_finalRoundingWidth;
+ float m_padding;
+ float m_padPerSpace;
+
+ HashSet<const SimpleFontData*>* m_fallbackFonts;
+
+ unsigned m_lastRoundingGlyph;
+};
+
+} // namespace WebCore
+
+#endif // ComplexTextController_h
diff --git a/WebCore/platform/graphics/mac/ComplexTextControllerATSUI.cpp b/WebCore/platform/graphics/mac/ComplexTextControllerATSUI.cpp
new file mode 100644
index 0000000..78c588f
--- /dev/null
+++ b/WebCore/platform/graphics/mac/ComplexTextControllerATSUI.cpp
@@ -0,0 +1,341 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (C) 2000 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2003, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "ComplexTextController.h"
+
+#if USE(ATSUI)
+
+#include "CharacterNames.h"
+#include "Font.h"
+#include "ShapeArabic.h"
+
+#ifdef __LP64__
+// ATSUTextInserted() is SPI in 64-bit.
+extern "C" {
+OSStatus ATSUTextInserted(ATSUTextLayout iTextLayout, UniCharArrayOffset iInsertionLocation, UniCharCount iInsertionLength);
+}
+#endif
+
+using namespace WTF::Unicode;
+
+namespace WebCore {
+
+OSStatus ComplexTextController::ComplexTextRun::overrideLayoutOperation(ATSULayoutOperationSelector, ATSULineRef atsuLineRef, URefCon refCon, void*, ATSULayoutOperationCallbackStatus* callbackStatus)
+{
+ ComplexTextRun* complexTextRun = reinterpret_cast<ComplexTextRun*>(refCon);
+ OSStatus status;
+ ItemCount count;
+ ATSLayoutRecord *layoutRecords;
+
+ status = ATSUDirectGetLayoutDataArrayPtrFromLineRef(atsuLineRef, kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, true, reinterpret_cast<void**>(&layoutRecords), &count);
+ if (status != noErr) {
+ *callbackStatus = kATSULayoutOperationCallbackStatusContinue;
+ return status;
+ }
+
+ count--;
+ ItemCount j = 0;
+ CFIndex indexOffset = 0;
+
+ if (complexTextRun->m_directionalOverride) {
+ j++;
+ count -= 2;
+ indexOffset = -1;
+ }
+
+ complexTextRun->m_glyphCount = count;
+ complexTextRun->m_glyphsVector.reserveCapacity(count);
+ complexTextRun->m_advancesVector.reserveCapacity(count);
+ complexTextRun->m_indices.reserveCapacity(count);
+
+ bool atBeginning = true;
+ CGFloat lastX = 0;
+
+ for (ItemCount i = 0; i < count; ++i, ++j) {
+ if (layoutRecords[j].glyphID == kATSDeletedGlyphcode) {
+ complexTextRun->m_glyphCount--;
+ continue;
+ }
+ complexTextRun->m_glyphsVector.uncheckedAppend(layoutRecords[j].glyphID);
+ complexTextRun->m_indices.uncheckedAppend(layoutRecords[j].originalOffset / 2 + indexOffset);
+ CGFloat x = FixedToFloat(layoutRecords[j].realPos);
+ if (!atBeginning)
+ complexTextRun->m_advancesVector.uncheckedAppend(CGSizeMake(x - lastX, 0));
+ lastX = x;
+ atBeginning = false;
+ }
+
+ complexTextRun->m_advancesVector.uncheckedAppend(CGSizeMake(FixedToFloat(layoutRecords[j].realPos) - lastX, 0));
+
+ complexTextRun->m_glyphs = complexTextRun->m_glyphsVector.data();
+ complexTextRun->m_advances = complexTextRun->m_advancesVector.data();
+
+ status = ATSUDirectReleaseLayoutDataArrayPtr(atsuLineRef, kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, reinterpret_cast<void**>(&layoutRecords));
+ *callbackStatus = kATSULayoutOperationCallbackStatusContinue;
+ return noErr;
+}
+
+static inline bool isArabicLamWithAlefLigature(UChar c)
+{
+ return c >= 0xfef5 && c <= 0xfefc;
+}
+
+static void shapeArabic(const UChar* source, UChar* dest, unsigned totalLength)
+{
+ unsigned shapingStart = 0;
+ while (shapingStart < totalLength) {
+ unsigned shapingEnd;
+ // We do not want to pass a Lam with Alef ligature followed by a space to the shaper,
+ // since we want to be able to identify this sequence as the result of shaping a Lam
+ // followed by an Alef and padding with a space.
+ bool foundLigatureSpace = false;
+ for (shapingEnd = shapingStart; !foundLigatureSpace && shapingEnd < totalLength - 1; ++shapingEnd)
+ foundLigatureSpace = isArabicLamWithAlefLigature(source[shapingEnd]) && source[shapingEnd + 1] == ' ';
+ shapingEnd++;
+
+ UErrorCode shapingError = U_ZERO_ERROR;
+ unsigned charsWritten = shapeArabic(source + shapingStart, shapingEnd - shapingStart, dest + shapingStart, shapingEnd - shapingStart, U_SHAPE_LETTERS_SHAPE | U_SHAPE_LENGTH_FIXED_SPACES_NEAR, &shapingError);
+
+ if (U_SUCCESS(shapingError) && charsWritten == shapingEnd - shapingStart) {
+ for (unsigned j = shapingStart; j < shapingEnd - 1; ++j) {
+ if (isArabicLamWithAlefLigature(dest[j]) && dest[j + 1] == ' ')
+ dest[++j] = zeroWidthSpace;
+ }
+ if (foundLigatureSpace) {
+ dest[shapingEnd] = ' ';
+ shapingEnd++;
+ } else if (isArabicLamWithAlefLigature(dest[shapingEnd - 1])) {
+ // u_shapeArabic quirk: if the last two characters in the source string are a Lam and an Alef,
+ // the space is put at the beginning of the string, despite U_SHAPE_LENGTH_FIXED_SPACES_NEAR.
+ ASSERT(dest[shapingStart] == ' ');
+ dest[shapingStart] = zeroWidthSpace;
+ }
+ } else {
+ // Something went wrong. Abandon shaping and just copy the rest of the buffer.
+ LOG_ERROR("u_shapeArabic failed(%d)", shapingError);
+ shapingEnd = totalLength;
+ memcpy(dest + shapingStart, source + shapingStart, (shapingEnd - shapingStart) * sizeof(UChar));
+ }
+ shapingStart = shapingEnd;
+ }
+}
+
+ComplexTextController::ComplexTextRun::ComplexTextRun(ATSUTextLayout atsuTextLayout, const SimpleFontData* fontData, const UChar* characters, unsigned stringLocation, size_t stringLength, bool ltr, bool directionalOverride)
+ : m_fontData(fontData)
+ , m_characters(characters)
+ , m_stringLocation(stringLocation)
+ , m_stringLength(stringLength)
+ , m_ltr(ltr)
+ , m_directionalOverride(directionalOverride)
+{
+ OSStatus status;
+
+ status = ATSUSetTextLayoutRefCon(atsuTextLayout, reinterpret_cast<URefCon>(this));
+
+ ATSLineLayoutOptions lineLayoutOptions = kATSLineKeepSpacesOutOfMargin | kATSLineHasNoHangers;
+
+ Boolean rtl = !ltr;
+
+ Vector<UChar, 256> substituteCharacters;
+ bool shouldCheckForMirroring = !ltr && !fontData->m_ATSUMirrors;
+ bool shouldCheckForArabic = !fontData->shapesArabic();
+ bool shouldShapeArabic = false;
+
+ bool mirrored = false;
+ for (size_t i = 0; i < stringLength; ++i) {
+ if (shouldCheckForMirroring) {
+ UChar mirroredChar = u_charMirror(characters[i]);
+ if (mirroredChar != characters[i]) {
+ if (!mirrored) {
+ mirrored = true;
+ substituteCharacters.grow(stringLength);
+ memcpy(substituteCharacters.data(), characters, stringLength * sizeof(UChar));
+ ATSUTextMoved(atsuTextLayout, substituteCharacters.data());
+ }
+ substituteCharacters[i] = mirroredChar;
+ }
+ }
+ if (shouldCheckForArabic && isArabicChar(characters[i])) {
+ shouldCheckForArabic = false;
+ shouldShapeArabic = true;
+ }
+ }
+
+ if (shouldShapeArabic) {
+ Vector<UChar, 256> shapedArabic(stringLength);
+ shapeArabic(substituteCharacters.isEmpty() ? characters : substituteCharacters.data(), shapedArabic.data(), stringLength);
+ substituteCharacters.swap(shapedArabic);
+ ATSUTextMoved(atsuTextLayout, substituteCharacters.data());
+ }
+
+ if (directionalOverride) {
+ UChar override = ltr ? leftToRightOverride : rightToLeftOverride;
+ if (substituteCharacters.isEmpty()) {
+ substituteCharacters.grow(stringLength + 2);
+ substituteCharacters[0] = override;
+ memcpy(substituteCharacters.data() + 1, characters, stringLength * sizeof(UChar));
+ substituteCharacters[stringLength + 1] = popDirectionalFormatting;
+ ATSUTextMoved(atsuTextLayout, substituteCharacters.data());
+ } else {
+ substituteCharacters.prepend(override);
+ substituteCharacters.append(popDirectionalFormatting);
+ }
+ ATSUTextInserted(atsuTextLayout, 0, 2);
+ }
+
+ ATSULayoutOperationOverrideSpecifier overrideSpecifier;
+ overrideSpecifier.operationSelector = kATSULayoutOperationPostLayoutAdjustment;
+ overrideSpecifier.overrideUPP = overrideLayoutOperation;
+
+ ATSUAttributeTag tags[] = { kATSULineLayoutOptionsTag, kATSULineDirectionTag, kATSULayoutOperationOverrideTag };
+ ByteCount sizes[] = { sizeof(ATSLineLayoutOptions), sizeof(Boolean), sizeof(ATSULayoutOperationOverrideSpecifier) };
+ ATSUAttributeValuePtr values[] = { &lineLayoutOptions, &rtl, &overrideSpecifier };
+
+ status = ATSUSetLayoutControls(atsuTextLayout, 3, tags, sizes, values);
+
+ ItemCount boundsCount;
+ status = ATSUGetGlyphBounds(atsuTextLayout, 0, 0, 0, m_stringLength, kATSUseFractionalOrigins, 0, 0, &boundsCount);
+
+ status = ATSUDisposeTextLayout(atsuTextLayout);
+}
+
+ComplexTextController::ComplexTextRun::ComplexTextRun(const SimpleFontData* fontData, const UChar* characters, unsigned stringLocation, size_t stringLength, bool ltr)
+ : m_fontData(fontData)
+ , m_characters(characters)
+ , m_stringLocation(stringLocation)
+ , m_stringLength(stringLength)
+{
+ m_indices.reserveCapacity(stringLength);
+ unsigned r = 0;
+ while (r < stringLength) {
+ m_indices.uncheckedAppend(r);
+ if (U_IS_SURROGATE(characters[r])) {
+ ASSERT(r + 1 < stringLength);
+ ASSERT(U_IS_SURROGATE_LEAD(characters[r]));
+ ASSERT(U_IS_TRAIL(characters[r + 1]));
+ r += 2;
+ } else
+ r++;
+ }
+ m_glyphCount = m_indices.size();
+ if (!ltr) {
+ for (unsigned r = 0, end = m_glyphCount - 1; r < m_glyphCount / 2; ++r, --end)
+ std::swap(m_indices[r], m_indices[end]);
+ }
+
+ m_glyphsVector.fill(0, m_glyphCount);
+ m_glyphs = m_glyphsVector.data();
+ m_advancesVector.fill(CGSizeMake(fontData->widthForGlyph(0), 0), m_glyphCount);
+ m_advances = m_advancesVector.data();
+}
+
+static bool fontHasMirroringInfo(ATSUFontID fontID)
+{
+ ByteCount propTableSize;
+ OSStatus status = ATSFontGetTable(fontID, 'prop', 0, 0, 0, &propTableSize);
+ if (status == noErr) // naively assume that if a 'prop' table exists then it contains mirroring info
+ return true;
+ else if (status != kATSInvalidFontTableAccess) // anything other than a missing table is logged as an error
+ LOG_ERROR("ATSFontGetTable failed (%d)", static_cast<int>(status));
+
+ return false;
+}
+
+static void disableLigatures(const SimpleFontData* fontData, TextRenderingMode textMode)
+{
+ // Don't be too aggressive: if the font doesn't contain 'a', then assume that any ligatures it contains are
+ // in characters that always go through ATSUI, and therefore allow them. Geeza Pro is an example.
+ // See bugzilla 5166.
+ if (textMode == OptimizeLegibility || textMode == GeometricPrecision || fontData->platformData().allowsLigatures())
+ return;
+
+ ATSUFontFeatureType featureTypes[] = { kLigaturesType };
+ ATSUFontFeatureSelector featureSelectors[] = { kCommonLigaturesOffSelector };
+ OSStatus status = ATSUSetFontFeatures(fontData->m_ATSUStyle, 1, featureTypes, featureSelectors);
+ if (status != noErr)
+ LOG_ERROR("ATSUSetFontFeatures failed (%d) -- ligatures remain enabled", static_cast<int>(status));
+}
+
+static void initializeATSUStyle(const SimpleFontData* fontData, TextRenderingMode textMode)
+{
+ if (fontData->m_ATSUStyleInitialized)
+ return;
+
+ ATSUFontID fontID = fontData->platformData().m_atsuFontID;
+ if (!fontID) {
+ LOG_ERROR("unable to get ATSUFontID for %p", fontData->platformData().font());
+ return;
+ }
+
+ OSStatus status = ATSUCreateStyle(&fontData->m_ATSUStyle);
+ if (status != noErr)
+ LOG_ERROR("ATSUCreateStyle failed (%d)", static_cast<int>(status));
+
+ Fixed fontSize = FloatToFixed(fontData->platformData().m_size);
+ Fract kerningInhibitFactor = FloatToFract(1);
+ static CGAffineTransform verticalFlip = CGAffineTransformMakeScale(1, -1);
+
+ ByteCount styleSizes[4] = { sizeof(fontSize), sizeof(fontID), sizeof(verticalFlip), sizeof(kerningInhibitFactor) };
+ ATSUAttributeTag styleTags[4] = { kATSUSizeTag, kATSUFontTag, kATSUFontMatrixTag, kATSUKerningInhibitFactorTag };
+ ATSUAttributeValuePtr styleValues[4] = { &fontSize, &fontID, &verticalFlip, &kerningInhibitFactor };
+
+ bool allowKerning = textMode == OptimizeLegibility || textMode == GeometricPrecision;
+ status = ATSUSetAttributes(fontData->m_ATSUStyle, allowKerning ? 3 : 4, styleTags, styleSizes, styleValues);
+ if (status != noErr)
+ LOG_ERROR("ATSUSetAttributes failed (%d)", static_cast<int>(status));
+
+ fontData->m_ATSUMirrors = fontHasMirroringInfo(fontID);
+
+ disableLigatures(fontData, textMode);
+
+ fontData->m_ATSUStyleInitialized = true;
+}
+
+void ComplexTextController::collectComplexTextRunsForCharacters(const UChar* cp, unsigned length, unsigned stringLocation, const SimpleFontData* fontData)
+{
+ if (!fontData) {
+ // Create a run of missing glyphs from the primary font.
+ m_complexTextRuns.append(ComplexTextRun::create(m_font.primaryFont(), cp, stringLocation, length, m_run.ltr()));
+ return;
+ }
+
+ if (m_fallbackFonts && fontData != m_font.primaryFont())
+ m_fallbackFonts->add(fontData);
+
+ initializeATSUStyle(fontData, m_font.fontDescription().textRenderingMode());
+
+ OSStatus status;
+ ATSUTextLayout atsuTextLayout;
+ UniCharCount runLength = length;
+
+ status = ATSUCreateTextLayoutWithTextPtr(cp, 0, length, length, 1, &runLength, &fontData->m_ATSUStyle, &atsuTextLayout);
+ if (status != noErr) {
+ LOG_ERROR("ATSUCreateTextLayoutWithTextPtr failed with error %d", static_cast<int>(status));
+ return;
+ }
+ m_complexTextRuns.append(ComplexTextRun::create(atsuTextLayout, fontData, cp, stringLocation, length, m_run.ltr(), m_run.directionalOverride()));
+}
+
+} // namespace WebCore
+
+#endif // USE(ATSUI)
diff --git a/WebCore/platform/graphics/mac/ComplexTextControllerCoreText.cpp b/WebCore/platform/graphics/mac/ComplexTextControllerCoreText.cpp
new file mode 100644
index 0000000..c9daf84
--- /dev/null
+++ b/WebCore/platform/graphics/mac/ComplexTextControllerCoreText.cpp
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2007, 2008, 2009 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "ComplexTextController.h"
+
+#if USE(CORE_TEXT)
+
+#include "Font.h"
+
+namespace WebCore {
+
+ComplexTextController::ComplexTextRun::ComplexTextRun(CTRunRef ctRun, const SimpleFontData* fontData, const UChar* characters, unsigned stringLocation, size_t stringLength)
+ : m_CTRun(ctRun)
+ , m_fontData(fontData)
+ , m_characters(characters)
+ , m_stringLocation(stringLocation)
+ , m_stringLength(stringLength)
+{
+ m_glyphCount = CTRunGetGlyphCount(m_CTRun.get());
+ m_indices = CTRunGetStringIndicesPtr(m_CTRun.get());
+ if (!m_indices) {
+ m_indicesData.adoptCF(CFDataCreateMutable(kCFAllocatorDefault, m_glyphCount * sizeof(CFIndex)));
+ CFDataIncreaseLength(m_indicesData.get(), m_glyphCount * sizeof(CFIndex));
+ m_indices = reinterpret_cast<const CFIndex*>(CFDataGetMutableBytePtr(m_indicesData.get()));
+ CTRunGetStringIndices(m_CTRun.get(), CFRangeMake(0, 0), const_cast<CFIndex*>(m_indices));
+ }
+
+ m_glyphs = CTRunGetGlyphsPtr(m_CTRun.get());
+ if (!m_glyphs) {
+ m_glyphsVector.grow(m_glyphCount);
+ CTRunGetGlyphs(m_CTRun.get(), CFRangeMake(0, 0), m_glyphsVector.data());
+ m_glyphs = m_glyphsVector.data();
+ }
+
+ m_advances = CTRunGetAdvancesPtr(m_CTRun.get());
+ if (!m_advances) {
+ m_advancesVector.grow(m_glyphCount);
+ CTRunGetAdvances(m_CTRun.get(), CFRangeMake(0, 0), m_advancesVector.data());
+ m_advances = m_advancesVector.data();
+ }
+
+}
+
+// Missing glyphs run constructor. Core Text will not generate a run of missing glyphs, instead falling back on
+// glyphs from LastResort. We want to use the primary font's missing glyph in order to match the fast text code path.
+ComplexTextController::ComplexTextRun::ComplexTextRun(const SimpleFontData* fontData, const UChar* characters, unsigned stringLocation, size_t stringLength, bool ltr)
+ : m_fontData(fontData)
+ , m_characters(characters)
+ , m_stringLocation(stringLocation)
+ , m_stringLength(stringLength)
+{
+ Vector<CFIndex, 16> indices;
+ unsigned r = 0;
+ while (r < stringLength) {
+ indices.append(r);
+ if (U_IS_SURROGATE(characters[r])) {
+ ASSERT(r + 1 < stringLength);
+ ASSERT(U_IS_SURROGATE_LEAD(characters[r]));
+ ASSERT(U_IS_TRAIL(characters[r + 1]));
+ r += 2;
+ } else
+ r++;
+ }
+ m_glyphCount = indices.size();
+ if (!ltr) {
+ for (unsigned r = 0, end = m_glyphCount - 1; r < m_glyphCount / 2; ++r, --end)
+ std::swap(indices[r], indices[end]);
+ }
+ m_indicesData.adoptCF(CFDataCreateMutable(kCFAllocatorDefault, m_glyphCount * sizeof(CFIndex)));
+ CFDataAppendBytes(m_indicesData.get(), reinterpret_cast<const UInt8*>(indices.data()), m_glyphCount * sizeof(CFIndex));
+ m_indices = reinterpret_cast<const CFIndex*>(CFDataGetBytePtr(m_indicesData.get()));
+
+ // Synthesize a run of missing glyphs.
+ m_glyphsVector.fill(0, m_glyphCount);
+ m_glyphs = m_glyphsVector.data();
+ m_advancesVector.fill(CGSizeMake(m_fontData->widthForGlyph(0), 0), m_glyphCount);
+ m_advances = m_advancesVector.data();
+}
+
+void ComplexTextController::collectComplexTextRunsForCharacters(const UChar* cp, unsigned length, unsigned stringLocation, const SimpleFontData* fontData)
+{
+ if (!fontData) {
+ // Create a run of missing glyphs from the primary font.
+ m_complexTextRuns.append(ComplexTextRun::create(m_font.primaryFont(), cp, stringLocation, length, m_run.ltr()));
+ return;
+ }
+
+ if (m_fallbackFonts && fontData != m_font.primaryFont())
+ m_fallbackFonts->add(fontData);
+
+ RetainPtr<CFStringRef> string(AdoptCF, CFStringCreateWithCharactersNoCopy(NULL, cp, length, kCFAllocatorNull));
+
+ RetainPtr<CFAttributedStringRef> attributedString(AdoptCF, CFAttributedStringCreate(NULL, string.get(), fontData->getCFStringAttributes(m_font.fontDescription().textRenderingMode())));
+
+ RetainPtr<CTTypesetterRef> typesetter;
+
+ if (!m_mayUseNaturalWritingDirection || m_run.directionalOverride()) {
+ static const void* optionKeys[] = { kCTTypesetterOptionForcedEmbeddingLevel };
+ static const void* ltrOptionValues[] = { kCFBooleanFalse };
+ static const void* rtlOptionValues[] = { kCFBooleanTrue };
+ static CFDictionaryRef ltrTypesetterOptions = CFDictionaryCreate(kCFAllocatorDefault, optionKeys, ltrOptionValues, sizeof(optionKeys) / sizeof(*optionKeys), &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ static CFDictionaryRef rtlTypesetterOptions = CFDictionaryCreate(kCFAllocatorDefault, optionKeys, rtlOptionValues, sizeof(optionKeys) / sizeof(*optionKeys), &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ typesetter.adoptCF(CTTypesetterCreateWithAttributedStringAndOptions(attributedString.get(), m_run.ltr() ? ltrTypesetterOptions : rtlTypesetterOptions));
+ } else
+ typesetter.adoptCF(CTTypesetterCreateWithAttributedString(attributedString.get()));
+
+ RetainPtr<CTLineRef> line(AdoptCF, CTTypesetterCreateLine(typesetter.get(), CFRangeMake(0, 0)));
+
+ CFArrayRef runArray = CTLineGetGlyphRuns(line.get());
+
+ CFIndex runCount = CFArrayGetCount(runArray);
+
+ for (CFIndex r = 0; r < runCount; r++) {
+ CTRunRef ctRun = static_cast<CTRunRef>(CFArrayGetValueAtIndex(runArray, r));
+ ASSERT(CFGetTypeID(ctRun) == CTRunGetTypeID());
+ m_complexTextRuns.append(ComplexTextRun::create(ctRun, fontData, cp, stringLocation, length));
+ }
+}
+
+} // namespace WebCore
+
+#endif // USE(CORE_TEXT)
diff --git a/WebCore/platform/graphics/mac/CoreTextController.h b/WebCore/platform/graphics/mac/CoreTextController.h
deleted file mode 100644
index 4dd6f93..0000000
--- a/WebCore/platform/graphics/mac/CoreTextController.h
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright (C) 2007, 2008 Apple 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:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. 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.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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.
- */
-
-#ifndef CoreTextController_h
-#define CoreTextController_h
-
-#if USE(CORE_TEXT)
-
-#include "Font.h"
-#include "GlyphBuffer.h"
-#include <wtf/RetainPtr.h>
-#include <wtf/Vector.h>
-
-namespace WebCore {
-
-class CoreTextController {
-public:
- CoreTextController(const Font*, const TextRun&, bool mayUseNaturalWritingDirection = false, HashSet<const SimpleFontData*>* fallbackFonts = 0);
-
- // Advance and emit glyphs up to the specified character.
- void advance(unsigned to, GlyphBuffer* = 0);
-
- // Compute the character offset for a given x coordinate.
- int offsetForPosition(int x, bool includePartialGlyphs);
-
- // Returns the width of everything we've consumed so far.
- float runWidthSoFar() const { return m_runWidthSoFar; }
-
- float totalWidth() const { return m_totalWidth; }
-
- // Extra width to the left of the leftmost glyph.
- float finalRoundingWidth() const { return m_finalRoundingWidth; }
-
-private:
- class CoreTextRun {
- public:
- CoreTextRun(CTRunRef, const SimpleFontData*, const UChar* characters, unsigned stringLocation, size_t stringLength);
- CoreTextRun(const SimpleFontData*, const UChar* characters, unsigned stringLocation, size_t stringLength, bool ltr);
-
- CTRunRef ctRun() const { return m_CTRun.get(); }
- unsigned glyphCount() const { return m_glyphCount; }
- const SimpleFontData* fontData() const { return m_fontData; }
- const UChar* characters() const { return m_characters; }
- unsigned stringLocation() const { return m_stringLocation; }
- size_t stringLength() const { return m_stringLength; }
- CFIndex indexAt(size_t i) const { return m_indices[i]; }
-
- private:
- RetainPtr<CTRunRef> m_CTRun;
- unsigned m_glyphCount;
- const SimpleFontData* m_fontData;
- const UChar* m_characters;
- unsigned m_stringLocation;
- size_t m_stringLength;
- const CFIndex* m_indices;
- // Used only if CTRunGet*Ptr fails or if this is a missing glyphs run.
- RetainPtr<CFMutableDataRef> m_indicesData;
- };
-
- void collectCoreTextRuns();
- void collectCoreTextRunsForCharacters(const UChar*, unsigned length, unsigned stringLocation, const SimpleFontData*);
- void adjustGlyphsAndAdvances();
-
- const Font& m_font;
- const TextRun& m_run;
- bool m_mayUseNaturalWritingDirection;
-
- Vector<UChar, 256> m_smallCapsBuffer;
-
- Vector<CoreTextRun, 16> m_coreTextRuns;
- Vector<CGSize, 256> m_adjustedAdvances;
- Vector<CGGlyph, 256> m_adjustedGlyphs;
-
- unsigned m_currentCharacter;
- int m_end;
-
- CGFloat m_totalWidth;
-
- float m_runWidthSoFar;
- unsigned m_numGlyphsSoFar;
- size_t m_currentRun;
- unsigned m_glyphInCurrentRun;
- float m_finalRoundingWidth;
- float m_padding;
- float m_padPerSpace;
-
- HashSet<const SimpleFontData*>* m_fallbackFonts;
-
- unsigned m_lastRoundingGlyph;
-};
-
-} // namespace WebCore
-#endif // USE(CORE_TEXT)
-#endif // CoreTextController_h
diff --git a/WebCore/platform/graphics/mac/FontMacCoreText.cpp b/WebCore/platform/graphics/mac/FontComplexTextMac.cpp
index 9dffc7a..0db2601 100644
--- a/WebCore/platform/graphics/mac/FontMacCoreText.cpp
+++ b/WebCore/platform/graphics/mac/FontComplexTextMac.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,25 +10,22 @@
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "Font.h"
-#if USE(CORE_TEXT)
-
-#include "CoreTextController.h"
+#include "ComplexTextController.h"
#include "FontFallbackList.h"
#include "GlyphBuffer.h"
#include "GraphicsContext.h"
@@ -41,7 +38,7 @@ namespace WebCore {
FloatRect Font::selectionRectForComplexText(const TextRun& run, const IntPoint& point, int h,
int from, int to) const
{
- CoreTextController controller(this, run);
+ ComplexTextController controller(this, run);
controller.advance(from);
float beforeWidth = controller.runWidthSoFar();
controller.advance(to);
@@ -63,7 +60,7 @@ void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const F
GlyphBuffer glyphBuffer;
float startX = point.x();
- CoreTextController controller(this, run);
+ ComplexTextController controller(this, run);
controller.advance(from);
float beforeWidth = controller.runWidthSoFar();
controller.advance(to, &glyphBuffer);
@@ -88,15 +85,14 @@ void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const F
float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts) const
{
- CoreTextController controller(this, run, true, fallbackFonts);
+ ComplexTextController controller(this, run, true, fallbackFonts);
return controller.totalWidth();
}
int Font::offsetForPositionForComplexText(const TextRun& run, int x, bool includePartialGlyphs) const
{
- CoreTextController controller(this, run);
+ ComplexTextController controller(this, run);
return controller.offsetForPosition(x, includePartialGlyphs);
}
-}
-#endif // USE(CORE_TEXT)
+} // namespace WebCore
diff --git a/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp b/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp
index 5e72101..256b5a4 100644
--- a/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp
+++ b/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp
@@ -24,6 +24,7 @@
#include <ApplicationServices/ApplicationServices.h>
#include "SharedBuffer.h"
#include "FontPlatformData.h"
+#include "OpenTypeSanitizer.h"
namespace WebCore {
@@ -43,6 +44,14 @@ FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer)
{
ASSERT_ARG(buffer, buffer);
+#if ENABLE(OPENTYPE_SANITIZER)
+ OpenTypeSanitizer sanitizer(buffer);
+ RefPtr<SharedBuffer> transcodeBuffer = sanitizer.sanitize();
+ if (!transcodeBuffer)
+ return 0; // validation failed.
+ buffer = transcodeBuffer.get();
+#endif
+
ATSFontContainerRef containerRef = 0;
ATSFontRef fontRef = 0;
diff --git a/WebCore/platform/graphics/mac/FontMac.mm b/WebCore/platform/graphics/mac/FontMac.mm
index b2b9a5c..bb9561e 100644
--- a/WebCore/platform/graphics/mac/FontMac.mm
+++ b/WebCore/platform/graphics/mac/FontMac.mm
@@ -115,6 +115,7 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons
IntSize shadowSize;
int shadowBlur;
Color shadowColor;
+ ColorSpace fillColorSpace = context->fillColorSpace();
context->getShadow(shadowSize, shadowBlur, shadowColor);
bool hasSimpleShadow = context->textDrawingMode() == cTextFill && shadowColor.isValid() && !shadowBlur;
@@ -123,14 +124,14 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons
context->clearShadow();
Color fillColor = context->fillColor();
Color shadowFillColor(shadowColor.red(), shadowColor.green(), shadowColor.blue(), shadowColor.alpha() * fillColor.alpha() / 255);
- context->setFillColor(shadowFillColor);
+ context->setFillColor(shadowFillColor, fillColorSpace);
CGContextSetTextPosition(cgContext, point.x() + shadowSize.width(), point.y() + shadowSize.height());
CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs);
if (font->syntheticBoldOffset()) {
CGContextSetTextPosition(cgContext, point.x() + shadowSize.width() + font->syntheticBoldOffset(), point.y() + shadowSize.height());
CGContextShowGlyphsWithAdvances(cgContext, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs);
}
- context->setFillColor(fillColor);
+ context->setFillColor(fillColor, fillColorSpace);
}
CGContextSetTextPosition(cgContext, point.x(), point.y());
@@ -141,7 +142,7 @@ void Font::drawGlyphs(GraphicsContext* context, const SimpleFontData* font, cons
}
if (hasSimpleShadow)
- context->setShadow(shadowSize, shadowBlur, shadowColor);
+ context->setShadow(shadowSize, shadowBlur, shadowColor, fillColorSpace);
if (originalShouldUseFontSmoothing != newShouldUseFontSmoothing)
CGContextSetShouldSmoothFonts(cgContext, originalShouldUseFontSmoothing);
diff --git a/WebCore/platform/graphics/mac/FontMacATSUI.mm b/WebCore/platform/graphics/mac/FontMacATSUI.mm
deleted file mode 100644
index 409bda4..0000000
--- a/WebCore/platform/graphics/mac/FontMacATSUI.mm
+++ /dev/null
@@ -1,635 +0,0 @@
-/*
- * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
- * (C) 1999 Antti Koivisto (koivisto@kde.org)
- * (C) 2000 Dirk Mueller (mueller@kde.org)
- * Copyright (C) 2003, 2006 Apple Computer, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#import "config.h"
-#import "Font.h"
-
-#if USE(ATSUI)
-
-#import "CharacterNames.h"
-#import "GraphicsContext.h"
-#import "Logging.h"
-#import "ShapeArabic.h"
-#import "SimpleFontData.h"
-#import <AppKit/NSGraphicsContext.h>
-#import <wtf/OwnArrayPtr.h>
-
-#define SYNTHETIC_OBLIQUE_ANGLE 14
-
-#ifdef __LP64__
-#define URefCon void*
-#else
-#define URefCon UInt32
-#endif
-
-using namespace std;
-
-namespace WebCore {
-
-struct ATSULayoutParameters : Noncopyable
-{
- ATSULayoutParameters(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts = 0)
- : m_run(run)
- , m_font(0)
- , m_hasSyntheticBold(false)
- , m_syntheticBoldPass(false)
- , m_padPerSpace(0)
- , m_fallbackFonts(fallbackFonts)
- {
- }
-
- ~ATSULayoutParameters()
- {
- ATSUDisposeTextLayout(m_layout);
- }
-
- void initialize(const Font*, const GraphicsContext* = 0);
-
- const TextRun& m_run;
-
- const Font* m_font;
-
- ATSUTextLayout m_layout;
- OwnArrayPtr<const SimpleFontData*> m_fonts;
-
- OwnArrayPtr<UChar> m_charBuffer;
- bool m_hasSyntheticBold;
- bool m_syntheticBoldPass;
- float m_padPerSpace;
- HashSet<const SimpleFontData*>* m_fallbackFonts;
-};
-
-static TextRun copyRunForDirectionalOverrideIfNecessary(const TextRun& run, OwnArrayPtr<UChar>& charactersWithOverride)
-{
- if (!run.directionalOverride())
- return run;
-
- charactersWithOverride.set(new UChar[run.length() + 2]);
- charactersWithOverride[0] = run.rtl() ? rightToLeftOverride : leftToRightOverride;
- memcpy(&charactersWithOverride[1], run.data(0), sizeof(UChar) * run.length());
- charactersWithOverride[run.length() + 1] = popDirectionalFormatting;
-
- TextRun result = run;
- result.setText(charactersWithOverride.get(), run.length() + 2);
- return result;
-}
-
-static bool fontHasMirroringInfo(ATSUFontID fontID)
-{
- ByteCount propTableSize;
- OSStatus status = ATSFontGetTable(fontID, 'prop', 0, 0, 0, &propTableSize);
- if (status == noErr) // naively assume that if a 'prop' table exists then it contains mirroring info
- return true;
- else if (status != kATSInvalidFontTableAccess) // anything other than a missing table is logged as an error
- LOG_ERROR("ATSFontGetTable failed (%d)", status);
-
- return false;
-}
-
-static void disableLigatures(const SimpleFontData* fontData, TextRenderingMode textMode)
-{
- // Don't be too aggressive: if the font doesn't contain 'a', then assume that any ligatures it contains are
- // in characters that always go through ATSUI, and therefore allow them. Geeza Pro is an example.
- // See bugzilla 5166.
- if (textMode == OptimizeLegibility || textMode == GeometricPrecision || fontData->platformData().allowsLigatures())
- return;
-
- ATSUFontFeatureType featureTypes[] = { kLigaturesType };
- ATSUFontFeatureSelector featureSelectors[] = { kCommonLigaturesOffSelector };
- OSStatus status = ATSUSetFontFeatures(fontData->m_ATSUStyle, 1, featureTypes, featureSelectors);
- if (status != noErr)
- LOG_ERROR("ATSUSetFontFeatures failed (%d) -- ligatures remain enabled", status);
-}
-
-static void initializeATSUStyle(const SimpleFontData* fontData, TextRenderingMode textMode)
-{
- if (fontData->m_ATSUStyleInitialized)
- return;
-
- ATSUFontID fontID = fontData->platformData().m_atsuFontID;
- if (!fontID) {
- LOG_ERROR("unable to get ATSUFontID for %@", fontData->platformData().font());
- return;
- }
-
- OSStatus status = ATSUCreateStyle(&fontData->m_ATSUStyle);
- if (status != noErr)
- // Who knows how many ATSU functions will crash when passed a NULL style...
- LOG_ERROR("ATSUCreateStyle failed (%d)", status);
-
- CGAffineTransform transform = CGAffineTransformMakeScale(1, -1);
- if (fontData->platformData().m_syntheticOblique)
- transform = CGAffineTransformConcat(transform, CGAffineTransformMake(1, 0, -tanf(SYNTHETIC_OBLIQUE_ANGLE * acosf(0) / 90), 1, 0, 0));
- Fixed fontSize = FloatToFixed(fontData->platformData().m_size);
- ByteCount styleSizes[4] = { sizeof(Fixed), sizeof(ATSUFontID), sizeof(CGAffineTransform), sizeof(Fract) };
-
- bool allowKerning = textMode == OptimizeLegibility || textMode == GeometricPrecision;
- if (!allowKerning) {
- // Turn off automatic kerning until it is supported in the CG code path (bug 6136)
- Fract kerningInhibitFactor = FloatToFract(1.0);
- ATSUAttributeTag styleTags[4] = { kATSUSizeTag, kATSUFontTag, kATSUFontMatrixTag, kATSUKerningInhibitFactorTag };
- ATSUAttributeValuePtr styleValues[4] = { &fontSize, &fontID, &transform, &kerningInhibitFactor };
- status = ATSUSetAttributes(fontData->m_ATSUStyle, 4, styleTags, styleSizes, styleValues);
- if (status != noErr)
- LOG_ERROR("ATSUSetAttributes failed (%d)", status);
- } else {
- ATSUAttributeTag styleTags[3] = { kATSUSizeTag, kATSUFontTag, kATSUFontMatrixTag };
- ATSUAttributeValuePtr styleValues[3] = { &fontSize, &fontID, &transform, };
- status = ATSUSetAttributes(fontData->m_ATSUStyle, 3, styleTags, styleSizes, styleValues);
- if (status != noErr)
- LOG_ERROR("ATSUSetAttributes failed (%d)", status);
- }
-
- fontData->m_ATSUMirrors = fontHasMirroringInfo(fontID);
-
- // Turn off ligatures such as 'fi' to match the CG code path's behavior, until bug 6135 is fixed.
- disableLigatures(fontData, textMode);
-
- fontData->m_ATSUStyleInitialized = true;
-}
-
-static OSStatus overrideLayoutOperation(ATSULayoutOperationSelector, ATSULineRef iLineRef, URefCon iRefCon, void*, ATSULayoutOperationCallbackStatus* oCallbackStatus)
-{
- ATSULayoutParameters* params = reinterpret_cast<ATSULayoutParameters*>(iRefCon);
- OSStatus status;
- ItemCount count;
- ATSLayoutRecord *layoutRecords;
-
- if (params->m_run.applyWordRounding()) {
- status = ATSUDirectGetLayoutDataArrayPtrFromLineRef(iLineRef, kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, true, (void **)&layoutRecords, &count);
- if (status != noErr) {
- *oCallbackStatus = kATSULayoutOperationCallbackStatusContinue;
- return status;
- }
-
- Fixed lastNativePos = 0;
- float lastAdjustedPos = 0;
- const UChar* characters = params->m_charBuffer ? params->m_charBuffer.get() : params->m_run.characters();
- const SimpleFontData** renderers = params->m_fonts.get();
- const SimpleFontData* renderer;
- const SimpleFontData* lastRenderer = 0;
- ByteCount offset = layoutRecords[0].originalOffset;
- UChar nextCh = *(UChar *)(((char *)characters)+offset);
- bool shouldRound = false;
- bool syntheticBoldPass = params->m_syntheticBoldPass;
- Fixed syntheticBoldOffset = 0;
- bool hasExtraSpacing = (params->m_font->letterSpacing() || params->m_font->wordSpacing() || params->m_run.padding()) && !params->m_run.spacingDisabled();
- float padding = params->m_run.padding();
- // In the CoreGraphics code path, the rounding hack is applied in logical order.
- // Here it is applied in visual left-to-right order, which may be better.
- ItemCount lastRoundingChar = 0;
- ItemCount i;
- for (i = 1; i < count; i++) {
- bool isLastChar = i == count - 1;
- renderer = renderers[offset / 2];
- float width;
- if (nextCh == zeroWidthSpace || Font::treatAsZeroWidthSpace(nextCh) && !Font::treatAsSpace(nextCh)) {
- width = 0;
- layoutRecords[i-1].glyphID = renderer->spaceGlyph();
- } else {
- width = FixedToFloat(layoutRecords[i].realPos - lastNativePos);
- if (renderer != lastRenderer && width) {
- lastRenderer = renderer;
- // The CoreGraphics interpretation of NSFontAntialiasedIntegerAdvancementsRenderingMode seems
- // to be "round each glyph's width to the nearest integer". This is not the same as ATSUI
- // does in any of its device-metrics modes.
- shouldRound = renderer->platformData().roundsGlyphAdvances();
- if (syntheticBoldPass)
- syntheticBoldOffset = FloatToFixed(renderer->syntheticBoldOffset());
- if (params->m_fallbackFonts && renderer != params->m_font->primaryFont())
- params->m_fallbackFonts->add(renderer);
- }
- if (shouldRound)
- width = roundf(width);
- width += renderer->syntheticBoldOffset();
- if (renderer->pitch() == FixedPitch ? width == renderer->spaceWidth() : (layoutRecords[i-1].flags & kATSGlyphInfoIsWhiteSpace))
- width = renderer->adjustedSpaceWidth();
- }
- lastNativePos = layoutRecords[i].realPos;
-
- if (hasExtraSpacing) {
- if (width && params->m_font->letterSpacing())
- width +=params->m_font->letterSpacing();
- if (Font::treatAsSpace(nextCh)) {
- if (params->m_run.padding()) {
- if (padding < params->m_padPerSpace) {
- width += padding;
- padding = 0;
- } else {
- width += params->m_padPerSpace;
- padding -= params->m_padPerSpace;
- }
- }
- if (offset != 0 && !Font::treatAsSpace(*((UChar *)(((char *)characters)+offset) - 1)) && params->m_font->wordSpacing())
- width += params->m_font->wordSpacing();
- }
- }
-
- UChar ch = nextCh;
- offset = layoutRecords[i].originalOffset;
- // Use space for nextCh at the end of the loop so that we get inside the rounding hack code.
- // We won't actually round unless the other conditions are satisfied.
- nextCh = isLastChar ? ' ' : *(UChar *)(((char *)characters)+offset);
-
- if (Font::isRoundingHackCharacter(ch))
- width = ceilf(width);
- lastAdjustedPos = lastAdjustedPos + width;
- if (Font::isRoundingHackCharacter(nextCh) && (!isLastChar || params->m_run.applyRunRounding())){
- if (params->m_run.ltr())
- lastAdjustedPos = ceilf(lastAdjustedPos);
- else {
- float roundingWidth = ceilf(lastAdjustedPos) - lastAdjustedPos;
- Fixed rw = FloatToFixed(roundingWidth);
- ItemCount j;
- for (j = lastRoundingChar; j < i; j++)
- layoutRecords[j].realPos += rw;
- lastRoundingChar = i;
- lastAdjustedPos += roundingWidth;
- }
- }
- if (syntheticBoldPass) {
- if (syntheticBoldOffset)
- layoutRecords[i-1].realPos += syntheticBoldOffset;
- else
- layoutRecords[i-1].glyphID = renderer->spaceGlyph();
- }
- layoutRecords[i].realPos = FloatToFixed(lastAdjustedPos);
- }
-
- status = ATSUDirectReleaseLayoutDataArrayPtr(iLineRef, kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, (void **)&layoutRecords);
- }
- *oCallbackStatus = kATSULayoutOperationCallbackStatusHandled;
- return noErr;
-}
-
-static inline bool isArabicLamWithAlefLigature(UChar c)
-{
- return c >= 0xfef5 && c <= 0xfefc;
-}
-
-static void shapeArabic(const UChar* source, UChar* dest, unsigned totalLength, unsigned shapingStart)
-{
- while (shapingStart < totalLength) {
- unsigned shapingEnd;
- // We do not want to pass a Lam with Alef ligature followed by a space to the shaper,
- // since we want to be able to identify this sequence as the result of shaping a Lam
- // followed by an Alef and padding with a space.
- bool foundLigatureSpace = false;
- for (shapingEnd = shapingStart; !foundLigatureSpace && shapingEnd < totalLength - 1; ++shapingEnd)
- foundLigatureSpace = isArabicLamWithAlefLigature(source[shapingEnd]) && source[shapingEnd + 1] == ' ';
- shapingEnd++;
-
- UErrorCode shapingError = U_ZERO_ERROR;
- unsigned charsWritten = shapeArabic(source + shapingStart, shapingEnd - shapingStart, dest + shapingStart, shapingEnd - shapingStart, U_SHAPE_LETTERS_SHAPE | U_SHAPE_LENGTH_FIXED_SPACES_NEAR, &shapingError);
-
- if (U_SUCCESS(shapingError) && charsWritten == shapingEnd - shapingStart) {
- for (unsigned j = shapingStart; j < shapingEnd - 1; ++j) {
- if (isArabicLamWithAlefLigature(dest[j]) && dest[j + 1] == ' ')
- dest[++j] = zeroWidthSpace;
- }
- if (foundLigatureSpace) {
- dest[shapingEnd] = ' ';
- shapingEnd++;
- } else if (isArabicLamWithAlefLigature(dest[shapingEnd - 1])) {
- // u_shapeArabic quirk: if the last two characters in the source string are a Lam and an Alef,
- // the space is put at the beginning of the string, despite U_SHAPE_LENGTH_FIXED_SPACES_NEAR.
- ASSERT(dest[shapingStart] == ' ');
- dest[shapingStart] = zeroWidthSpace;
- }
- } else {
- // Something went wrong. Abandon shaping and just copy the rest of the buffer.
- LOG_ERROR("u_shapeArabic failed(%d)", shapingError);
- shapingEnd = totalLength;
- memcpy(dest + shapingStart, source + shapingStart, (shapingEnd - shapingStart) * sizeof(UChar));
- }
- shapingStart = shapingEnd;
- }
-}
-
-void ATSULayoutParameters::initialize(const Font* font, const GraphicsContext* graphicsContext)
-{
- m_font = font;
-
- const SimpleFontData* fontData = font->primaryFont();
- m_fonts.set(new const SimpleFontData*[m_run.length()]);
- if (font->isSmallCaps())
- m_charBuffer.set(new UChar[m_run.length()]);
-
- ATSUTextLayout layout;
- OSStatus status;
- ATSULayoutOperationOverrideSpecifier overrideSpecifier;
-
- initializeATSUStyle(fontData, m_font->fontDescription().textRenderingMode());
-
- // FIXME: This is currently missing the following required features that the CoreGraphics code path has:
- // - \n, \t, and nonbreaking space render as a space.
-
- UniCharCount runLength = m_run.length();
-
- if (m_charBuffer)
- memcpy(m_charBuffer.get(), m_run.characters(), runLength * sizeof(UChar));
-
- status = ATSUCreateTextLayoutWithTextPtr(
- (m_charBuffer ? m_charBuffer.get() : m_run.characters()),
- 0, // offset
- runLength, // length
- runLength, // total length
- 1, // styleRunCount
- &runLength, // length of style run
- &fontData->m_ATSUStyle,
- &layout);
- if (status != noErr)
- LOG_ERROR("ATSUCreateTextLayoutWithTextPtr failed(%d)", status);
- m_layout = layout;
- ATSUSetTextLayoutRefCon(m_layout, (URefCon)this);
-
- // FIXME: There are certain times when this method is called, when we don't have access to a GraphicsContext
- // measuring text runs with floatWidthForComplexText is one example.
- // ATSUI requires that we pass a valid CGContextRef to it when specifying kATSUCGContextTag (crashes when passed 0)
- // ATSUI disables sub-pixel rendering if kATSUCGContextTag is not specified! So we're in a bind.
- // Sometimes [[NSGraphicsContext currentContext] graphicsPort] may return the wrong (or no!) context. Nothing we can do about it (yet).
- CGContextRef cgContext = graphicsContext ? graphicsContext->platformContext() : (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
-
- ATSLineLayoutOptions lineLayoutOptions = kATSLineKeepSpacesOutOfMargin | kATSLineHasNoHangers;
- Boolean rtl = m_run.rtl();
- overrideSpecifier.operationSelector = kATSULayoutOperationPostLayoutAdjustment;
- overrideSpecifier.overrideUPP = overrideLayoutOperation;
- ATSUAttributeTag tags[] = { kATSUCGContextTag, kATSULineLayoutOptionsTag, kATSULineDirectionTag, kATSULayoutOperationOverrideTag };
- ByteCount sizes[] = { sizeof(CGContextRef), sizeof(ATSLineLayoutOptions), sizeof(Boolean), sizeof(ATSULayoutOperationOverrideSpecifier) };
- ATSUAttributeValuePtr values[] = { &cgContext, &lineLayoutOptions, &rtl, &overrideSpecifier };
-
- status = ATSUSetLayoutControls(layout, (m_run.applyWordRounding() ? 4 : 3), tags, sizes, values);
- if (status != noErr)
- LOG_ERROR("ATSUSetLayoutControls failed(%d)", status);
-
- status = ATSUSetTransientFontMatching(layout, YES);
- if (status != noErr)
- LOG_ERROR("ATSUSetTransientFontMatching failed(%d)", status);
-
- m_hasSyntheticBold = false;
- ATSUFontID ATSUSubstituteFont;
- UniCharArrayOffset substituteOffset = 0;
- UniCharCount substituteLength;
- UniCharArrayOffset lastOffset;
- const SimpleFontData* substituteFontData = 0;
-
- while (substituteOffset < runLength) {
- // FIXME: Using ATSUMatchFontsToText() here results in several problems: the CSS font family list is not necessarily followed for the 2nd
- // and onwards unmatched characters; segmented fonts do not work correctly; behavior does not match the simple text and Uniscribe code
- // paths. Change this function to use Font::glyphDataForCharacter() for each character instead.
- lastOffset = substituteOffset;
- status = ATSUMatchFontsToText(layout, substituteOffset, kATSUToTextEnd, &ATSUSubstituteFont, &substituteOffset, &substituteLength);
- if (status == kATSUFontsMatched || status == kATSUFontsNotMatched) {
- const FontData* fallbackFontData = m_font->fontDataForCharacters(m_run.characters() + substituteOffset, substituteLength);
- substituteFontData = fallbackFontData ? fallbackFontData->fontDataForCharacter(m_run[0]) : 0;
- if (substituteFontData) {
- initializeATSUStyle(substituteFontData, m_font->fontDescription().textRenderingMode());
- if (substituteFontData->m_ATSUStyle)
- ATSUSetRunStyle(layout, substituteFontData->m_ATSUStyle, substituteOffset, substituteLength);
- } else
- substituteFontData = fontData;
- } else {
- substituteOffset = runLength;
- substituteLength = 0;
- }
-
- bool shapedArabic = false;
- bool isSmallCap = false;
- UniCharArrayOffset firstSmallCap = 0;
- const SimpleFontData *r = fontData;
- UniCharArrayOffset i;
- for (i = lastOffset; ; i++) {
- if (i == substituteOffset || i == substituteOffset + substituteLength) {
- if (isSmallCap) {
- isSmallCap = false;
- initializeATSUStyle(r->smallCapsFontData(m_font->fontDescription()), m_font->fontDescription().textRenderingMode());
- ATSUSetRunStyle(layout, r->smallCapsFontData(m_font->fontDescription())->m_ATSUStyle, firstSmallCap, i - firstSmallCap);
- }
- if (i == substituteOffset && substituteLength > 0)
- r = substituteFontData;
- else
- break;
- }
- if (!shapedArabic && WTF::Unicode::isArabicChar(m_run[i]) && !r->shapesArabic()) {
- shapedArabic = true;
- if (!m_charBuffer) {
- m_charBuffer.set(new UChar[runLength]);
- memcpy(m_charBuffer.get(), m_run.characters(), i * sizeof(UChar));
- ATSUTextMoved(layout, m_charBuffer.get());
- }
- shapeArabic(m_run.characters(), m_charBuffer.get(), runLength, i);
- }
- if (m_run.rtl() && !r->m_ATSUMirrors) {
- UChar mirroredChar = u_charMirror(m_run[i]);
- if (mirroredChar != m_run[i]) {
- if (!m_charBuffer) {
- m_charBuffer.set(new UChar[runLength]);
- memcpy(m_charBuffer.get(), m_run.characters(), runLength * sizeof(UChar));
- ATSUTextMoved(layout, m_charBuffer.get());
- }
- m_charBuffer[i] = mirroredChar;
- }
- }
- if (m_font->isSmallCaps()) {
- const SimpleFontData* smallCapsData = r->smallCapsFontData(m_font->fontDescription());
- UChar c = m_charBuffer[i];
- UChar newC;
- if (U_GET_GC_MASK(c) & U_GC_M_MASK)
- m_fonts[i] = isSmallCap ? smallCapsData : r;
- else if (!u_isUUppercase(c) && (newC = u_toupper(c)) != c) {
- m_charBuffer[i] = newC;
- if (!isSmallCap) {
- isSmallCap = true;
- firstSmallCap = i;
- }
- m_fonts[i] = smallCapsData;
- } else {
- if (isSmallCap) {
- isSmallCap = false;
- initializeATSUStyle(smallCapsData, m_font->fontDescription().textRenderingMode());
- ATSUSetRunStyle(layout, smallCapsData->m_ATSUStyle, firstSmallCap, i - firstSmallCap);
- }
- m_fonts[i] = r;
- }
- } else
- m_fonts[i] = r;
- if (m_fonts[i]->syntheticBoldOffset())
- m_hasSyntheticBold = true;
- }
- substituteOffset += substituteLength;
- }
- if (m_run.padding()) {
- float numSpaces = 0;
- unsigned k;
- for (k = 0; k < runLength; k++)
- if (Font::treatAsSpace(m_run[k]))
- numSpaces++;
-
- if (numSpaces == 0)
- m_padPerSpace = 0;
- else
- m_padPerSpace = ceilf(m_run.padding() / numSpaces);
- } else
- m_padPerSpace = 0;
-}
-
-FloatRect Font::selectionRectForComplexText(const TextRun& run, const IntPoint& point, int h, int from, int to) const
-{
- OwnArrayPtr<UChar> charactersWithOverride;
- TextRun adjustedRun = copyRunForDirectionalOverrideIfNecessary(run, charactersWithOverride);
- if (run.directionalOverride()) {
- from++;
- to++;
- }
-
- ATSULayoutParameters params(adjustedRun);
- params.initialize(this);
-
- ATSTrapezoid firstGlyphBounds;
- ItemCount actualNumBounds;
-
- OSStatus status = ATSUGetGlyphBounds(params.m_layout, 0, 0, from, to - from, kATSUseFractionalOrigins, 1, &firstGlyphBounds, &actualNumBounds);
- if (status != noErr || actualNumBounds != 1) {
- static ATSTrapezoid zeroTrapezoid = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
- firstGlyphBounds = zeroTrapezoid;
- }
-
- float beforeWidth = min(FixedToFloat(firstGlyphBounds.lowerLeft.x), FixedToFloat(firstGlyphBounds.upperLeft.x));
- float afterWidth = max(FixedToFloat(firstGlyphBounds.lowerRight.x), FixedToFloat(firstGlyphBounds.upperRight.x));
-
- FloatRect rect(point.x() + floorf(beforeWidth), point.y(), roundf(afterWidth) - floorf(beforeWidth), h);
-
- return rect;
-}
-
-void Font::drawComplexText(GraphicsContext* graphicsContext, const TextRun& run, const FloatPoint& point, int from, int to) const
-{
- OSStatus status;
-
- int drawPortionLength = to - from;
- OwnArrayPtr<UChar> charactersWithOverride;
- TextRun adjustedRun = copyRunForDirectionalOverrideIfNecessary(run, charactersWithOverride);
- if (run.directionalOverride())
- from++;
-
- ATSULayoutParameters params(adjustedRun);
- params.initialize(this, graphicsContext);
-
- // ATSUI can't draw beyond -32768 to +32767 so we translate the CTM and tell ATSUI to draw at (0, 0).
- CGContextRef context = graphicsContext->platformContext();
- CGContextTranslateCTM(context, point.x(), point.y());
-
- IntSize shadowSize;
- int shadowBlur;
- Color shadowColor;
- graphicsContext->getShadow(shadowSize, shadowBlur, shadowColor);
-
- bool hasSimpleShadow = graphicsContext->textDrawingMode() == cTextFill && shadowColor.isValid() && !shadowBlur;
- if (hasSimpleShadow) {
- // Paint simple shadows ourselves instead of relying on CG shadows, to avoid losing subpixel antialiasing.
- graphicsContext->clearShadow();
- Color fillColor = graphicsContext->fillColor();
- Color shadowFillColor(shadowColor.red(), shadowColor.green(), shadowColor.blue(), shadowColor.alpha() * fillColor.alpha() / 255);
- graphicsContext->setFillColor(shadowFillColor);
- CGContextTranslateCTM(context, shadowSize.width(), shadowSize.height());
- status = ATSUDrawText(params.m_layout, from, drawPortionLength, 0, 0);
- if (status == noErr && params.m_hasSyntheticBold) {
- // Force relayout for the bold pass
- ATSUClearLayoutCache(params.m_layout, 0);
- params.m_syntheticBoldPass = true;
- status = ATSUDrawText(params.m_layout, from, drawPortionLength, 0, 0);
- // Force relayout for the next pass
- ATSUClearLayoutCache(params.m_layout, 0);
- params.m_syntheticBoldPass = false;
- }
- CGContextTranslateCTM(context, -shadowSize.width(), -shadowSize.height());
- graphicsContext->setFillColor(fillColor);
- }
-
- status = ATSUDrawText(params.m_layout, from, drawPortionLength, 0, 0);
- if (status == noErr && params.m_hasSyntheticBold) {
- // Force relayout for the bold pass
- ATSUClearLayoutCache(params.m_layout, 0);
- params.m_syntheticBoldPass = true;
- status = ATSUDrawText(params.m_layout, from, drawPortionLength, 0, 0);
- }
- CGContextTranslateCTM(context, -point.x(), -point.y());
-
- if (status != noErr)
- // Nothing to do but report the error (dev build only).
- LOG_ERROR("ATSUDrawText() failed(%d)", status);
-
- if (hasSimpleShadow)
- graphicsContext->setShadow(shadowSize, shadowBlur, shadowColor);
-}
-
-float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts) const
-{
- if (run.length() == 0)
- return 0;
-
- ATSULayoutParameters params(run, fallbackFonts);
- params.initialize(this);
-
- OSStatus status;
-
- ATSTrapezoid firstGlyphBounds;
- ItemCount actualNumBounds;
- status = ATSUGetGlyphBounds(params.m_layout, 0, 0, 0, run.length(), kATSUseFractionalOrigins, 1, &firstGlyphBounds, &actualNumBounds);
- if (status != noErr)
- LOG_ERROR("ATSUGetGlyphBounds() failed(%d)", status);
- if (actualNumBounds != 1)
- LOG_ERROR("unexpected result from ATSUGetGlyphBounds(): actualNumBounds(%d) != 1", actualNumBounds);
-
- return max(FixedToFloat(firstGlyphBounds.upperRight.x), FixedToFloat(firstGlyphBounds.lowerRight.x)) -
- min(FixedToFloat(firstGlyphBounds.upperLeft.x), FixedToFloat(firstGlyphBounds.lowerLeft.x));
-}
-
-int Font::offsetForPositionForComplexText(const TextRun& run, int x, bool /*includePartialGlyphs*/) const
-{
- OwnArrayPtr<UChar> charactersWithOverride;
- TextRun adjustedRun = copyRunForDirectionalOverrideIfNecessary(run, charactersWithOverride);
-
- ATSULayoutParameters params(adjustedRun);
- params.initialize(this);
-
- UniCharArrayOffset primaryOffset = 0;
-
- // FIXME: No idea how to avoid including partial glyphs.
- // Not even sure if that's the behavior this yields now.
- Boolean isLeading;
- UniCharArrayOffset secondaryOffset = 0;
- OSStatus status = ATSUPositionToOffset(params.m_layout, FloatToFixed(x), FloatToFixed(-1), &primaryOffset, &isLeading, &secondaryOffset);
- unsigned offset;
- if (status == noErr) {
- offset = (unsigned)primaryOffset;
- if (run.directionalOverride() && offset > 0)
- offset--;
- } else
- // Failed to find offset! Return 0 offset.
- offset = 0;
-
- return offset;
-}
-
-}
-#endif // USE(ATSUI)
diff --git a/WebCore/platform/graphics/mac/GraphicsContext3DMac.cpp b/WebCore/platform/graphics/mac/GraphicsContext3DMac.cpp
index 47617d8..41f63a9 100644
--- a/WebCore/platform/graphics/mac/GraphicsContext3DMac.cpp
+++ b/WebCore/platform/graphics/mac/GraphicsContext3DMac.cpp
@@ -30,18 +30,18 @@
#include "GraphicsContext3D.h"
#include "CachedImage.h"
-#include "CanvasActiveInfo.h"
-#include "CanvasArray.h"
-#include "CanvasBuffer.h"
-#include "CanvasFramebuffer.h"
-#include "CanvasFloatArray.h"
-#include "CanvasIntArray.h"
+#include "WebGLActiveInfo.h"
+#include "WebGLArray.h"
+#include "WebGLBuffer.h"
+#include "WebGLFramebuffer.h"
+#include "WebGLFloatArray.h"
+#include "WebGLIntArray.h"
#include "CanvasObject.h"
-#include "CanvasProgram.h"
-#include "CanvasRenderbuffer.h"
-#include "CanvasShader.h"
-#include "CanvasTexture.h"
-#include "CanvasUnsignedByteArray.h"
+#include "WebGLProgram.h"
+#include "WebGLRenderbuffer.h"
+#include "WebGLShader.h"
+#include "WebGLTexture.h"
+#include "WebGLUnsignedByteArray.h"
#include "CString.h"
#include "HTMLCanvasElement.h"
#include "HTMLImageElement.h"
@@ -175,21 +175,12 @@ GraphicsContext3D::~GraphicsContext3D()
}
}
-void GraphicsContext3D::checkError() const
-{
- // FIXME: This needs to only be done in the debug context. It will probably throw an exception
- // on error and print the error message to the debug console
- GLenum error = ::glGetError();
- if (error != GL_NO_ERROR)
- notImplemented();
-}
-
void GraphicsContext3D::makeContextCurrent()
{
CGLSetCurrentContext(m_contextObj);
}
-void GraphicsContext3D::beginPaint(CanvasRenderingContext3D* context)
+void GraphicsContext3D::beginPaint(WebGLRenderingContext* context)
{
UNUSED_PARAM(context);
}
@@ -246,43 +237,42 @@ void GraphicsContext3D::activeTexture(unsigned long texture)
::glActiveTexture(texture);
}
-void GraphicsContext3D::attachShader(CanvasProgram* program, CanvasShader* shader)
+void GraphicsContext3D::attachShader(WebGLProgram* program, WebGLShader* shader)
{
- if (!program || !shader)
- return;
+ ASSERT(program);
+ ASSERT(shader);
ensureContext(m_contextObj);
::glAttachShader((GLuint) program->object(), (GLuint) shader->object());
}
-void GraphicsContext3D::bindAttribLocation(CanvasProgram* program, unsigned long index, const String& name)
+void GraphicsContext3D::bindAttribLocation(WebGLProgram* program, unsigned long index, const String& name)
{
- if (!program)
- return;
+ ASSERT(program);
ensureContext(m_contextObj);
::glBindAttribLocation((GLuint) program->object(), index, name.utf8().data());
}
-void GraphicsContext3D::bindBuffer(unsigned long target, CanvasBuffer* buffer)
+void GraphicsContext3D::bindBuffer(unsigned long target, WebGLBuffer* buffer)
{
ensureContext(m_contextObj);
::glBindBuffer(target, buffer ? (GLuint) buffer->object() : 0);
}
-void GraphicsContext3D::bindFramebuffer(unsigned long target, CanvasFramebuffer* buffer)
+void GraphicsContext3D::bindFramebuffer(unsigned long target, WebGLFramebuffer* buffer)
{
ensureContext(m_contextObj);
::glBindFramebufferEXT(target, buffer ? (GLuint) buffer->object() : m_fbo);
}
-void GraphicsContext3D::bindRenderbuffer(unsigned long target, CanvasRenderbuffer* renderbuffer)
+void GraphicsContext3D::bindRenderbuffer(unsigned long target, WebGLRenderbuffer* renderbuffer)
{
ensureContext(m_contextObj);
- ::glBindBuffer(target, renderbuffer ? (GLuint) renderbuffer->object() : 0);
+ ::glBindRenderbufferEXT(target, renderbuffer ? (GLuint) renderbuffer->object() : 0);
}
-void GraphicsContext3D::bindTexture(unsigned long target, CanvasTexture* texture)
+void GraphicsContext3D::bindTexture(unsigned long target, WebGLTexture* texture)
{
ensureContext(m_contextObj);
::glBindTexture(target, texture ? (GLuint) texture->object() : 0);
@@ -324,22 +314,22 @@ void GraphicsContext3D::bufferData(unsigned long target, int size, unsigned long
ensureContext(m_contextObj);
::glBufferData(target, size, 0, usage);
}
-void GraphicsContext3D::bufferData(unsigned long target, CanvasArray* array, unsigned long usage)
+void GraphicsContext3D::bufferData(unsigned long target, WebGLArray* array, unsigned long usage)
{
if (!array || !array->length())
return;
ensureContext(m_contextObj);
- ::glBufferData(target, array->sizeInBytes(), array->baseAddress(), usage);
+ ::glBufferData(target, array->byteLength(), array->baseAddress(), usage);
}
-void GraphicsContext3D::bufferSubData(unsigned long target, long offset, CanvasArray* array)
+void GraphicsContext3D::bufferSubData(unsigned long target, long offset, WebGLArray* array)
{
if (!array || !array->length())
return;
ensureContext(m_contextObj);
- ::glBufferSubData(target, offset, array->sizeInBytes(), array->baseAddress());
+ ::glBufferSubData(target, offset, array->byteLength(), array->baseAddress());
}
unsigned long GraphicsContext3D::checkFramebufferStatus(unsigned long target)
@@ -378,11 +368,9 @@ void GraphicsContext3D::colorMask(bool red, bool green, bool blue, bool alpha)
::glColorMask(red, green, blue, alpha);
}
-void GraphicsContext3D::compileShader(CanvasShader* shader)
+void GraphicsContext3D::compileShader(WebGLShader* shader)
{
- if (!shader)
- return;
-
+ ASSERT(shader);
ensureContext(m_contextObj);
::glCompileShader((GLuint) shader->object());
}
@@ -423,11 +411,10 @@ void GraphicsContext3D::depthRange(double zNear, double zFar)
::glDepthRange(zNear, zFar);
}
-void GraphicsContext3D::detachShader(CanvasProgram* program, CanvasShader* shader)
+void GraphicsContext3D::detachShader(WebGLProgram* program, WebGLShader* shader)
{
- if (!program || !shader)
- return;
-
+ ASSERT(program);
+ ASSERT(shader);
ensureContext(m_contextObj);
::glDetachShader((GLuint) program->object(), (GLuint) shader->object());
}
@@ -480,22 +467,16 @@ void GraphicsContext3D::flush()
::glFlush();
}
-void GraphicsContext3D::framebufferRenderbuffer(unsigned long target, unsigned long attachment, unsigned long renderbuffertarget, CanvasRenderbuffer* buffer)
+void GraphicsContext3D::framebufferRenderbuffer(unsigned long target, unsigned long attachment, unsigned long renderbuffertarget, WebGLRenderbuffer* buffer)
{
- if (!buffer)
- return;
-
ensureContext(m_contextObj);
- ::glFramebufferRenderbufferEXT(target, attachment, renderbuffertarget, (GLuint) buffer->object());
+ ::glFramebufferRenderbufferEXT(target, attachment, renderbuffertarget, buffer ? (GLuint) buffer->object() : 0);
}
-void GraphicsContext3D::framebufferTexture2D(unsigned long target, unsigned long attachment, unsigned long textarget, CanvasTexture* texture, long level)
+void GraphicsContext3D::framebufferTexture2D(unsigned long target, unsigned long attachment, unsigned long textarget, WebGLTexture* texture, long level)
{
- if (!texture)
- return;
-
ensureContext(m_contextObj);
- ::glFramebufferTexture2DEXT(target, attachment, textarget, (GLuint) texture->object(), level);
+ ::glFramebufferTexture2DEXT(target, attachment, textarget, texture ? (GLuint) texture->object() : 0, level);
}
void GraphicsContext3D::frontFace(unsigned long mode)
@@ -510,10 +491,12 @@ void GraphicsContext3D::generateMipmap(unsigned long target)
::glGenerateMipmapEXT(target);
}
-bool GraphicsContext3D::getActiveAttrib(CanvasProgram* program, unsigned long index, ActiveInfo& info)
+bool GraphicsContext3D::getActiveAttrib(WebGLProgram* program, unsigned long index, ActiveInfo& info)
{
- if (!program->object())
+ if (!program->object()) {
+ synthesizeGLError(INVALID_VALUE);
return false;
+ }
ensureContext(m_contextObj);
GLint maxAttributeSize = 0;
::glGetProgramiv(static_cast<GLuint>(program->object()), GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxAttributeSize);
@@ -530,10 +513,12 @@ bool GraphicsContext3D::getActiveAttrib(CanvasProgram* program, unsigned long in
return true;
}
-bool GraphicsContext3D::getActiveUniform(CanvasProgram* program, unsigned long index, ActiveInfo& info)
+bool GraphicsContext3D::getActiveUniform(WebGLProgram* program, unsigned long index, ActiveInfo& info)
{
- if (!program->object())
+ if (!program->object()) {
+ synthesizeGLError(INVALID_VALUE);
return false;
+ }
ensureContext(m_contextObj);
GLint maxUniformSize = 0;
::glGetProgramiv(static_cast<GLuint>(program->object()), GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxUniformSize);
@@ -550,7 +535,7 @@ bool GraphicsContext3D::getActiveUniform(CanvasProgram* program, unsigned long i
return true;
}
-int GraphicsContext3D::getAttribLocation(CanvasProgram* program, const String& name)
+int GraphicsContext3D::getAttribLocation(WebGLProgram* program, const String& name)
{
if (!program)
return -1;
@@ -561,6 +546,13 @@ int GraphicsContext3D::getAttribLocation(CanvasProgram* program, const String& n
unsigned long GraphicsContext3D::getError()
{
+ if (m_syntheticErrors.size() > 0) {
+ ListHashSet<unsigned long>::iterator iter = m_syntheticErrors.begin();
+ unsigned long err = *iter;
+ m_syntheticErrors.remove(iter);
+ return err;
+ }
+
ensureContext(m_contextObj);
return ::glGetError();
}
@@ -577,7 +569,7 @@ void GraphicsContext3D::hint(unsigned long target, unsigned long mode)
::glHint(target, mode);
}
-bool GraphicsContext3D::isBuffer(CanvasBuffer* buffer)
+bool GraphicsContext3D::isBuffer(WebGLBuffer* buffer)
{
if (!buffer)
return false;
@@ -592,7 +584,7 @@ bool GraphicsContext3D::isEnabled(unsigned long cap)
return ::glIsEnabled(cap);
}
-bool GraphicsContext3D::isFramebuffer(CanvasFramebuffer* framebuffer)
+bool GraphicsContext3D::isFramebuffer(WebGLFramebuffer* framebuffer)
{
if (!framebuffer)
return false;
@@ -601,7 +593,7 @@ bool GraphicsContext3D::isFramebuffer(CanvasFramebuffer* framebuffer)
return ::glIsFramebufferEXT((GLuint) framebuffer->object());
}
-bool GraphicsContext3D::isProgram(CanvasProgram* program)
+bool GraphicsContext3D::isProgram(WebGLProgram* program)
{
if (!program)
return false;
@@ -610,7 +602,7 @@ bool GraphicsContext3D::isProgram(CanvasProgram* program)
return ::glIsProgram((GLuint) program->object());
}
-bool GraphicsContext3D::isRenderbuffer(CanvasRenderbuffer* renderbuffer)
+bool GraphicsContext3D::isRenderbuffer(WebGLRenderbuffer* renderbuffer)
{
if (!renderbuffer)
return false;
@@ -619,7 +611,7 @@ bool GraphicsContext3D::isRenderbuffer(CanvasRenderbuffer* renderbuffer)
return ::glIsRenderbufferEXT((GLuint) renderbuffer->object());
}
-bool GraphicsContext3D::isShader(CanvasShader* shader)
+bool GraphicsContext3D::isShader(WebGLShader* shader)
{
if (!shader)
return false;
@@ -628,7 +620,7 @@ bool GraphicsContext3D::isShader(CanvasShader* shader)
return ::glIsShader((GLuint) shader->object());
}
-bool GraphicsContext3D::isTexture(CanvasTexture* texture)
+bool GraphicsContext3D::isTexture(WebGLTexture* texture)
{
if (!texture)
return false;
@@ -643,11 +635,9 @@ void GraphicsContext3D::lineWidth(double width)
::glLineWidth(static_cast<float>(width));
}
-void GraphicsContext3D::linkProgram(CanvasProgram* program)
+void GraphicsContext3D::linkProgram(WebGLProgram* program)
{
- if (!program)
- return;
-
+ ASSERT(program);
ensureContext(m_contextObj);
::glLinkProgram((GLuint) program->object());
}
@@ -664,7 +654,7 @@ void GraphicsContext3D::polygonOffset(double factor, double units)
::glPolygonOffset(static_cast<float>(factor), static_cast<float>(units));
}
-PassRefPtr<CanvasArray> GraphicsContext3D::readPixels(long x, long y, unsigned long width, unsigned long height, unsigned long format, unsigned long type)
+PassRefPtr<WebGLArray> GraphicsContext3D::readPixels(long x, long y, unsigned long width, unsigned long height, unsigned long format, unsigned long type)
{
ensureContext(m_contextObj);
@@ -675,7 +665,7 @@ PassRefPtr<CanvasArray> GraphicsContext3D::readPixels(long x, long y, unsigned l
if (type != GL_UNSIGNED_BYTE || format != GL_RGBA)
return 0;
- RefPtr<CanvasUnsignedByteArray> array = CanvasUnsignedByteArray::create(width * height * 4);
+ RefPtr<WebGLUnsignedByteArray> array = WebGLUnsignedByteArray::create(width * height * 4);
::glReadPixels(x, y, width, height, format, type, (GLvoid*) array->data());
return array;
}
@@ -705,10 +695,9 @@ void GraphicsContext3D::scissor(long x, long y, unsigned long width, unsigned lo
::glScissor(x, y, width, height);
}
-void GraphicsContext3D::shaderSource(CanvasShader* shader, const String& string)
+void GraphicsContext3D::shaderSource(WebGLShader* shader, const String& string)
{
- if (!shader)
- return;
+ ASSERT(shader);
ensureContext(m_contextObj);
const CString& cs = string.utf8();
@@ -889,19 +878,17 @@ void GraphicsContext3D::uniformMatrix4fv(long location, bool transpose, float* a
::glUniformMatrix4fv(location, size, transpose, array);
}
-void GraphicsContext3D::useProgram(CanvasProgram* program)
+void GraphicsContext3D::useProgram(WebGLProgram* program)
{
- if (!program)
- return;
+ ASSERT(program);
ensureContext(m_contextObj);
::glUseProgram((GLuint) program->object());
}
-void GraphicsContext3D::validateProgram(CanvasProgram* program)
+void GraphicsContext3D::validateProgram(WebGLProgram* program)
{
- if (!program)
- return;
+ ASSERT(program);
ensureContext(m_contextObj);
::glValidateProgram((GLuint) program->object());
@@ -967,567 +954,156 @@ void GraphicsContext3D::viewport(long x, long y, unsigned long width, unsigned l
::glViewport(static_cast<GLint>(x), static_cast<GLint>(y), static_cast<GLsizei>(width), static_cast<GLsizei>(height));
}
-static int sizeForGetParam(unsigned long pname)
-{
- switch(pname) {
- case GL_ACTIVE_TEXTURE: return 1;
- case GL_ALIASED_LINE_WIDTH_RANGE: return 2;
- case GL_ALIASED_POINT_SIZE_RANGE: return 2;
- case GL_ALPHA_BITS: return 1;
- case GL_ARRAY_BUFFER_BINDING: return 1; // (* actually a CanvasBuffer*)
- case GL_BLEND: return 1;
- case GL_BLEND_COLOR: return 4;
- case GL_BLEND_DST_ALPHA: return 1;
- case GL_BLEND_DST_RGB: return 1;
- case GL_BLEND_EQUATION_ALPHA: return 1;
- case GL_BLEND_EQUATION_RGB: return 1;
- case GL_BLEND_SRC_ALPHA: return 1;
- case GL_BLEND_SRC_RGB: return 1;
- case GL_BLUE_BITS: return 1;
- case GL_COLOR_CLEAR_VALUE: return 4;
- case GL_COLOR_WRITEMASK: return 4;
- case GL_COMPRESSED_TEXTURE_FORMATS: return GL_NUM_COMPRESSED_TEXTURE_FORMATS;
- case GL_CULL_FACE: return 1;
- case GL_CULL_FACE_MODE: return 1;
- case GL_CURRENT_PROGRAM: return 1; // (* actually a CanvasProgram*)
- case GL_DEPTH_BITS: return 1;
- case GL_DEPTH_CLEAR_VALUE: return 1;
- case GL_DEPTH_FUNC: return 1;
- case GL_DEPTH_RANGE: return 2;
- case GL_DEPTH_TEST: return 1;
- case GL_DEPTH_WRITEMASK: return 1;
- case GL_DITHER: return 1;
- case GL_ELEMENT_ARRAY_BUFFER_BINDING: return 1; // (* actually a CanvasBuffer*)
- case GL_FRAMEBUFFER_BINDING_EXT: return 1; // (* actually a CanvasFramebuffer*)
- case GL_FRONT_FACE: return 1;
- case GL_GENERATE_MIPMAP_HINT: return 1;
- case GL_GREEN_BITS: return 1;
- //case GL_IMPLEMENTATION_COLOR_READ_FORMAT:return 1;
- //case GL_IMPLEMENTATION_COLOR_READ_TYPE: return 1;
- case GL_LINE_WIDTH: return 1;
- case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:return 1;
- case GL_MAX_CUBE_MAP_TEXTURE_SIZE: return 1;
- //case GL_MAX_FRAGMENT_UNIFORM_VECTORS: return 1;
- case GL_MAX_RENDERBUFFER_SIZE_EXT: return 1;
- case GL_MAX_TEXTURE_IMAGE_UNITS: return 1;
- case GL_MAX_TEXTURE_SIZE: return 1;
- //case GL_MAX_VARYING_VECTORS: return 1;
- case GL_MAX_VERTEX_ATTRIBS: return 1;
- case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS: return 1;
- //case GL_MAX_VERTEX_UNIFORM_VECTORS: return 1;
- case GL_MAX_VIEWPORT_DIMS: return 2;
- case GL_NUM_COMPRESSED_TEXTURE_FORMATS: return 1;
- //case GL_NUM_SHADER_BINARY_FORMATS: return 1;
- case GL_PACK_ALIGNMENT: return 1;
- case GL_POLYGON_OFFSET_FACTOR: return 1;
- case GL_POLYGON_OFFSET_FILL: return 1;
- case GL_POLYGON_OFFSET_UNITS: return 1;
- case GL_RED_BITS: return 1;
- case GL_RENDERBUFFER_BINDING_EXT: return 1; // (* actually a CanvasRenderbuffer*)
- case GL_SAMPLE_BUFFERS: return 1;
- case GL_SAMPLE_COVERAGE_INVERT: return 1;
- case GL_SAMPLE_COVERAGE_VALUE: return 1;
- case GL_SAMPLES: return 1;
- case GL_SCISSOR_BOX: return 4;
- case GL_SCISSOR_TEST: return 1;
- //case GL_SHADER_BINARY_FORMATS: return GL_NUM_SHADER_BINARY_FORMATS;
- //case GL_SHADER_COMPILER: return 1;
- case GL_STENCIL_BACK_FAIL: return 1;
- case GL_STENCIL_BACK_FUNC: return 1;
- case GL_STENCIL_BACK_PASS_DEPTH_FAIL: return 1;
- case GL_STENCIL_BACK_PASS_DEPTH_PASS: return 1;
- case GL_STENCIL_BACK_REF: return 1;
- case GL_STENCIL_BACK_VALUE_MASK: return 1;
- case GL_STENCIL_BACK_WRITEMASK: return 1;
- case GL_STENCIL_BITS: return 1;
- case GL_STENCIL_CLEAR_VALUE: return 1;
- case GL_STENCIL_FAIL: return 1;
- case GL_STENCIL_FUNC: return 1;
- case GL_STENCIL_PASS_DEPTH_FAIL: return 1;
- case GL_STENCIL_PASS_DEPTH_PASS: return 1;
- case GL_STENCIL_REF: return 1;
- case GL_STENCIL_TEST: return 1;
- case GL_STENCIL_VALUE_MASK: return 1;
- case GL_STENCIL_WRITEMASK: return 1;
- case GL_SUBPIXEL_BITS: return 1;
- case GL_TEXTURE_BINDING_2D: return 1; // (* actually a CanvasTexture*)
- case GL_TEXTURE_BINDING_CUBE_MAP: return 1; // (* actually a CanvasTexture*)
- case GL_UNPACK_ALIGNMENT: return 1;
- case GL_VIEWPORT: return 4;
- }
-
- return -1;
-}
-
-bool GraphicsContext3D::getBoolean(unsigned long pname)
-{
- int size = sizeForGetParam(pname);
- if (size < 1)
- return 0;
-
- ensureContext(m_contextObj);
-
- bool isAlloced = false;
- GLboolean buf[4];
- GLboolean* pbuf = buf;
-
- if (size > 4) {
- pbuf = (GLboolean*) malloc(size * sizeof(GLboolean));
- isAlloced = true;
- }
-
- ::glGetBooleanv(pname, pbuf);
-
- bool value = pbuf[0];
-
- if (isAlloced)
- free(pbuf);
-
- return value;
-}
-
-PassRefPtr<CanvasUnsignedByteArray> GraphicsContext3D::getBooleanv(unsigned long pname)
-{
- int size = sizeForGetParam(pname);
- if (size < 1)
- return 0;
-
- ensureContext(m_contextObj);
-
- RefPtr<CanvasUnsignedByteArray> array = CanvasUnsignedByteArray::create(size);
- bool isAlloced = false;
- GLboolean buf[4];
- GLboolean* pbuf = buf;
-
- if (size > 4) {
- pbuf = (GLboolean*) malloc(size * sizeof(GLboolean));
- isAlloced = true;
- }
-
- ::glGetBooleanv(pname, pbuf);
-
- for (int i = 0; i < size; ++i)
- array->set(i, static_cast<unsigned char>(pbuf[i]));
-
- if (isAlloced)
- free(pbuf);
-
- return array;
-}
-
-float GraphicsContext3D::getFloat(unsigned long pname)
+void GraphicsContext3D::getBooleanv(unsigned long pname, unsigned char* value)
{
- int size = sizeForGetParam(pname);
- if (size < 1)
- return 0;
-
ensureContext(m_contextObj);
-
- bool isAlloced = false;
- GLfloat buf[4];
- GLfloat* pbuf = buf;
-
- if (size > 4) {
- pbuf = (GLfloat*) malloc(size * sizeof(GLfloat));
- isAlloced = true;
- }
-
- ::glGetFloatv(pname, pbuf);
-
- float value = pbuf[0];
-
- if (isAlloced)
- free(pbuf);
-
- return value;
+ ::glGetBooleanv(pname, value);
}
-PassRefPtr<CanvasFloatArray> GraphicsContext3D::getFloatv(unsigned long pname)
+void GraphicsContext3D::getBufferParameteriv(unsigned long target, unsigned long pname, int* value)
{
- int size = sizeForGetParam(pname);
- if (size < 1)
- return 0;
-
ensureContext(m_contextObj);
-
- RefPtr<CanvasFloatArray> array = CanvasFloatArray::create(size);
- bool isAlloced = false;
- GLfloat buf[4];
- GLfloat* pbuf = buf;
-
- if (size > 4) {
- pbuf = (GLfloat*) malloc(size * sizeof(GLfloat));
- isAlloced = true;
- }
-
- ::glGetFloatv(pname, pbuf);
-
- for (int i = 0; i < size; ++i)
- array->set(i, static_cast<float>(pbuf[i]));
-
- if (isAlloced)
- free(pbuf);
-
- return array;
+ ::glGetBufferParameteriv(target, pname, value);
}
-int GraphicsContext3D::getInteger(unsigned long pname)
+void GraphicsContext3D::getFloatv(unsigned long pname, float* value)
{
- int size = sizeForGetParam(pname);
- if (size < 1)
- return 0;
-
ensureContext(m_contextObj);
-
- bool isAlloced = false;
- GLint buf[4];
- GLint* pbuf = buf;
-
- if (size > 4) {
- pbuf = (GLint*) malloc(size * sizeof(GLint));
- isAlloced = true;
- }
-
- ::glGetIntegerv(pname, pbuf);
-
- int value = pbuf[0];
-
- if (isAlloced)
- free(pbuf);
-
- return value;
+ ::glGetFloatv(pname, value);
}
-PassRefPtr<CanvasIntArray> GraphicsContext3D::getIntegerv(unsigned long pname)
+void GraphicsContext3D::getFramebufferAttachmentParameteriv(unsigned long target, unsigned long attachment, unsigned long pname, int* value)
{
- int size = sizeForGetParam(pname);
- if (size < 1)
- return 0;
-
ensureContext(m_contextObj);
-
- RefPtr<CanvasIntArray> array = CanvasIntArray::create(size);
- bool isAlloced = false;
- GLint buf[4];
- GLint* pbuf = buf;
-
- if (size > 4) {
- pbuf = (GLint*) malloc(size * sizeof(GLint));
- isAlloced = true;
- }
-
- ::glGetIntegerv(pname, pbuf);
-
- for (int i = 0; i < size; ++i)
- array->set(i, static_cast<int>(pbuf[i]));
-
- if (isAlloced)
- free(pbuf);
-
- return array;
+ ::glGetFramebufferAttachmentParameterivEXT(target, attachment, pname, value);
}
-int GraphicsContext3D::getBufferParameteri(unsigned long target, unsigned long pname)
+void GraphicsContext3D::getIntegerv(unsigned long pname, int* value)
{
ensureContext(m_contextObj);
- GLint data;
- ::glGetBufferParameteriv(target, pname, &data);
- return data;
+ ::glGetIntegerv(pname, value);
}
-PassRefPtr<CanvasIntArray> GraphicsContext3D::getBufferParameteriv(unsigned long target, unsigned long pname)
+void GraphicsContext3D::getProgramiv(WebGLProgram* program, unsigned long pname, int* value)
{
ensureContext(m_contextObj);
- RefPtr<CanvasIntArray> array = CanvasIntArray::create(1);
- GLint data;
- ::glGetBufferParameteriv(target, pname, &data);
- array->set(0, static_cast<int>(data));
-
- return array;
+ ::glGetProgramiv((GLuint) program->object(), pname, value);
}
-int GraphicsContext3D::getFramebufferAttachmentParameteri(unsigned long target, unsigned long attachment, unsigned long pname)
+String GraphicsContext3D::getProgramInfoLog(WebGLProgram* program)
{
- ensureContext(m_contextObj);
- GLint data;
- ::glGetFramebufferAttachmentParameterivEXT(target, attachment, pname, &data);
- return data;
-}
-
-PassRefPtr<CanvasIntArray> GraphicsContext3D::getFramebufferAttachmentParameteriv(unsigned long target, unsigned long attachment, unsigned long pname)
-{
- ensureContext(m_contextObj);
- RefPtr<CanvasIntArray> array = CanvasIntArray::create(1);
- GLint data;
- ::glGetFramebufferAttachmentParameterivEXT(target, attachment, pname, &data);
- array->set(0, static_cast<int>(data));
-
- return array;
-}
-
-int GraphicsContext3D::getProgrami(CanvasProgram* program, unsigned long pname)
-{
- ensureContext(m_contextObj);
- GLint data;
- ::glGetProgramiv((GLuint) program->object(), pname, &data);
- return data;
-}
-
-PassRefPtr<CanvasIntArray> GraphicsContext3D::getProgramiv(CanvasProgram* program, unsigned long pname)
-{
- ensureContext(m_contextObj);
- RefPtr<CanvasIntArray> array = CanvasIntArray::create(1);
- GLint data;
- ::glGetProgramiv((GLuint) program->object(), pname, &data);
- array->set(0, static_cast<int>(data));
-
- return array;
-}
-
-String GraphicsContext3D::getProgramInfoLog(CanvasProgram* program)
-{
- if (!program)
- return String();
+ ASSERT(program);
ensureContext(m_contextObj);
GLint length;
::glGetProgramiv((GLuint) program->object(), GL_INFO_LOG_LENGTH, &length);
GLsizei size;
- GLchar* info = (GLchar*) malloc(length);
+ GLchar* info = (GLchar*) fastMalloc(length);
+ if (!info)
+ return "";
+
::glGetProgramInfoLog((GLuint) program->object(), length, &size, info);
String s(info);
- free(info);
+ fastFree(info);
return s;
}
-int GraphicsContext3D::getRenderbufferParameteri(unsigned long target, unsigned long pname)
-{
- ensureContext(m_contextObj);
- GLint data;
- ::glGetBufferParameteriv(target, pname, &data);
- return data;
-}
-
-PassRefPtr<CanvasIntArray> GraphicsContext3D::getRenderbufferParameteriv(unsigned long target, unsigned long pname)
+void GraphicsContext3D::getRenderbufferParameteriv(unsigned long target, unsigned long pname, int* value)
{
ensureContext(m_contextObj);
- RefPtr<CanvasIntArray> array = CanvasIntArray::create(1);
- GLint data;
- ::glGetBufferParameteriv(target, pname, &data);
- array->set(0, static_cast<int>(data));
-
- return array;
+ ::glGetRenderbufferParameterivEXT(target, pname, value);
}
-int GraphicsContext3D::getShaderi(CanvasShader* shader, unsigned long pname)
+void GraphicsContext3D::getShaderiv(WebGLShader* shader, unsigned long pname, int* value)
{
- if (!shader)
- return 0;
-
- ensureContext(m_contextObj);
- GLint data;
- ::glGetShaderiv((GLuint) shader->object(), pname, &data);
- return data;
-}
-
-PassRefPtr<CanvasIntArray> GraphicsContext3D::getShaderiv(CanvasShader* shader, unsigned long pname)
-{
- if (!shader)
- return 0;
+ ASSERT(shader);
ensureContext(m_contextObj);
- RefPtr<CanvasIntArray> array = CanvasIntArray::create(1);
- GLint data;
- ::glGetShaderiv((GLuint) shader->object(), pname, &data);
- array->set(0, static_cast<int>(data));
-
- return array;
+ ::glGetShaderiv((GLuint) shader->object(), pname, value);
}
-String GraphicsContext3D::getShaderInfoLog(CanvasShader* shader)
+String GraphicsContext3D::getShaderInfoLog(WebGLShader* shader)
{
- if (!shader)
- return String();
+ ASSERT(shader);
ensureContext(m_contextObj);
GLint length;
::glGetShaderiv((GLuint) shader->object(), GL_INFO_LOG_LENGTH, &length);
GLsizei size;
- GLchar* info = (GLchar*) malloc(length);
+ GLchar* info = (GLchar*) fastMalloc(length);
+ if (!info)
+ return "";
+
::glGetShaderInfoLog((GLuint) shader->object(), length, &size, info);
String s(info);
- free(info);
+ fastFree(info);
return s;
}
-String GraphicsContext3D::getShaderSource(CanvasShader* shader)
+String GraphicsContext3D::getShaderSource(WebGLShader* shader)
{
- if (!shader)
- return String();
-
+ ASSERT(shader);
+
ensureContext(m_contextObj);
GLint length;
::glGetShaderiv((GLuint) shader->object(), GL_SHADER_SOURCE_LENGTH, &length);
GLsizei size;
- GLchar* info = (GLchar*) malloc(length);
+ GLchar* info = (GLchar*) fastMalloc(length);
+ if (!info)
+ return "";
+
::glGetShaderSource((GLuint) shader->object(), length, &size, info);
String s(info);
- free(info);
+ fastFree(info);
return s;
}
-float GraphicsContext3D::getTexParameterf(unsigned long target, unsigned long pname)
+void GraphicsContext3D::getTexParameterfv(unsigned long target, unsigned long pname, float* value)
{
ensureContext(m_contextObj);
- GLfloat data;
- ::glGetTexParameterfv(target, pname, &data);
- return data;
+ ::glGetTexParameterfv(target, pname, value);
}
-PassRefPtr<CanvasFloatArray> GraphicsContext3D::getTexParameterfv(unsigned long target, unsigned long pname)
+void GraphicsContext3D::getTexParameteriv(unsigned long target, unsigned long pname, int* value)
{
ensureContext(m_contextObj);
- RefPtr<CanvasFloatArray> array = CanvasFloatArray::create(1);
- GLfloat data;
- ::glGetTexParameterfv(target, pname, &data);
- array->set(0, static_cast<float>(data));
-
- return array;
+ ::glGetTexParameteriv(target, pname, value);
}
-int GraphicsContext3D::getTexParameteri(unsigned long target, unsigned long pname)
+void GraphicsContext3D::getUniformfv(WebGLProgram* program, long location, float* value)
{
ensureContext(m_contextObj);
- GLint data;
- ::glGetTexParameteriv(target, pname, &data);
- return data;
+ ::glGetUniformfv((GLuint) program->object(), location, value);
}
-PassRefPtr<CanvasIntArray> GraphicsContext3D::getTexParameteriv(unsigned long target, unsigned long pname)
+void GraphicsContext3D::getUniformiv(WebGLProgram* program, long location, int* value)
{
ensureContext(m_contextObj);
- RefPtr<CanvasIntArray> array = CanvasIntArray::create(1);
- GLint data;
- ::glGetTexParameteriv(target, pname, &data);
- array->set(0, static_cast<int>(data));
-
- return array;
-}
-
-float GraphicsContext3D::getUniformf(CanvasProgram* program, long location)
-{
- // FIXME: We need to query glGetUniformLocation to determine the size needed
- UNUSED_PARAM(program);
- UNUSED_PARAM(location);
- notImplemented();
- return 0;
+ ::glGetUniformiv((GLuint) program->object(), location, value);
}
-PassRefPtr<CanvasFloatArray> GraphicsContext3D::getUniformfv(CanvasProgram* program, long location)
+long GraphicsContext3D::getUniformLocation(WebGLProgram* program, const String& name)
{
- // FIXME: We need to query glGetUniformLocation to determine the size needed
- UNUSED_PARAM(program);
- UNUSED_PARAM(location);
- notImplemented();
- return 0;
-}
-
-int GraphicsContext3D::getUniformi(CanvasProgram* program, long location)
-{
- // FIXME: We need to query glGetUniformLocation to determine the size needed
- UNUSED_PARAM(program);
- UNUSED_PARAM(location);
- notImplemented();
- return 0;
-}
-
-PassRefPtr<CanvasIntArray> GraphicsContext3D::getUniformiv(CanvasProgram* program, long location)
-{
- // FIXME: We need to query glGetUniformLocation to determine the size needed
- UNUSED_PARAM(program);
- UNUSED_PARAM(location);
- notImplemented();
- return 0;
-}
-
-long GraphicsContext3D::getUniformLocation(CanvasProgram* program, const String& name)
-{
- if (!program)
- return -1;
+ ASSERT(program);
ensureContext(m_contextObj);
return ::glGetUniformLocation((GLuint) program->object(), name.utf8().data());
}
-static int sizeForGetVertexAttribParam(unsigned long pname)
-{
- switch(pname) {
- case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING: return 1; // (* actually a CanvasBuffer*)
- case GL_VERTEX_ATTRIB_ARRAY_ENABLED: return 1;
- case GL_VERTEX_ATTRIB_ARRAY_SIZE: return 1;
- case GL_VERTEX_ATTRIB_ARRAY_STRIDE: return 1;
- case GL_VERTEX_ATTRIB_ARRAY_TYPE: return 1;
- case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED: return 1;
- case GL_CURRENT_VERTEX_ATTRIB: return 4;
- }
-
- return -1;
-}
-
-float GraphicsContext3D::getVertexAttribf(unsigned long index, unsigned long pname)
-{
- ensureContext(m_contextObj);
- GLfloat buf[4];
- ::glGetVertexAttribfv(index, pname, buf);
- return buf[0];
-}
-
-PassRefPtr<CanvasFloatArray> GraphicsContext3D::getVertexAttribfv(unsigned long index, unsigned long pname)
-{
- int size = sizeForGetVertexAttribParam(pname);
- if (size < 1)
- return 0;
-
- ensureContext(m_contextObj);
-
- RefPtr<CanvasFloatArray> array = CanvasFloatArray::create(size);
- GLfloat buf[4];
- ::glGetVertexAttribfv(index, pname, buf);
-
- for (int i = 0; i < size; ++i)
- array->set(i, static_cast<float>(buf[i]));
-
- return array;
-}
-
-int GraphicsContext3D::getVertexAttribi(unsigned long index, unsigned long pname)
+void GraphicsContext3D::getVertexAttribfv(unsigned long index, unsigned long pname, float* value)
{
ensureContext(m_contextObj);
- GLint buf[4];
- ::glGetVertexAttribiv(index, pname, buf);
- return buf[0];
+ ::glGetVertexAttribfv(index, pname, value);
}
-PassRefPtr<CanvasIntArray> GraphicsContext3D::getVertexAttribiv(unsigned long index, unsigned long pname)
+void GraphicsContext3D::getVertexAttribiv(unsigned long index, unsigned long pname, int* value)
{
- int size = sizeForGetVertexAttribParam(pname);
- if (size < 1)
- return 0;
-
ensureContext(m_contextObj);
-
- RefPtr<CanvasIntArray> array = CanvasIntArray::create(size);
- GLint buf[4];
- ::glGetVertexAttribiv(index, pname, buf);
-
- for (int i = 0; i < size; ++i)
- array->set(i, static_cast<int>(buf[i]));
-
- return array;
+ ::glGetVertexAttribiv(index, pname, value);
}
long GraphicsContext3D::getVertexAttribOffset(unsigned long index, unsigned long pname)
@@ -1552,18 +1128,21 @@ static void imageToTexture(Image* image, unsigned target, unsigned level)
size_t textureWidth = CGImageGetWidth(textureImage);
size_t textureHeight = CGImageGetHeight(textureImage);
- GLubyte* textureData = (GLubyte*) malloc(textureWidth * textureHeight * 4);
+ GLubyte* textureData = (GLubyte*) fastMalloc(textureWidth * textureHeight * 4);
+ if (!textureData)
+ return;
+
CGContextRef textureContext = CGBitmapContextCreate(textureData, textureWidth, textureHeight, 8, textureWidth * 4,
CGImageGetColorSpace(textureImage), kCGImageAlphaPremultipliedLast);
-
+ CGContextSetBlendMode(textureContext, kCGBlendModeCopy);
CGContextDrawImage(textureContext, CGRectMake(0, 0, (CGFloat)textureWidth, (CGFloat)textureHeight), textureImage);
CGContextRelease(textureContext);
::glTexImage2D(target, level, GL_RGBA, textureWidth, textureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, textureData);
- free(textureData);
+ fastFree(textureData);
}
-int GraphicsContext3D::texImage2D(unsigned target, unsigned level, unsigned internalformat, unsigned width, unsigned height, unsigned border, unsigned format, unsigned type, CanvasArray* pixels)
+int GraphicsContext3D::texImage2D(unsigned target, unsigned level, unsigned internalformat, unsigned width, unsigned height, unsigned border, unsigned format, unsigned type, WebGLArray* pixels)
{
// FIXME: Need to do bounds checking on the buffer here.
::glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels->baseAddress());
@@ -1585,39 +1164,15 @@ int GraphicsContext3D::texImage2D(unsigned target, unsigned level, unsigned inte
return -1;
}
-int GraphicsContext3D::texImage2D(unsigned target, unsigned level, HTMLImageElement* image, bool flipY, bool premultiplyAlpha)
+int GraphicsContext3D::texImage2D(unsigned target, unsigned level, Image* image, bool flipY, bool premultiplyAlpha)
{
// FIXME: need to support flipY and premultiplyAlpha
UNUSED_PARAM(flipY);
UNUSED_PARAM(premultiplyAlpha);
-
- if (!image)
- return -1;
+ ASSERT(image);
ensureContext(m_contextObj);
- CachedImage* cachedImage = image->cachedImage();
- if (!cachedImage)
- return -1;
-
- imageToTexture(cachedImage->image(), target, level);
- return 0;
-}
-
-int GraphicsContext3D::texImage2D(unsigned target, unsigned level, HTMLCanvasElement* canvas, bool flipY, bool premultiplyAlpha)
-{
- // FIXME: need to support flipY and premultiplyAlpha
- UNUSED_PARAM(flipY);
- UNUSED_PARAM(premultiplyAlpha);
-
- if (!canvas)
- return -1;
-
- ensureContext(m_contextObj);
- ImageBuffer* buffer = canvas->buffer();
- if (!buffer)
- return -1;
-
- imageToTexture(buffer->image(), target, level);
+ imageToTexture(image, target, level);
return 0;
}
@@ -1634,7 +1189,7 @@ int GraphicsContext3D::texImage2D(unsigned target, unsigned level, HTMLVideoElem
return -1;
}
-int GraphicsContext3D::texSubImage2D(unsigned target, unsigned level, unsigned xoff, unsigned yoff, unsigned width, unsigned height, unsigned format, unsigned type, CanvasArray* pixels)
+int GraphicsContext3D::texSubImage2D(unsigned target, unsigned level, unsigned xoff, unsigned yoff, unsigned width, unsigned height, unsigned format, unsigned type, WebGLArray* pixels)
{
// FIXME: we will need to deal with PixelStore params when dealing with image buffers that differ from the subimage size
UNUSED_PARAM(target);
@@ -1664,7 +1219,7 @@ int GraphicsContext3D::texSubImage2D(unsigned target, unsigned level, unsigned x
return -1;
}
-int GraphicsContext3D::texSubImage2D(unsigned target, unsigned level, unsigned xoff, unsigned yoff, unsigned width, unsigned height, HTMLImageElement* image, bool flipY, bool premultiplyAlpha)
+int GraphicsContext3D::texSubImage2D(unsigned target, unsigned level, unsigned xoff, unsigned yoff, unsigned width, unsigned height, Image* image, bool flipY, bool premultiplyAlpha)
{
// FIXME: we will need to deal with PixelStore params when dealing with image buffers that differ from the subimage size
UNUSED_PARAM(target);
@@ -1681,23 +1236,6 @@ int GraphicsContext3D::texSubImage2D(unsigned target, unsigned level, unsigned x
return -1;
}
-int GraphicsContext3D::texSubImage2D(unsigned target, unsigned level, unsigned xoff, unsigned yoff, unsigned width, unsigned height, HTMLCanvasElement* canvas, bool flipY, bool premultiplyAlpha)
-{
- // FIXME: we will need to deal with PixelStore params when dealing with image buffers that differ from the subimage size
- UNUSED_PARAM(target);
- UNUSED_PARAM(level);
- UNUSED_PARAM(xoff);
- UNUSED_PARAM(yoff);
- UNUSED_PARAM(width);
- UNUSED_PARAM(height);
- UNUSED_PARAM(canvas);
-
- // FIXME: need to support flipY and premultiplyAlpha
- UNUSED_PARAM(flipY);
- UNUSED_PARAM(premultiplyAlpha);
- return -1;
-}
-
int GraphicsContext3D::texSubImage2D(unsigned target, unsigned level, unsigned xoff, unsigned yoff, unsigned width, unsigned height, HTMLVideoElement* video, bool flipY, bool premultiplyAlpha)
{
// FIXME: we will need to deal with PixelStore params when dealing with image buffers that differ from the subimage size
@@ -1745,7 +1283,7 @@ unsigned GraphicsContext3D::createRenderbuffer()
return o;
}
-unsigned GraphicsContext3D::createShader(ShaderType type)
+unsigned GraphicsContext3D::createShader(unsigned long type)
{
ensureContext(m_contextObj);
return glCreateShader((type == FRAGMENT_SHADER) ? GL_FRAGMENT_SHADER : GL_VERTEX_SHADER);
@@ -1817,6 +1355,11 @@ int GraphicsContext3D::sizeInBytes(int type)
}
}
+void GraphicsContext3D::synthesizeGLError(unsigned long error)
+{
+ m_syntheticErrors.add(error);
+}
+
}
#endif // ENABLE(3D_CANVAS)
diff --git a/WebCore/platform/graphics/mac/GraphicsLayerCA.h b/WebCore/platform/graphics/mac/GraphicsLayerCA.h
index 8cf51b4..8024091 100644
--- a/WebCore/platform/graphics/mac/GraphicsLayerCA.h
+++ b/WebCore/platform/graphics/mac/GraphicsLayerCA.h
@@ -54,6 +54,7 @@ public:
// for hosting this GraphicsLayer in a native layer hierarchy
virtual NativeLayer nativeLayer() const;
+ virtual bool setChildren(const Vector<GraphicsLayer*>&);
virtual void addChild(GraphicsLayer*);
virtual void addChildAtIndex(GraphicsLayer*, int index);
virtual void addChildAbove(GraphicsLayer* layer, GraphicsLayer* sibling);
diff --git a/WebCore/platform/graphics/mac/GraphicsLayerCA.mm b/WebCore/platform/graphics/mac/GraphicsLayerCA.mm
index b351956..dea6bfc 100644
--- a/WebCore/platform/graphics/mac/GraphicsLayerCA.mm
+++ b/WebCore/platform/graphics/mac/GraphicsLayerCA.mm
@@ -47,6 +47,7 @@
#import "WebLayer.h"
#import "WebTiledLayer.h"
#import <limits.h>
+#import <objc/objc-auto.h>
#import <wtf/CurrentTime.h>
#import <wtf/UnusedParam.h>
#import <wtf/RetainPtr.h>
@@ -298,6 +299,18 @@ static void clearLayerBackgroundColor(PlatformLayer* layer)
[layer setBackgroundColor:0];
}
+static void safeSetSublayers(CALayer* layer, NSArray* sublayers)
+{
+ // Workaround for <rdar://problem/7390716>: -[CALayer setSublayers:] crashes if sublayers is an empty array, or nil, under GC.
+ if (objc_collectingEnabled() && ![sublayers count]) {
+ while ([[layer sublayers] count])
+ [[[layer sublayers] objectAtIndex:0] removeFromSuperlayer];
+ return;
+ }
+
+ [layer setSublayers:sublayers];
+}
+
static bool caValueFunctionSupported()
{
static bool sHaveValueFunction = [CAPropertyAnimation instancesRespondToSelector:@selector(setValueFunction:)];
@@ -315,18 +328,6 @@ GraphicsLayer::CompositingCoordinatesOrientation GraphicsLayer::compositingCoord
return CompositingCoordinatesBottomUp;
}
-bool GraphicsLayer::showDebugBorders()
-{
- static bool showDebugBorders = [[NSUserDefaults standardUserDefaults] boolForKey:@"WebCoreLayerBorders"];
- return showDebugBorders;
-}
-
-bool GraphicsLayer::showRepaintCounter()
-{
- static bool showRepaintCounter = [[NSUserDefaults standardUserDefaults] boolForKey:@"WebCoreLayerRepaintCounter"];
- return showRepaintCounter;
-}
-
static NSDictionary* nullActionsDictionary()
{
NSNull* nullValue = [NSNull null];
@@ -352,13 +353,13 @@ PassOwnPtr<GraphicsLayer> GraphicsLayer::create(GraphicsLayerClient* client)
}
GraphicsLayerCA::GraphicsLayerCA(GraphicsLayerClient* client)
-: GraphicsLayer(client)
-, m_contentsLayerPurpose(NoContentsLayer)
-, m_contentsLayerHasBackgroundColor(false)
-, m_uncommittedChanges(NoChange)
+ : GraphicsLayer(client)
+ , m_contentsLayerPurpose(NoContentsLayer)
+ , m_contentsLayerHasBackgroundColor(false)
+ , m_uncommittedChanges(NoChange)
#if ENABLE(3D_CANVAS)
-, m_platformGraphicsContext3D(NullPlatformGraphicsContext3D)
-, m_platformTexture(NullPlatform3DObject)
+ , m_platformGraphicsContext3D(NullPlatformGraphicsContext3D)
+ , m_platformTexture(NullPlatform3DObject)
#endif
{
BEGIN_BLOCK_OBJC_EXCEPTIONS
@@ -409,6 +410,15 @@ NativeLayer GraphicsLayerCA::nativeLayer() const
return m_layer.get();
}
+bool GraphicsLayerCA::setChildren(const Vector<GraphicsLayer*>& children)
+{
+ bool childrenChanged = GraphicsLayer::setChildren(children);
+ if (childrenChanged)
+ noteLayerPropertyChanged(ChildrenChanged);
+
+ return childrenChanged;
+}
+
void GraphicsLayerCA::addChild(GraphicsLayer* childLayer)
{
GraphicsLayer::addChild(childLayer);
@@ -882,17 +892,16 @@ void GraphicsLayerCA::updateSublayerList()
[newSublayers makeObjectsPerformSelector:@selector(removeFromSuperlayer)];
if (m_transformLayer) {
- [m_transformLayer.get() setSublayers:newSublayers];
+ safeSetSublayers(m_transformLayer.get(), newSublayers);
if (m_contentsLayer) {
// If we have a transform layer, then the contents layer is parented in the
// primary layer (which is itself a child of the transform layer).
- [m_layer.get() setSublayers:nil];
+ safeSetSublayers(m_layer.get(), nil);
[m_layer.get() addSublayer:m_contentsLayer.get()];
}
- } else {
- [m_layer.get() setSublayers:newSublayers];
- }
+ } else
+ safeSetSublayers(m_layer.get(), newSublayers);
[newSublayers release];
}
@@ -1757,7 +1766,7 @@ void GraphicsLayerCA::swapFromOrToTiledLayer(bool useTiledLayer)
}
[m_layer.get() setLayerOwner:this];
- [m_layer.get() setSublayers:[oldLayer.get() sublayers]];
+ safeSetSublayers(m_layer.get(), [oldLayer.get() sublayers]);
[[oldLayer.get() superlayer] replaceSublayer:oldLayer.get() with:m_layer.get()];
diff --git a/WebCore/platform/graphics/mac/IconMac.mm b/WebCore/platform/graphics/mac/IconMac.mm
index 63abe59..aee7234 100644
--- a/WebCore/platform/graphics/mac/IconMac.mm
+++ b/WebCore/platform/graphics/mac/IconMac.mm
@@ -39,27 +39,32 @@ Icon::~Icon()
{
}
-PassRefPtr<Icon> Icon::createIconForFile(const String& filename)
+PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames)
{
- // Don't pass relative filenames -- we don't want a result that depends on the current directory.
- // Need 0U here to disambiguate String::operator[] from operator(NSString*, int)[]
- if (filename.isEmpty() || filename[0U] != '/')
+ if (filenames.isEmpty())
return 0;
- NSImage* image = [[NSWorkspace sharedWorkspace] iconForFile:filename];
- if (!image)
- return 0;
+ bool useIconFromFirstFile;
+#ifdef BUILDING_ON_TIGER
+ // FIXME: find a better image for multiple files to use on Tiger.
+ useIconFromFirstFile = true;
+#else
+ useIconFromFirstFile = filenames.size() == 1;
+#endif
+ if (useIconFromFirstFile) {
+ // Don't pass relative filenames -- we don't want a result that depends on the current directory.
+ // Need 0U here to disambiguate String::operator[] from operator(NSString*, int)[]
+ if (filenames[0].isEmpty() || filenames[0][0U] != '/')
+ return 0;
- return adoptRef(new Icon(image));
-}
+ NSImage* image = [[NSWorkspace sharedWorkspace] iconForFile:filenames[0]];
+ if (!image)
+ return 0;
-PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames)
-{
- if (filenames.isEmpty())
- return 0;
+ return adoptRef(new Icon(image));
+ }
#ifdef BUILDING_ON_TIGER
- // FIXME: find a better image to use on Tiger.
- return createIconForFile(filenames[0]);
+ return 0;
#else
NSImage* image = [NSImage imageNamed:NSImageNameMultipleDocuments];
if (!image)
diff --git a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h
index 0a63626..7aaf95d 100644
--- a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h
+++ b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h
@@ -101,6 +101,9 @@ private:
void setVolume(float);
void setPreservesPitch(bool);
+ bool hasClosedCaptions() const;
+ void setClosedCaptionsVisible(bool);
+
void setEndTime(float time);
int dataRate() const;
diff --git a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm
index 30d0c82..dfb5958 100644
--- a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm
+++ b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm
@@ -736,8 +736,13 @@ bool MediaPlayerPrivate::hasAudio() const
}
bool MediaPlayerPrivate::supportsFullscreen() const
-{
+{
+#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
return true;
+#else
+ // See <rdar://problem/7389945>
+ return false;
+#endif
}
void MediaPlayerPrivate::setVolume(float volume)
@@ -746,6 +751,27 @@ void MediaPlayerPrivate::setVolume(float volume)
[m_qtMovie.get() setVolume:volume];
}
+bool MediaPlayerPrivate::hasClosedCaptions() const
+{
+ if (!metaDataAvailable())
+ return false;
+ return wkQTMovieHasClosedCaptions(m_qtMovie.get());
+}
+
+void MediaPlayerPrivate::setClosedCaptionsVisible(bool closedCaptionsVisible)
+{
+ if (metaDataAvailable()) {
+ wkQTMovieSetShowClosedCaptions(m_qtMovie.get(), closedCaptionsVisible);
+
+#if USE(ACCELERATED_COMPOSITING) && (!defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD))
+ if (closedCaptionsVisible && m_qtVideoLayer) {
+ // Captions will be rendered upsided down unless we flag the movie as flipped (again). See <rdar://7408440>.
+ [m_qtVideoLayer.get() setGeometryFlipped:YES];
+ }
+#endif
+ }
+}
+
void MediaPlayerPrivate::setRate(float rate)
{
if (m_qtMovie)
@@ -1158,10 +1184,10 @@ void MediaPlayerPrivate::paint(GraphicsContext* context, const IntRect& r)
TextRun textRun(text.characters(), text.length());
const Color color(255, 0, 0);
context->scale(FloatSize(1.0f, -1.0f));
- context->setStrokeColor(color);
+ context->setStrokeColor(color, styleToUse->colorSpace());
context->setStrokeStyle(SolidStroke);
context->setStrokeThickness(1.0f);
- context->setFillColor(color);
+ context->setFillColor(color, styleToUse->colorSpace());
context->drawText(styleToUse->font(), textRun, IntPoint(2, -3));
}
}