diff options
Diffstat (limited to 'WebCore/rendering')
71 files changed, 1770 insertions, 1201 deletions
diff --git a/WebCore/rendering/FixedTableLayout.cpp b/WebCore/rendering/FixedTableLayout.cpp index 09af518..4d6b88c 100644 --- a/WebCore/rendering/FixedTableLayout.cpp +++ b/WebCore/rendering/FixedTableLayout.cpp @@ -166,8 +166,7 @@ int FixedTableLayout::calcWidthArray(int) int usedSpan = 0; int i = 0; - while (usedSpan < span) { - ASSERT(cCol + i < nEffCols); + while (usedSpan < span && cCol + i < nEffCols) { int eSpan = m_table->spanOfEffCol(cCol + i); // Only set if no col element has already set it. if (m_width[cCol + i].isAuto() && w.type() != Auto) { diff --git a/WebCore/rendering/InlineFlowBox.cpp b/WebCore/rendering/InlineFlowBox.cpp index e31bf4f..05d8fcd 100644 --- a/WebCore/rendering/InlineFlowBox.cpp +++ b/WebCore/rendering/InlineFlowBox.cpp @@ -252,7 +252,7 @@ void InlineFlowBox::determineSpacingForFlowBoxes(bool lastLine, RenderObject* en } } -int InlineFlowBox::placeBoxesHorizontally(int xPos, bool& needsWordSpacing) +int InlineFlowBox::placeBoxesHorizontally(int xPos, bool& needsWordSpacing, GlyphOverflowAndFallbackFontsMap& textBoxDataMap) { // Set our x position. setX(xPos); @@ -289,7 +289,8 @@ int InlineFlowBox::placeBoxesHorizontally(int xPos, bool& needsWordSpacing) int letterSpacing = min(0, (int)rt->style(m_firstLine)->font().letterSpacing()); rightLayoutOverflow = max(xPos + text->width() - letterSpacing, rightLayoutOverflow); - GlyphOverflow* glyphOverflow = static_cast<InlineTextBox*>(curr)->glyphOverflow(); + GlyphOverflowAndFallbackFontsMap::iterator it = textBoxDataMap.find(static_cast<InlineTextBox*>(curr)); + GlyphOverflow* glyphOverflow = it == textBoxDataMap.end() ? 0 : &it->second.second; int leftGlyphOverflow = -strokeOverflow - (glyphOverflow ? glyphOverflow->left : 0); int rightGlyphOverflow = strokeOverflow - letterSpacing + (glyphOverflow ? glyphOverflow->right : 0); @@ -319,7 +320,7 @@ int InlineFlowBox::placeBoxesHorizontally(int xPos, bool& needsWordSpacing) if (curr->renderer()->isRenderInline()) { InlineFlowBox* flow = static_cast<InlineFlowBox*>(curr); xPos += flow->marginLeft(); - xPos = flow->placeBoxesHorizontally(xPos, needsWordSpacing); + xPos = flow->placeBoxesHorizontally(xPos, needsWordSpacing, textBoxDataMap); xPos += flow->marginRight(); leftLayoutOverflow = min(leftLayoutOverflow, flow->leftLayoutOverflow()); rightLayoutOverflow = max(rightLayoutOverflow, flow->rightLayoutOverflow()); @@ -391,7 +392,7 @@ static int verticalPositionForBox(InlineBox* curr, bool firstLine) } void InlineFlowBox::computeLogicalBoxHeights(int& maxPositionTop, int& maxPositionBottom, - int& maxAscent, int& maxDescent, bool strictMode) + int& maxAscent, int& maxDescent, bool strictMode, GlyphOverflowAndFallbackFontsMap& textBoxDataMap) { if (isRootInlineBox()) { // Examine our root box. @@ -416,8 +417,10 @@ void InlineFlowBox::computeLogicalBoxHeights(int& maxPositionTop, int& maxPositi int lineHeight; int baseline; Vector<const SimpleFontData*>* usedFonts = 0; - if (curr->isInlineTextBox()) - usedFonts = static_cast<InlineTextBox*>(curr)->fallbackFonts(); + if (curr->isInlineTextBox()) { + GlyphOverflowAndFallbackFontsMap::iterator it = textBoxDataMap.find(static_cast<InlineTextBox*>(curr)); + usedFonts = it == textBoxDataMap.end() ? 0 : &it->second.first; + } if (usedFonts) { usedFonts->append(curr->renderer()->style(m_firstLine)->font().primaryFont()); @@ -468,7 +471,7 @@ void InlineFlowBox::computeLogicalBoxHeights(int& maxPositionTop, int& maxPositi } if (curr->isInlineFlowBox()) - static_cast<InlineFlowBox*>(curr)->computeLogicalBoxHeights(maxPositionTop, maxPositionBottom, maxAscent, maxDescent, strictMode); + static_cast<InlineFlowBox*>(curr)->computeLogicalBoxHeights(maxPositionTop, maxPositionBottom, maxAscent, maxDescent, strictMode, textBoxDataMap); } } @@ -529,7 +532,7 @@ void InlineFlowBox::placeBoxesVertically(int yPos, int maxHeight, int maxAscent, } } -void InlineFlowBox::computeVerticalOverflow(int lineTop, int lineBottom, bool strictMode) +void InlineFlowBox::computeVerticalOverflow(int lineTop, int lineBottom, bool strictMode, GlyphOverflowAndFallbackFontsMap& textBoxDataMap) { int boxHeight = height(); @@ -566,7 +569,8 @@ void InlineFlowBox::computeVerticalOverflow(int lineTop, int lineBottom, bool st int strokeOverflow = static_cast<int>(ceilf(rt->style()->textStrokeWidth() / 2.0f)); - GlyphOverflow* glyphOverflow = static_cast<InlineTextBox*>(curr)->glyphOverflow(); + GlyphOverflowAndFallbackFontsMap::iterator it = textBoxDataMap.find(static_cast<InlineTextBox*>(curr)); + GlyphOverflow* glyphOverflow = it == textBoxDataMap.end() ? 0 : &it->second.second; int topGlyphOverflow = -strokeOverflow - (glyphOverflow ? glyphOverflow->top : 0); int bottomGlyphOverflow = strokeOverflow + (glyphOverflow ? glyphOverflow->bottom : 0); @@ -582,7 +586,7 @@ void InlineFlowBox::computeVerticalOverflow(int lineTop, int lineBottom, bool st bottomVisualOverflow = max(curr->y() + text->height() + childOverflowBottom, bottomVisualOverflow); } else if (curr->renderer()->isRenderInline()) { InlineFlowBox* flow = static_cast<InlineFlowBox*>(curr); - flow->computeVerticalOverflow(lineTop, lineBottom, strictMode); + flow->computeVerticalOverflow(lineTop, lineBottom, strictMode, textBoxDataMap); topLayoutOverflow = min(topLayoutOverflow, flow->topLayoutOverflow()); bottomLayoutOverflow = max(bottomLayoutOverflow, flow->bottomLayoutOverflow()); topVisualOverflow = min(topVisualOverflow, flow->topVisualOverflow()); diff --git a/WebCore/rendering/InlineFlowBox.h b/WebCore/rendering/InlineFlowBox.h index ecb4724..e939fb4 100644 --- a/WebCore/rendering/InlineFlowBox.h +++ b/WebCore/rendering/InlineFlowBox.h @@ -28,8 +28,11 @@ namespace WebCore { class HitTestRequest; class HitTestResult; +class InlineTextBox; class RenderLineBoxList; +typedef HashMap<const InlineTextBox*, pair<Vector<const SimpleFontData*>, GlyphOverflow> > GlyphOverflowAndFallbackFontsMap; + class InlineFlowBox : public InlineBox { public: InlineFlowBox(RenderObject* obj) @@ -124,13 +127,13 @@ public: void determineSpacingForFlowBoxes(bool lastLine, RenderObject* endObject); int getFlowSpacingWidth(); bool onEndChain(RenderObject* endObject); - virtual int placeBoxesHorizontally(int x, bool& needsWordSpacing); + virtual int placeBoxesHorizontally(int x, bool& needsWordSpacing, GlyphOverflowAndFallbackFontsMap&); void computeLogicalBoxHeights(int& maxPositionTop, int& maxPositionBottom, - int& maxAscent, int& maxDescent, bool strictMode); + int& maxAscent, int& maxDescent, bool strictMode, GlyphOverflowAndFallbackFontsMap&); void adjustMaxAscentAndDescent(int& maxAscent, int& maxDescent, int maxPositionTop, int maxPositionBottom); void placeBoxesVertically(int y, int maxHeight, int maxAscent, bool strictMode, int& lineTop, int& lineBottom); - void computeVerticalOverflow(int lineTop, int lineBottom, bool strictMode); + void computeVerticalOverflow(int lineTop, int lineBottom, bool strictMode, GlyphOverflowAndFallbackFontsMap&); void removeChild(InlineBox* child); diff --git a/WebCore/rendering/InlineTextBox.cpp b/WebCore/rendering/InlineTextBox.cpp index 0c5df41..292a9ac 100644 --- a/WebCore/rendering/InlineTextBox.cpp +++ b/WebCore/rendering/InlineTextBox.cpp @@ -1037,48 +1037,4 @@ bool InlineTextBox::containsCaretOffset(int offset) const return true; } -void InlineTextBox::setFallbackFonts(const HashSet<const SimpleFontData*>& fallbackFonts) -{ - if (!s_glyphOverflowAndFallbackFontsMap) - s_glyphOverflowAndFallbackFontsMap = new GlyphOverflowAndFallbackFontsMap; - - GlyphOverflowAndFallbackFontsMap::iterator it = s_glyphOverflowAndFallbackFontsMap->add(this, make_pair(Vector<const SimpleFontData*>(), GlyphOverflow())).first; - ASSERT(it->second.first.isEmpty()); - copyToVector(fallbackFonts, it->second.first); -} - -Vector<const SimpleFontData*>* InlineTextBox::fallbackFonts() const -{ - if (!s_glyphOverflowAndFallbackFontsMap) - return 0; - - GlyphOverflowAndFallbackFontsMap::iterator it = s_glyphOverflowAndFallbackFontsMap->find(this); - if (it == s_glyphOverflowAndFallbackFontsMap->end()) - return 0; - - return &it->second.first; -} - -InlineTextBox::GlyphOverflowAndFallbackFontsMap* InlineTextBox::s_glyphOverflowAndFallbackFontsMap = 0; - -void InlineTextBox::setGlyphOverflow(const GlyphOverflow& glyphOverflow) -{ - if (!s_glyphOverflowAndFallbackFontsMap) - s_glyphOverflowAndFallbackFontsMap = new GlyphOverflowAndFallbackFontsMap; - - GlyphOverflowAndFallbackFontsMap::iterator it = s_glyphOverflowAndFallbackFontsMap->add(this, make_pair(Vector<const SimpleFontData*>(), GlyphOverflow())).first; - it->second.second = glyphOverflow; -} - -GlyphOverflow* InlineTextBox::glyphOverflow() const -{ - if (!s_glyphOverflowAndFallbackFontsMap) - return 0; - GlyphOverflowAndFallbackFontsMap::iterator it = s_glyphOverflowAndFallbackFontsMap->find(this); - if (it == s_glyphOverflowAndFallbackFontsMap->end()) - return 0; - - return &it->second.second; -} - } // namespace WebCore diff --git a/WebCore/rendering/InlineTextBox.h b/WebCore/rendering/InlineTextBox.h index 2eb0c42..d03de85 100644 --- a/WebCore/rendering/InlineTextBox.h +++ b/WebCore/rendering/InlineTextBox.h @@ -63,18 +63,6 @@ public: void offsetRun(int d) { m_start += d; } - void setFallbackFonts(const HashSet<const SimpleFontData*>&); - Vector<const SimpleFontData*>* fallbackFonts() const; - - void setGlyphOverflow(const GlyphOverflow&); - GlyphOverflow* glyphOverflow() const; - - static void clearGlyphOverflowAndFallbackFontMap() - { - if (s_glyphOverflowAndFallbackFontsMap) - s_glyphOverflowAndFallbackFontsMap->clear(); - } - unsigned short truncation() { return m_truncation; } private: @@ -138,9 +126,6 @@ private: unsigned short m_truncation; // Where to truncate when text overflow is applied. We use special constants to // denote no truncation (the whole run paints) and full truncation (nothing paints at all). - typedef HashMap<const InlineTextBox*, pair<Vector<const SimpleFontData*>, GlyphOverflow> > GlyphOverflowAndFallbackFontsMap; - static GlyphOverflowAndFallbackFontsMap* s_glyphOverflowAndFallbackFontsMap; - protected: void paintCompositionBackground(GraphicsContext*, int tx, int ty, RenderStyle*, const Font&, int startPos, int endPos); void paintDocumentMarkers(GraphicsContext*, int tx, int ty, RenderStyle*, const Font&, bool background); diff --git a/WebCore/rendering/RenderArena.cpp b/WebCore/rendering/RenderArena.cpp index 41f33de..57ed978 100644 --- a/WebCore/rendering/RenderArena.cpp +++ b/WebCore/rendering/RenderArena.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2003 Apple Computer, Inc. + * Copyright (C) Research In Motion Limited 2010. All rights reserved. * * Portions are Copyright (C) 1998 Netscape Communications Corporation. * @@ -54,6 +55,8 @@ typedef struct { int signature; } RenderArenaDebugHeader; +static const size_t debugHeaderSize = ARENA_ALIGN(sizeof(RenderArenaDebugHeader)); + #endif RenderArena::RenderArena(unsigned arenaSize) @@ -75,12 +78,12 @@ void* RenderArena::allocate(size_t size) #ifndef NDEBUG // Use standard malloc so that memory debugging tools work. ASSERT(this); - void* block = ::malloc(sizeof(RenderArenaDebugHeader) + size); + void* block = ::malloc(debugHeaderSize + size); RenderArenaDebugHeader* header = static_cast<RenderArenaDebugHeader*>(block); header->arena = this; header->size = size; header->signature = signature; - return header + 1; + return static_cast<char*>(block) + debugHeaderSize; #else void* result = 0; @@ -112,12 +115,13 @@ void RenderArena::free(size_t size, void* ptr) { #ifndef NDEBUG // Use standard free so that memory debugging tools work. - RenderArenaDebugHeader* header = static_cast<RenderArenaDebugHeader*>(ptr) - 1; + void* block = static_cast<char*>(ptr) - debugHeaderSize; + RenderArenaDebugHeader* header = static_cast<RenderArenaDebugHeader*>(block); ASSERT(header->signature == signature); ASSERT_UNUSED(size, header->size == size); ASSERT(header->arena == this); header->signature = signatureDead; - ::free(header); + ::free(block); #else // Ensure we have correct alignment for pointers. Important for Tru64 size = ROUNDUP(size, sizeof(void*)); diff --git a/WebCore/rendering/RenderBlock.cpp b/WebCore/rendering/RenderBlock.cpp index f8c8b8d..7b6c817 100644 --- a/WebCore/rendering/RenderBlock.cpp +++ b/WebCore/rendering/RenderBlock.cpp @@ -756,6 +756,8 @@ void RenderBlock::layoutBlock(bool relayoutChildren) int repaintTop = 0; int repaintBottom = 0; int maxFloatBottom = 0; + if (!firstChild()) + setChildrenInline(true); if (childrenInline()) layoutInlineChildren(relayoutChildren, repaintTop, repaintBottom); else @@ -992,11 +994,13 @@ bool RenderBlock::handleRunInChild(RenderBox* child) // Move the nodes from the old child to the new child, but skip any :before/:after content. It has already // been regenerated by the new inline. - for (RenderObject* runInChild = blockRunIn->firstChild(); runInChild; runInChild = runInChild->nextSibling()) { + for (RenderObject* runInChild = blockRunIn->firstChild(); runInChild;) { + RenderObject* nextSibling = runInChild->nextSibling(); if (runInIsGenerated || (runInChild->style()->styleType() != BEFORE && runInChild->style()->styleType() != AFTER)) { blockRunIn->children()->removeChildNode(blockRunIn, runInChild, false); inlineRunIn->addChild(runInChild); // Use addChild instead of appendChildNode since it handles correct placement of the children relative to :after-generated content. } + runInChild = nextSibling; } // Now insert the new child under |currBlock|. @@ -1167,9 +1171,8 @@ int RenderBlock::estimateVerticalPosition(RenderBox* child, const MarginInfo& ma void RenderBlock::determineHorizontalPosition(RenderBox* child) { + int xPos = borderLeft() + paddingLeft(); if (style()->direction() == LTR) { - int xPos = borderLeft() + paddingLeft(); - // Add in our left margin. int chPos = xPos + child->marginLeft(); @@ -1195,7 +1198,7 @@ void RenderBlock::determineHorizontalPosition(RenderBox* child) view()->addLayoutDelta(IntSize(child->x() - chPos, 0)); child->setLocation(chPos, child->y()); } else { - int xPos = width() - borderRight() - paddingRight() - verticalScrollbarWidth(); + xPos += availableWidth(); int chPos = xPos - (child->width() + child->marginRight()); if (child->avoidsFloats()) { int rightOff = rightOffset(height(), false); @@ -1579,13 +1582,12 @@ void RenderBlock::paintColumnRules(PaintInfo& paintInfo, int tx, int ty) return; // We need to do multiple passes, breaking up our child painting into strips. - int currXOffset = 0; - int ruleAdd = borderLeft() + paddingLeft(); - int ruleX = 0; Vector<IntRect>* colRects = columnRects(); unsigned colCount = colRects->size(); + int currXOffset = style()->direction() == LTR ? 0 : contentWidth(); + int ruleAdd = borderLeft() + paddingLeft(); + int ruleX = style()->direction() == LTR ? 0 : contentWidth(); for (unsigned i = 0; i < colCount; i++) { - // For each rect, we clip to the rect, and then we adjust our coords. IntRect colRect = colRects->at(i); // Move to the next position. @@ -1615,11 +1617,13 @@ void RenderBlock::paintColumnContents(PaintInfo& paintInfo, int tx, int ty, bool { // We need to do multiple passes, breaking up our child painting into strips. GraphicsContext* context = paintInfo.context; - int currXOffset = 0; - int currYOffset = 0; int colGap = columnGap(); Vector<IntRect>* colRects = columnRects(); unsigned colCount = colRects->size(); + if (!colCount) + return; + int currXOffset = style()->direction() == LTR ? 0 : contentWidth() - colRects->at(0).width(); + int currYOffset = 0; for (unsigned i = 0; i < colCount; i++) { // For each rect, we clip to the rect, and then we adjust our coords. IntRect colRect = colRects->at(i); @@ -3356,12 +3360,16 @@ bool RenderBlock::nodeAtPoint(const HitTestRequest& request, HitTestResult& resu } // Hit test contents if we don't have columns. - if (!hasColumns() && hitTestContents(request, result, _x, _y, scrolledX, scrolledY, hitTestAction)) + if (!hasColumns() && hitTestContents(request, result, _x, _y, scrolledX, scrolledY, hitTestAction)) { + updateHitTestResult(result, IntPoint(_x - tx, _y - ty)); return true; - + } + // Hit test our columns if we do have them. - if (hasColumns() && hitTestColumns(request, result, _x, _y, scrolledX, scrolledY, hitTestAction)) + if (hasColumns() && hitTestColumns(request, result, _x, _y, scrolledX, scrolledY, hitTestAction)) { + updateHitTestResult(result, IntPoint(_x - tx, _y - ty)); return true; + } // Hit test floats. if (hitTestAction == HitTestFloat && m_floatingObjects) { @@ -3414,11 +3422,14 @@ bool RenderBlock::hitTestColumns(const HitTestRequest& request, HitTestResult& r // We need to do multiple passes, breaking up our hit testing into strips. // We can always go left to right, since column contents are clipped (meaning that there // can't be any overlap). - int currXOffset = 0; + Vector<IntRect>* colRects = columnRects(); + unsigned colCount = colRects->size(); + if (!colCount) + return false; + int currXOffset = style()->direction() == LTR ? 0 : contentWidth() - colRects->at(0).width(); int currYOffset = 0; int colGap = columnGap(); - Vector<IntRect>* colRects = columnRects(); - for (unsigned i = 0; i < colRects->size(); i++) { + for (unsigned i = 0; i < colCount; i++) { IntRect colRect = colRects->at(i); colRect.move(tx, ty); @@ -3456,20 +3467,16 @@ bool RenderBlock::hitTestContents(const HitTestRequest& request, HitTestResult& { if (childrenInline() && !isTable()) { // We have to hit-test our line boxes. - if (m_lineBoxes.hitTest(this, request, result, x, y, tx, ty, hitTestAction)) { - updateHitTestResult(result, IntPoint(x - tx, y - ty)); + if (m_lineBoxes.hitTest(this, request, result, x, y, tx, ty, hitTestAction)) return true; - } } else { // Hit test our children. HitTestAction childHitTest = hitTestAction; if (hitTestAction == HitTestChildBlockBackgrounds) childHitTest = HitTestChildBlockBackground; for (RenderBox* child = lastChildBox(); child; child = child->previousSiblingBox()) { - if (!child->hasSelfPaintingLayer() && !child->isFloating() && child->nodeAtPoint(request, result, x, y, tx, ty, childHitTest)) { - updateHitTestResult(result, IntPoint(x - tx, y - ty)); + if (!child->hasSelfPaintingLayer() && !child->isFloating() && child->nodeAtPoint(request, result, x, y, tx, ty, childHitTest)) return true; - } } } @@ -3824,7 +3831,7 @@ int RenderBlock::layoutColumns(int endOfContent, int requestedColumnHeight) int truncationPoint = visibleTopOfHighestFloatExtendingBelow(currY + colHeight, colHeight); // For the simulated paint, we pretend like everything is in one long strip. - IntRect pageRect(left, currY, desiredColumnWidth, truncationPoint - currY); + IntRect pageRect(left, currY, contentWidth(), truncationPoint - currY); v->setPrintRect(pageRect); v->setTruncatedAt(truncationPoint); GraphicsContext context((PlatformGraphicsContext*)0); @@ -3952,10 +3959,13 @@ void RenderBlock::adjustRectForColumns(IntRect& r) const IntRect result; // Determine which columns we intersect. - int currXOffset = 0; + unsigned colCount = colRects->size(); + if (!colCount) + return; + int currXOffset = style()->direction() == LTR ? 0 : contentWidth() - colRects->at(0).width(); int currYOffset = 0; int colGap = columnGap(); - for (unsigned i = 0; i < colRects->size(); i++) { + for (unsigned i = 0; i < colCount; i++) { IntRect colRect = colRects->at(i); IntRect repaintRect = r; @@ -3982,12 +3992,11 @@ void RenderBlock::adjustForColumns(IntSize& offset, const IntPoint& point) const if (!hasColumns()) return; - // FIXME: This is incorrect for right-to-left columns. - Vector<IntRect>& columnRects = *this->columnRects(); int gapWidth = columnGap(); - int xOffset = 0; + + int xOffset = style()->direction() == LTR ? 0 : contentWidth() - columnRects[0].width(); int yOffset = 0; size_t columnCount = columnRects.size(); for (size_t i = 0; i < columnCount; ++i) { @@ -3997,7 +4006,10 @@ void RenderBlock::adjustForColumns(IntSize& offset, const IntPoint& point) const return; } - xOffset += columnRect.width() + gapWidth; + if (style()->direction() == LTR) + xOffset += columnRect.width() + gapWidth; + else + xOffset -= columnRect.width() + gapWidth; yOffset += columnRect.height(); } } @@ -4704,10 +4716,12 @@ void RenderBlock::updateFirstLetter() // Drill into inlines looking for our first text child. RenderObject* currChild = firstLetterBlock->firstChild(); - while (currChild && currChild->needsLayout() && ((!currChild->isReplaced() && !currChild->isRenderButton() && !currChild->isMenuList()) || currChild->isFloatingOrPositioned()) && !currChild->isText()) { + while (currChild && ((!currChild->isReplaced() && !currChild->isRenderButton() && !currChild->isMenuList()) || currChild->isFloatingOrPositioned()) && !currChild->isText()) { if (currChild->isFloatingOrPositioned()) { - if (currChild->style()->styleType() == FIRST_LETTER) + if (currChild->style()->styleType() == FIRST_LETTER) { + currChild = currChild->firstChild(); break; + } currChild = currChild->nextSibling(); } else currChild = currChild->firstChild(); @@ -4724,11 +4738,11 @@ void RenderBlock::updateFirstLetter() // If the child already has style, then it has already been created, so we just want // to update it. - if (currChild->style()->styleType() == FIRST_LETTER) { + if (firstLetterContainer->style()->styleType() == FIRST_LETTER) { RenderStyle* pseudo = firstLetterBlock->getCachedPseudoStyle(FIRST_LETTER, - firstLetterContainer->firstLineStyle()); - currChild->setStyle(pseudo); - for (RenderObject* genChild = currChild->firstChild(); genChild; genChild = genChild->nextSibling()) { + firstLetterContainer->parent()->firstLineStyle()); + firstLetterContainer->setStyle(pseudo); + for (RenderObject* genChild = firstLetterContainer->firstChild(); genChild; genChild = genChild->nextSibling()) { if (genChild->isText()) genChild->setStyle(pseudo); } diff --git a/WebCore/rendering/RenderBlock.h b/WebCore/rendering/RenderBlock.h index 751a1df..b54f66d 100644 --- a/WebCore/rendering/RenderBlock.h +++ b/WebCore/rendering/RenderBlock.h @@ -264,8 +264,8 @@ private: InlineIterator findNextLineBreak(InlineBidiResolver&, bool firstLine, bool& isLineEmpty, bool& previousLineBrokeCleanly, EClear* clear = 0); RootInlineBox* constructLine(unsigned runCount, BidiRun* firstRun, BidiRun* lastRun, bool firstLine, bool lastLine, RenderObject* endObject); InlineFlowBox* createLineBoxes(RenderObject*, bool firstLine); - void computeHorizontalPositionsForLine(RootInlineBox*, bool firstLine, BidiRun* firstRun, BidiRun* trailingSpaceRun, bool reachedEnd); - void computeVerticalPositionsForLine(RootInlineBox*, BidiRun*); + void computeHorizontalPositionsForLine(RootInlineBox*, bool firstLine, BidiRun* firstRun, BidiRun* trailingSpaceRun, bool reachedEnd, GlyphOverflowAndFallbackFontsMap&); + void computeVerticalPositionsForLine(RootInlineBox*, BidiRun*, GlyphOverflowAndFallbackFontsMap&); void deleteEllipsisLineBoxes(); void checkLinesForTextOverflow(); void addOverflowFromInlineChildren(); diff --git a/WebCore/rendering/RenderBlockLineLayout.cpp b/WebCore/rendering/RenderBlockLineLayout.cpp index 895db66..ec138b9 100644 --- a/WebCore/rendering/RenderBlockLineLayout.cpp +++ b/WebCore/rendering/RenderBlockLineLayout.cpp @@ -317,7 +317,7 @@ RootInlineBox* RenderBlock::constructLine(unsigned runCount, BidiRun* firstRun, return lastRootBox(); } -void RenderBlock::computeHorizontalPositionsForLine(RootInlineBox* lineBox, bool firstLine, BidiRun* firstRun, BidiRun* trailingSpaceRun, bool reachedEnd) +void RenderBlock::computeHorizontalPositionsForLine(RootInlineBox* lineBox, bool firstLine, BidiRun* firstRun, BidiRun* trailingSpaceRun, bool reachedEnd, GlyphOverflowAndFallbackFontsMap& textBoxDataMap) { // First determine our total width. int availableWidth = lineWidth(height(), firstLine); @@ -357,7 +357,9 @@ void RenderBlock::computeHorizontalPositionsForLine(RootInlineBox* lineBox, bool #endif ) { ASSERT(r->m_box->isText()); - static_cast<InlineTextBox*>(r->m_box)->setFallbackFonts(fallbackFonts); + GlyphOverflowAndFallbackFontsMap::iterator it = textBoxDataMap.add(static_cast<InlineTextBox*>(r->m_box), make_pair(Vector<const SimpleFontData*>(), GlyphOverflow())).first; + ASSERT(it->second.first.isEmpty()); + copyToVector(fallbackFonts, it->second.first); } if ((glyphOverflow.top || glyphOverflow.bottom || glyphOverflow.left || glyphOverflow.right) #if ENABLE(SVG) @@ -365,7 +367,8 @@ void RenderBlock::computeHorizontalPositionsForLine(RootInlineBox* lineBox, bool #endif ) { ASSERT(r->m_box->isText()); - static_cast<InlineTextBox*>(r->m_box)->setGlyphOverflow(glyphOverflow); + GlyphOverflowAndFallbackFontsMap::iterator it = textBoxDataMap.add(static_cast<InlineTextBox*>(r->m_box), make_pair(Vector<const SimpleFontData*>(), GlyphOverflow())).first; + it->second.second = glyphOverflow; } } else if (!r->m_object->isRenderInline()) { RenderBox* renderBox = toRenderBox(r->m_object); @@ -482,12 +485,12 @@ void RenderBlock::computeHorizontalPositionsForLine(RootInlineBox* lineBox, bool // The widths of all runs are now known. We can now place every inline box (and // compute accurate widths for the inline flow boxes). needsWordSpacing = false; - lineBox->placeBoxesHorizontally(x, needsWordSpacing); + lineBox->placeBoxesHorizontally(x, needsWordSpacing, textBoxDataMap); } -void RenderBlock::computeVerticalPositionsForLine(RootInlineBox* lineBox, BidiRun* firstRun) +void RenderBlock::computeVerticalPositionsForLine(RootInlineBox* lineBox, BidiRun* firstRun, GlyphOverflowAndFallbackFontsMap& textBoxDataMap) { - setHeight(lineBox->verticallyAlignBoxes(height())); + setHeight(lineBox->verticallyAlignBoxes(height(), textBoxDataMap)); lineBox->setBlockHeight(height()); // Now make sure we place replaced render objects correctly. @@ -846,11 +849,11 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i lineBox->setEndsWithBreak(previousLineBrokeCleanly); // Now we position all of our text runs horizontally. - computeHorizontalPositionsForLine(lineBox, firstLine, resolver.firstRun(), trailingSpaceRun, end.atEnd()); + GlyphOverflowAndFallbackFontsMap textBoxDataMap; + computeHorizontalPositionsForLine(lineBox, firstLine, resolver.firstRun(), trailingSpaceRun, end.atEnd(), textBoxDataMap); // Now position our text runs vertically. - computeVerticalPositionsForLine(lineBox, resolver.firstRun()); - InlineTextBox::clearGlyphOverflowAndFallbackFontMap(); + computeVerticalPositionsForLine(lineBox, resolver.firstRun(), textBoxDataMap); #if ENABLE(SVG) // Special SVG text layout code @@ -946,7 +949,8 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int& repaintTop, i TrailingFloatsRootInlineBox* trailingFloatsLineBox = new (renderArena()) TrailingFloatsRootInlineBox(this); m_lineBoxes.appendLineBox(trailingFloatsLineBox); trailingFloatsLineBox->setConstructed(); - trailingFloatsLineBox->verticallyAlignBoxes(height()); + GlyphOverflowAndFallbackFontsMap textBoxDataMap; + trailingFloatsLineBox->verticallyAlignBoxes(height(), textBoxDataMap); trailingFloatsLineBox->setVerticalOverflowPositions(height(), bottomLayoutOverflow, height(), bottomVisualOverflow, 0); trailingFloatsLineBox->setBlockHeight(height()); } diff --git a/WebCore/rendering/RenderBox.h b/WebCore/rendering/RenderBox.h index 1c766aa..c033275 100644 --- a/WebCore/rendering/RenderBox.h +++ b/WebCore/rendering/RenderBox.h @@ -51,6 +51,7 @@ public: void setHeight(int height) { m_frameRect.setHeight(height); } IntPoint location() const { return m_frameRect.location(); } + IntSize locationOffset() const { return IntSize(x(), y()); } IntSize size() const { return m_frameRect.size(); } void setLocation(const IntPoint& location) { m_frameRect.setLocation(location); } diff --git a/WebCore/rendering/RenderBoxModelObject.h b/WebCore/rendering/RenderBoxModelObject.h index a4cf54a..62f1009 100644 --- a/WebCore/rendering/RenderBoxModelObject.h +++ b/WebCore/rendering/RenderBoxModelObject.h @@ -59,7 +59,7 @@ public: bool hasSelfPaintingLayer() const; RenderLayer* layer() const { return m_layer; } - virtual bool requiresLayer() const { return isRoot() || isPositioned() || isRelPositioned() || isTransparent() || hasOverflowClip() || hasTransform() || hasMask() || hasReflection(); } + virtual bool requiresLayer() const { return isRoot() || isPositioned() || isRelPositioned() || isTransparent() || hasOverflowClip() || hasTransform() || hasMask() || hasReflection() || style()->specifiesColumns(); } // This will work on inlines to return the bounding box of all of the lines' border boxes. virtual IntRect borderBoundingBox() const = 0; diff --git a/WebCore/rendering/RenderImage.cpp b/WebCore/rendering/RenderImage.cpp index 237dfb6..6fd38a6 100644 --- a/WebCore/rendering/RenderImage.cpp +++ b/WebCore/rendering/RenderImage.cpp @@ -508,7 +508,7 @@ int RenderImage::minimumReplacedHeight() const HTMLMapElement* RenderImage::imageMap() const { HTMLImageElement* i = node() && node()->hasTagName(imgTag) ? static_cast<HTMLImageElement*>(node()) : 0; - return i ? i->document()->getImageMap(i->getAttribute(usemapAttr)) : 0; + return i ? i->document()->getImageMap(i->fastGetAttribute(usemapAttr)) : 0; } bool RenderImage::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, HitTestAction hitTestAction) diff --git a/WebCore/rendering/RenderLayer.cpp b/WebCore/rendering/RenderLayer.cpp index 37dbd38..80e334a 100644 --- a/WebCore/rendering/RenderLayer.cpp +++ b/WebCore/rendering/RenderLayer.cpp @@ -587,14 +587,32 @@ bool RenderLayer::update3DTransformedDescendantStatus() void RenderLayer::updateLayerPosition() { - // Clear our cached clip rect information. - clearClipRects(); + IntPoint localPoint; + IntSize inlineBoundingBoxOffset; // We don't put this into the RenderLayer x/y for inlines, so we need to subtract it out when done. + if (renderer()->isRenderInline()) { + RenderInline* inlineFlow = toRenderInline(renderer()); + IntRect lineBox = inlineFlow->linesBoundingBox(); + setWidth(lineBox.width()); + setHeight(lineBox.height()); + inlineBoundingBoxOffset = IntSize(lineBox.x(), lineBox.y()); + localPoint += inlineBoundingBoxOffset; + } else if (RenderBox* box = renderBox()) { + setWidth(box->width()); + setHeight(box->height()); - RenderBox* rendererBox = renderBox(); - - int x = rendererBox ? rendererBox->x() : 0; - int y = rendererBox ? rendererBox->y() : 0; + if (!box->hasOverflowClip()) { + if (box->rightLayoutOverflow() > box->width()) + setWidth(box->rightLayoutOverflow()); + if (box->bottomLayoutOverflow() > box->height()) + setHeight(box->bottomLayoutOverflow()); + } + + localPoint += box->locationOffset(); + } + // Clear our cached clip rect information. + clearClipRects(); + if (!renderer()->isPositioned() && renderer()->parent()) { // We must adjust our position by walking up the render tree looking for the // nearest enclosing object with a layer. @@ -603,26 +621,15 @@ void RenderLayer::updateLayerPosition() if (curr->isBox() && !curr->isTableRow()) { // Rows and cells share the same coordinate space (that of the section). // Omit them when computing our xpos/ypos. - RenderBox* currBox = toRenderBox(curr); - x += currBox->x(); - y += currBox->y(); + localPoint += toRenderBox(curr)->locationOffset(); } curr = curr->parent(); } if (curr->isBox() && curr->isTableRow()) { // Put ourselves into the row coordinate space. - RenderBox* currBox = toRenderBox(curr); - x -= currBox->x(); - y -= currBox->y(); + localPoint -= toRenderBox(curr)->locationOffset(); } } - - m_relX = m_relY = 0; - if (renderer()->isRelPositioned()) { - m_relX = renderer()->relativePositionOffsetX(); - m_relY = renderer()->relativePositionOffsetY(); - x += m_relX; y += m_relY; - } // Subtract our parent's scroll offset. if (renderer()->isPositioned() && enclosingPositionedAncestor()) { @@ -630,40 +637,31 @@ void RenderLayer::updateLayerPosition() // For positioned layers, we subtract out the enclosing positioned layer's scroll offset. IntSize offset = positionedParent->scrolledContentOffset(); - x -= offset.width(); - y -= offset.height(); + localPoint -= offset; if (renderer()->isPositioned() && positionedParent->renderer()->isRelPositioned() && positionedParent->renderer()->isRenderInline()) { IntSize offset = toRenderInline(positionedParent->renderer())->relativePositionedInlineOffset(toRenderBox(renderer())); - x += offset.width(); - y += offset.height(); + localPoint += offset; } } else if (parent()) { - IntSize offset = parent()->scrolledContentOffset(); - x -= offset.width(); - y -= offset.height(); + IntSize columnOffset; + parent()->renderer()->adjustForColumns(columnOffset, localPoint); + localPoint += columnOffset; + + IntSize scrollOffset = parent()->scrolledContentOffset(); + localPoint -= scrollOffset; } - - // FIXME: We'd really like to just get rid of the concept of a layer rectangle and rely on the renderers. - - setLocation(x, y); - - if (renderer()->isRenderInline()) { - RenderInline* inlineFlow = toRenderInline(renderer()); - IntRect lineBox = inlineFlow->linesBoundingBox(); - setWidth(lineBox.width()); - setHeight(lineBox.height()); - } else if (RenderBox* box = renderBox()) { - setWidth(box->width()); - setHeight(box->height()); - - if (!box->hasOverflowClip()) { - if (box->rightLayoutOverflow() > box->width()) - setWidth(box->rightLayoutOverflow()); - if (box->bottomLayoutOverflow() > box->height()) - setHeight(box->bottomLayoutOverflow()); - } + + m_relX = m_relY = 0; + if (renderer()->isRelPositioned()) { + m_relX = renderer()->relativePositionOffsetX(); + m_relY = renderer()->relativePositionOffsetY(); + localPoint.move(m_relX, m_relY); } + + // FIXME: We'd really like to just get rid of the concept of a layer rectangle and rely on the renderers. + localPoint -= inlineBoundingBoxOffset; + setLocation(localPoint.x(), localPoint.y()); } TransformationMatrix RenderLayer::perspectiveTransform() const @@ -1158,7 +1156,7 @@ RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, int& xPos, i return; parentLayer->convertToLayerCoords(ancestorLayer, xPos, yPos); - + xPos += x(); yPos += y(); } @@ -3507,16 +3505,17 @@ void RenderLayer::repaintIncludingNonCompositingDescendants(RenderBoxModelObject bool RenderLayer::shouldBeNormalFlowOnly() const { - return (renderer()->hasOverflowClip() || renderer()->hasReflection() || renderer()->hasMask() || renderer()->isVideo() || renderer()->isEmbeddedObject()) && - !renderer()->isPositioned() && - !renderer()->isRelPositioned() && - !renderer()->hasTransform() && - !isTransparent(); + return (renderer()->hasOverflowClip() || renderer()->hasReflection() || renderer()->hasMask() || renderer()->isVideo() || renderer()->isEmbeddedObject() || + renderer()->isRenderIFrame() || renderer()->style()->specifiesColumns()) + && !renderer()->isPositioned() + && !renderer()->isRelPositioned() + && !renderer()->hasTransform() + && !isTransparent(); } bool RenderLayer::isSelfPaintingLayer() const { - return !isNormalFlowOnly() || renderer()->hasReflection() || renderer()->hasMask() || renderer()->isTableRow() || renderer()->isVideo() || renderer()->isEmbeddedObject(); + return !isNormalFlowOnly() || renderer()->hasReflection() || renderer()->hasMask() || renderer()->isTableRow() || renderer()->isVideo() || renderer()->isEmbeddedObject() || renderer()->isRenderIFrame(); } void RenderLayer::styleChanged(StyleDifference diff, const RenderStyle*) diff --git a/WebCore/rendering/RenderLayerBacking.cpp b/WebCore/rendering/RenderLayerBacking.cpp index b857420..4957265 100644 --- a/WebCore/rendering/RenderLayerBacking.cpp +++ b/WebCore/rendering/RenderLayerBacking.cpp @@ -45,6 +45,7 @@ #include "KeyframeList.h" #include "PluginWidget.h" #include "RenderBox.h" +#include "RenderIFrame.h" #include "RenderImage.h" #include "RenderLayerCompositor.h" #include "RenderEmbeddedObject.h" @@ -232,6 +233,9 @@ bool RenderLayerBacking::updateGraphicsLayerConfiguration() } #endif + if (renderer()->isRenderIFrame()) + layerConfigChanged = RenderLayerCompositor::parentIFrameContentLayers(toRenderIFrame(renderer())); + return layerConfigChanged; } @@ -384,25 +388,13 @@ void RenderLayerBacking::updateGraphicsLayerGeometry() } m_graphicsLayer->setContentsRect(contentsBox()); - m_graphicsLayer->setDrawsContent(containsPaintedContent()); + updateDrawsContent(); // If this is an iframe parent, update the iframe content's box - RenderLayerCompositor* innerCompositor = innerRenderLayerCompositor(); - if (innerCompositor) - innerCompositor->setRootPlatformLayerClippingBox(contentsBox()); -} - -RenderLayerCompositor* RenderLayerBacking::innerRenderLayerCompositor() const -{ if (renderer()->isRenderIFrame()) { - HTMLIFrameElement* element = static_cast<HTMLIFrameElement*>(renderer()->node()); - if (Document* contentDocument = element->contentDocument()) { - if (RenderView* view = contentDocument->renderView()) - return view->compositor(); - } + if (RenderLayerCompositor* innerCompositor = RenderLayerCompositor::iframeContentsCompositor(toRenderIFrame(renderer()))) + innerCompositor->updateContentLayerOffset(contentsBox().location()); } - - return 0; } void RenderLayerBacking::updateInternalHierarchy() @@ -421,6 +413,11 @@ void RenderLayerBacking::updateInternalHierarchy() } } +void RenderLayerBacking::updateDrawsContent() +{ + m_graphicsLayer->setDrawsContent(containsPaintedContent()); +} + // Return true if the layers changed. bool RenderLayerBacking::updateClippingLayers(bool needsAncestorClip, bool needsDescendantClip) { @@ -842,11 +839,10 @@ FloatPoint RenderLayerBacking::contentsToGraphicsLayerCoordinates(const Graphics bool RenderLayerBacking::paintingGoesToWindow() const { - if (!m_owningLayer->isRootLayer()) - return false; - - // Iframe root layers paint into backing store. - return !toRenderView(renderer())->document()->ownerElement(); + if (m_owningLayer->isRootLayer()) + return compositor()->rootLayerAttachment() == RenderLayerCompositor::RootLayerAttachedViaChromeClient; + + return false; } void RenderLayerBacking::setContentsNeedDisplay() diff --git a/WebCore/rendering/RenderLayerBacking.h b/WebCore/rendering/RenderLayerBacking.h index 8e0ee23..ff8c76c 100644 --- a/WebCore/rendering/RenderLayerBacking.h +++ b/WebCore/rendering/RenderLayerBacking.h @@ -62,6 +62,7 @@ public: void updateGraphicsLayerGeometry(); // make private // Update contents and clipping structure. void updateInternalHierarchy(); // make private + void updateDrawsContent(); GraphicsLayer* graphicsLayer() const { return m_graphicsLayer.get(); } @@ -124,8 +125,6 @@ public: IntRect contentsBox() const; - RenderLayerCompositor* innerRenderLayerCompositor() const; - private: void createGraphicsLayer(); void destroyGraphicsLayer(); diff --git a/WebCore/rendering/RenderLayerCompositor.cpp b/WebCore/rendering/RenderLayerCompositor.cpp index e96e375..ff6e3b2 100644 --- a/WebCore/rendering/RenderLayerCompositor.cpp +++ b/WebCore/rendering/RenderLayerCompositor.cpp @@ -42,6 +42,7 @@ #include "HTMLMediaElement.h" #include "HTMLNames.h" #endif +#include "NodeList.h" #include "Page.h" #include "RenderEmbeddedObject.h" #include "RenderIFrame.h" @@ -99,8 +100,8 @@ RenderLayerCompositor::RenderLayerCompositor(RenderView* renderView) , m_showRepaintCounter(false) , m_compositingConsultsOverlap(true) , m_compositing(false) - , m_rootLayerAttached(false) , m_compositingLayersNeedRebuild(false) + , m_rootLayerAttachment(RootLayerUnattached) #if PROFILE_LAYER_REBUILD , m_rootLayerUpdateCount(0) #endif // PROFILE_LAYER_REBUILD @@ -109,7 +110,7 @@ RenderLayerCompositor::RenderLayerCompositor(RenderView* renderView) RenderLayerCompositor::~RenderLayerCompositor() { - ASSERT(!m_rootLayerAttached); + ASSERT(m_rootLayerAttachment == RootLayerUnattached); } void RenderLayerCompositor::enableCompositingMode(bool enable /* = true */) @@ -117,20 +118,11 @@ void RenderLayerCompositor::enableCompositingMode(bool enable /* = true */) if (enable != m_compositing) { m_compositing = enable; - // We never go out of compositing mode for a given page, - // but if all the layers disappear, we'll just be left with - // the empty root layer, which has minimal overhead. - if (m_compositing) + if (m_compositing) { ensureRootPlatformLayer(); - else + notifyIFramesOfCompositingChange(); + } else destroyRootPlatformLayer(); - - if (shouldPropagateCompositingToIFrameParent()) { - if (Element* ownerElement = m_renderView->document()->ownerElement()) { - // Trigger a recalcStyle in the parent document, to update compositing in that document. - ownerElement->setNeedsStyleRecalc(SyntheticStyleChange); - } - } } } @@ -237,10 +229,9 @@ void RenderLayerCompositor::updateCompositingLayers(CompositingUpdateType update // Host the document layer in the RenderView's root layer. if (updateRoot == rootRenderLayer()) { - if (childList.isEmpty()) { - willMoveOffscreen(); - m_rootPlatformLayer = 0; - } else + if (childList.isEmpty()) + destroyRootPlatformLayer(); + else m_rootPlatformLayer->setChildren(childList); } } else if (needGeometryUpdate) { @@ -314,6 +305,13 @@ bool RenderLayerCompositor::updateBacking(RenderLayer* layer, CompositingChangeR video->acceleratedRenderingStateChanged(); } #endif + + if (layerChanged && layer->renderer()->isRenderIFrame()) { + RenderLayerCompositor* innerCompositor = iframeContentsCompositor(toRenderIFrame(layer->renderer())); + if (innerCompositor && innerCompositor->inCompositingMode()) + innerCompositor->updateRootLayerAttachment(); + } + return layerChanged; } @@ -332,7 +330,7 @@ bool RenderLayerCompositor::updateLayerCompositingState(RenderLayer* layer, Comp void RenderLayerCompositor::repaintOnCompositingChange(RenderLayer* layer) { // If the renderer is not attached yet, no need to repaint. - if (!layer->renderer()->parent()) + if (layer->renderer() != m_renderView && !layer->renderer()->parent()) return; RenderBoxModelObject* repaintContainer = layer->renderer()->containerForRepaint(); @@ -355,8 +353,21 @@ IntRect RenderLayerCompositor::calculateCompositedBounds(const RenderLayer* laye if (!canBeComposited(layer)) return IntRect(); - IntRect boundingBoxRect, unionBounds; - boundingBoxRect = unionBounds = layer->localBoundingBox(); + IntRect boundingBoxRect = layer->localBoundingBox(); + if (layer->renderer()->isRoot()) { + // If the root layer becomes composited (e.g. because some descendant with negative z-index is composited), + // then it has to be big enough to cover the viewport in order to display the background. This is akin + // to the code in RenderBox::paintRootBoxDecorations(). + if (m_renderView->frameView()) { + int rw = m_renderView->frameView()->contentsWidth(); + int rh = m_renderView->frameView()->contentsHeight(); + + boundingBoxRect.setWidth(max(boundingBoxRect.width(), rw - boundingBoxRect.x())); + boundingBoxRect.setHeight(max(boundingBoxRect.height(), rh - boundingBoxRect.y())); + } + } + + IntRect unionBounds = boundingBoxRect; if (layer->renderer()->hasOverflowClip() || layer->renderer()->hasMask()) { int ancestorRelX = 0, ancestorRelY = 0; @@ -795,30 +806,65 @@ void RenderLayerCompositor::rebuildCompositingLayerTree(RenderLayer* layer, cons } if (layerBacking) { - if (shouldPropagateCompositingToIFrameParent() && layer->renderer()->isRenderIFrame()) { - // This is an iframe parent. Make it the parent of the iframe document's root - layerBacking->parentForSublayers()->removeAllChildren(); - - RenderLayerCompositor* innerCompositor = layerBacking->innerRenderLayerCompositor(); - if (innerCompositor) { - GraphicsLayer* innerRootLayer = innerCompositor->rootPlatformLayer(); - if (innerRootLayer) - layerBacking->parentForSublayers()->addChild(innerRootLayer); - } - } else + bool parented = false; + if (layer->renderer()->isRenderIFrame()) + parented = parentIFrameContentLayers(toRenderIFrame(layer->renderer())); + + if (!parented) layerBacking->parentForSublayers()->setChildren(layerChildren); + childLayersOfEnclosingLayer.append(layerBacking->childForSuperlayers()); } } -void RenderLayerCompositor::setRootPlatformLayerClippingBox(const IntRect& contentsBox) +void RenderLayerCompositor::updateContentLayerOffset(const IntPoint& contentsOffset) { - if (m_clippingLayer) { - m_clippingLayer->setPosition(FloatPoint(contentsBox.x(), contentsBox.y())); - m_clippingLayer->setSize(FloatSize(contentsBox.width(), contentsBox.height())); + if (m_clipLayer) { + FrameView* frameView = m_renderView->frameView(); + m_clipLayer->setPosition(contentsOffset); + m_clipLayer->setSize(FloatSize(frameView->layoutWidth(), frameView->layoutHeight())); + + IntPoint scrollPosition = frameView->scrollPosition(); + m_scrollLayer->setPosition(FloatPoint(-scrollPosition.x(), -scrollPosition.y())); } } +void RenderLayerCompositor::updateContentLayerScrollPosition(const IntPoint& scrollPosition) +{ + if (m_scrollLayer) + m_scrollLayer->setPosition(FloatPoint(-scrollPosition.x(), -scrollPosition.y())); +} + +RenderLayerCompositor* RenderLayerCompositor::iframeContentsCompositor(RenderIFrame* renderer) +{ + HTMLIFrameElement* element = static_cast<HTMLIFrameElement*>(renderer->node()); + if (Document* contentDocument = element->contentDocument()) { + if (RenderView* view = contentDocument->renderView()) + return view->compositor(); + } + return 0; +} + +bool RenderLayerCompositor::parentIFrameContentLayers(RenderIFrame* renderer) +{ + RenderLayerCompositor* innerCompositor = iframeContentsCompositor(renderer); + if (!innerCompositor || !innerCompositor->inCompositingMode() || innerCompositor->rootLayerAttachment() != RootLayerAttachedViaEnclosingIframe) + return false; + + RenderLayer* layer = renderer->layer(); + if (!layer->isComposited()) + return false; + + RenderLayerBacking* backing = layer->backing(); + GraphicsLayer* hostingLayer = backing->parentForSublayers(); + GraphicsLayer* rootLayer = innerCompositor->rootPlatformLayer(); + if (hostingLayer->children().size() != 1 || hostingLayer->children()[0] != rootLayer) { + hostingLayer->removeAllChildren(); + hostingLayer->addChild(rootLayer); + } + return true; +} + // This just updates layer geometry without changing the hierarchy. void RenderLayerCompositor::updateLayerTreeGeometry(RenderLayer* layer) { @@ -972,82 +1018,32 @@ RenderLayer* RenderLayerCompositor::rootRenderLayer() const GraphicsLayer* RenderLayerCompositor::rootPlatformLayer() const { - return m_clippingLayer ? m_clippingLayer.get() : m_rootPlatformLayer.get(); + return m_clipLayer ? m_clipLayer.get() : m_rootPlatformLayer.get(); } void RenderLayerCompositor::didMoveOnscreen() { - if (!m_rootPlatformLayer) + if (!inCompositingMode() || m_rootLayerAttachment != RootLayerUnattached) return; - bool attached = false; - if (shouldPropagateCompositingToIFrameParent()) { - if (Element* ownerElement = m_renderView->document()->ownerElement()) { - RenderObject* renderer = ownerElement->renderer(); - if (renderer && renderer->isRenderIFrame()) { - // The layer will get hooked up via RenderLayerBacking::updateGraphicsLayerConfiguration() - // for the iframe's renderer in the parent document. - ownerElement->setNeedsStyleRecalc(SyntheticStyleChange); - attached = true; - } - } - } - - if (!attached) { - Frame* frame = m_renderView->frameView()->frame(); - Page* page = frame ? frame->page() : 0; - if (!page) - return; - - page->chrome()->client()->attachRootGraphicsLayer(frame, m_rootPlatformLayer.get()); - } - m_rootLayerAttached = true; + RootLayerAttachment attachment = shouldPropagateCompositingToEnclosingIFrame() ? RootLayerAttachedViaEnclosingIframe : RootLayerAttachedViaChromeClient; + attachRootPlatformLayer(attachment); } void RenderLayerCompositor::willMoveOffscreen() { - if (!m_rootPlatformLayer || !m_rootLayerAttached) + if (!inCompositingMode() || m_rootLayerAttachment == RootLayerUnattached) return; - bool detached = false; - if (shouldPropagateCompositingToIFrameParent()) { - if (Element* ownerElement = m_renderView->document()->ownerElement()) { - RenderObject* renderer = ownerElement->renderer(); - if (renderer->isRenderIFrame()) { - // The layer will get hooked up via RenderLayerBacking::updateGraphicsLayerConfiguration() - // for the iframe's renderer in the parent document. - ownerElement->setNeedsStyleRecalc(SyntheticStyleChange); - detached = true; - } - } - } - - if (!detached) { - Frame* frame = m_renderView->frameView()->frame(); - Page* page = frame ? frame->page() : 0; - if (!page) - return; - - page->chrome()->client()->attachRootGraphicsLayer(frame, 0); - } - m_rootLayerAttached = false; + detachRootPlatformLayer(); } void RenderLayerCompositor::updateRootLayerPosition() { - if (m_rootPlatformLayer) { - // FIXME: Adjust the y position of the m_rootPlatformLayer if we are clipping by its top edge - // Eventually this will be taken care of by scrolling logic - // https://bugs.webkit.org/show_bug.cgi?id=38518 - float height = m_renderView->bottomLayoutOverflow(); - float yOffset = 0; - - if (m_clippingLayer && height > m_clippingLayer->size().height()) - yOffset = m_clippingLayer->size().height() - height; - - m_rootPlatformLayer->setPosition(FloatPoint(0, yOffset)); - m_rootPlatformLayer->setSize(FloatSize(m_renderView->rightLayoutOverflow(), height)); - } + // Eventually we will need to account for scrolling here. + // https://bugs.webkit.org/show_bug.cgi?id=38518 + if (m_rootPlatformLayer) + m_rootPlatformLayer->setSize(FloatSize(m_renderView->rightLayoutOverflow(), m_renderView->bottomLayoutOverflow())); } void RenderLayerCompositor::didStartAcceleratedAnimation() @@ -1063,18 +1059,47 @@ bool RenderLayerCompositor::has3DContent() const return layerHas3DContent(rootRenderLayer()); } -bool RenderLayerCompositor::shouldPropagateCompositingToIFrameParent() +bool RenderLayerCompositor::shouldPropagateCompositingToEnclosingIFrame() const { // Parent document content needs to be able to render on top of a composited iframe, so correct behavior // is to have the parent document become composited too. However, this can cause problems on platforms that // use native views for frames (like Mac), so disable that behavior on those platforms for now. + Element* ownerElement = enclosingIFrameElement(); + RenderObject* renderer = ownerElement ? ownerElement->renderer() : 0; + if (!renderer || !renderer->isRenderIFrame()) + return false; + #if !PLATFORM(MAC) + // On non-Mac platforms, let compositing propagate for all iframes. return true; #else + // On Mac, only propagate compositing if the iframe is overlapped in the parent + // document, or the parent is already compositing. + RenderIFrame* iframeRenderer = toRenderIFrame(renderer); + if (iframeRenderer->widget()) { + ASSERT(iframeRenderer->widget()->isFrameView()); + FrameView* view = static_cast<FrameView*>(iframeRenderer->widget()); + if (view->isOverlapped()) + return true; + + if (RenderView* view = iframeRenderer->view()) { + if (view->compositor()->inCompositingMode()) + return true; + } + } + return false; #endif } +Element* RenderLayerCompositor::enclosingIFrameElement() const +{ + if (Element* ownerElement = m_renderView->document()->ownerElement()) + return ownerElement->hasTagName(iframeTag) ? ownerElement : 0; + + return 0; +} + bool RenderLayerCompositor::needsToBeComposited(const RenderLayer* layer) const { if (!canBeComposited(layer)) @@ -1262,9 +1287,16 @@ bool RenderLayerCompositor::requiresCompositingForPlugin(RenderObject* renderer) bool RenderLayerCompositor::requiresCompositingForIFrame(RenderObject* renderer) const { - return shouldPropagateCompositingToIFrameParent() - && renderer->isRenderIFrame() - && toRenderIFrame(renderer)->requiresAcceleratedCompositing(); + if (!renderer->isRenderIFrame()) + return false; + + RenderIFrame* iframe = toRenderIFrame(renderer); + + if (!iframe->requiresAcceleratedCompositing()) + return false; + + RenderLayerCompositor* innerCompositor = iframeContentsCompositor(iframe); + return innerCompositor->shouldPropagateCompositingToEnclosingIFrame(); } bool RenderLayerCompositor::requiresCompositingForAnimation(RenderObject* renderer) const @@ -1291,37 +1323,59 @@ bool RenderLayerCompositor::needsContentsCompositingLayer(const RenderLayer* lay void RenderLayerCompositor::ensureRootPlatformLayer() { - if (m_rootPlatformLayer) - return; + RootLayerAttachment expectedAttachment = shouldPropagateCompositingToEnclosingIFrame() ? RootLayerAttachedViaEnclosingIframe : RootLayerAttachedViaChromeClient; + if (expectedAttachment == m_rootLayerAttachment) + return; - m_rootPlatformLayer = GraphicsLayer::create(0); - m_rootPlatformLayer->setSize(FloatSize(m_renderView->rightLayoutOverflow(), m_renderView->bottomLayoutOverflow())); - m_rootPlatformLayer->setPosition(FloatPoint()); + if (!m_rootPlatformLayer) { + m_rootPlatformLayer = GraphicsLayer::create(0); +#ifndef NDEBUG + m_rootPlatformLayer->setName("Root platform"); +#endif + m_rootPlatformLayer->setSize(FloatSize(m_renderView->rightLayoutOverflow(), m_renderView->bottomLayoutOverflow())); + m_rootPlatformLayer->setPosition(FloatPoint()); - // The root layer does flipping if we need it on this platform. - m_rootPlatformLayer->setGeometryOrientation(GraphicsLayer::compositingCoordinatesOrientation()); + // Need to clip to prevent transformed content showing outside this frame + m_rootPlatformLayer->setMasksToBounds(true); + } - // Need to clip to prevent transformed content showing outside this frame - m_rootPlatformLayer->setMasksToBounds(true); + // The root layer does flipping if we need it on this platform. + m_rootPlatformLayer->setGeometryOrientation(expectedAttachment == RootLayerAttachedViaEnclosingIframe ? GraphicsLayer::CompositingCoordinatesTopDown : GraphicsLayer::compositingCoordinatesOrientation()); - if (shouldPropagateCompositingToIFrameParent()) { - // Create a clipping layer if this is an iframe - if (Element* ownerElement = m_renderView->document()->ownerElement()) { - RenderObject* renderer = ownerElement->renderer(); - if (renderer && renderer->isRenderIFrame()) { - m_clippingLayer = GraphicsLayer::create(0); - m_clippingLayer->setGeometryOrientation(GraphicsLayer::compositingCoordinatesOrientation()); + if (expectedAttachment == RootLayerAttachedViaEnclosingIframe) { + if (!m_clipLayer) { + ASSERT(!m_scrollLayer); + // Create a clipping layer if this is an iframe + m_clipLayer = GraphicsLayer::create(0); #ifndef NDEBUG - m_clippingLayer->setName("iframe Clipping"); + m_clipLayer->setName("iframe Clipping"); #endif - m_clippingLayer->setMasksToBounds(true); - m_clippingLayer->setAnchorPoint(FloatPoint()); - m_clippingLayer->addChild(m_rootPlatformLayer.get()); - } + m_clipLayer->setMasksToBounds(true); + + m_scrollLayer = GraphicsLayer::create(0); +#ifndef NDEBUG + m_scrollLayer->setName("iframe scrolling"); +#endif + // Hook them up + m_clipLayer->addChild(m_scrollLayer.get()); + m_scrollLayer->addChild(m_rootPlatformLayer.get()); + + updateContentLayerScrollPosition(m_renderView->frameView()->scrollPosition()); } + } else if (m_clipLayer) { + m_clipLayer->removeAllChildren(); + m_clipLayer->removeFromParent(); + m_clipLayer = 0; + + m_scrollLayer->removeAllChildren(); + m_scrollLayer = 0; } - didMoveOnscreen(); + // Check to see if we have to change the attachment + if (m_rootLayerAttachment != RootLayerUnattached) + detachRootPlatformLayer(); + + attachRootPlatformLayer(expectedAttachment); } void RenderLayerCompositor::destroyRootPlatformLayer() @@ -1329,10 +1383,111 @@ void RenderLayerCompositor::destroyRootPlatformLayer() if (!m_rootPlatformLayer) return; - willMoveOffscreen(); + detachRootPlatformLayer(); + if (m_clipLayer) { + m_clipLayer->removeAllChildren(); + m_clipLayer = 0; + + m_scrollLayer->removeAllChildren(); + m_scrollLayer = 0; + } + ASSERT(!m_scrollLayer); m_rootPlatformLayer = 0; } +void RenderLayerCompositor::attachRootPlatformLayer(RootLayerAttachment attachment) +{ + if (!m_rootPlatformLayer) + return; + + switch (attachment) { + case RootLayerUnattached: + ASSERT_NOT_REACHED(); + break; + case RootLayerAttachedViaChromeClient: { + Frame* frame = m_renderView->frameView()->frame(); + Page* page = frame ? frame->page() : 0; + if (!page) + return; + + page->chrome()->client()->attachRootGraphicsLayer(frame, m_rootPlatformLayer.get()); + break; + } + case RootLayerAttachedViaEnclosingIframe: { + // The layer will get hooked up via RenderLayerBacking::updateGraphicsLayerConfiguration() + // for the iframe's renderer in the parent document. + m_renderView->document()->ownerElement()->setNeedsStyleRecalc(SyntheticStyleChange); + break; + } + } + + m_rootLayerAttachment = attachment; + rootLayerAttachmentChanged(); +} + +void RenderLayerCompositor::detachRootPlatformLayer() +{ + if (!m_rootPlatformLayer || m_rootLayerAttachment == RootLayerUnattached) + return; + + switch (m_rootLayerAttachment) { + case RootLayerAttachedViaEnclosingIframe: { + // The layer will get unhooked up via RenderLayerBacking::updateGraphicsLayerConfiguration() + // for the iframe's renderer in the parent document. + if (m_clipLayer) + m_clipLayer->removeFromParent(); + else + m_rootPlatformLayer->removeFromParent(); + + m_renderView->document()->ownerElement()->setNeedsStyleRecalc(SyntheticStyleChange); + break; + } + case RootLayerAttachedViaChromeClient: { + Frame* frame = m_renderView->frameView()->frame(); + Page* page = frame ? frame->page() : 0; + if (!page) + return; + + page->chrome()->client()->attachRootGraphicsLayer(frame, 0); + } + break; + case RootLayerUnattached: + break; + } + + m_rootLayerAttachment = RootLayerUnattached; + rootLayerAttachmentChanged(); +} + +void RenderLayerCompositor::updateRootLayerAttachment() +{ + ensureRootPlatformLayer(); +} + +void RenderLayerCompositor::rootLayerAttachmentChanged() +{ + // The attachment can affect whether the RenderView layer's paintingGoesToWindow() behavior, + // so call updateGraphicsLayerGeometry() to udpate that. + RenderLayer* layer = m_renderView->layer(); + if (RenderLayerBacking* backing = layer ? layer->backing() : 0) + backing->updateDrawsContent(); +} + +// IFrames are special, because we hook compositing layers together across iframe boundaries +// when both parent and iframe content are composited. So when this frame becomes composited, we have +// to use a synthetic style change to get the iframes into RenderLayers in order to allow them to composite. +void RenderLayerCompositor::notifyIFramesOfCompositingChange() +{ + Frame* frame = m_renderView->frameView() ? m_renderView->frameView()->frame() : 0; + if (!frame) + return; + + for (Frame* child = frame->tree()->firstChild(); child; child = child->tree()->nextSibling()) { + if (child->document() && child->document()->ownerElement()) + child->document()->ownerElement()->setNeedsStyleRecalc(SyntheticStyleChange); + } +} + bool RenderLayerCompositor::layerHas3DContent(const RenderLayer* layer) const { const RenderStyle* style = layer->renderer()->style(); diff --git a/WebCore/rendering/RenderLayerCompositor.h b/WebCore/rendering/RenderLayerCompositor.h index 36f7c15..81f2058 100644 --- a/WebCore/rendering/RenderLayerCompositor.h +++ b/WebCore/rendering/RenderLayerCompositor.h @@ -34,6 +34,7 @@ namespace WebCore { #define PROFILE_LAYER_REBUILD 0 class GraphicsLayer; +class RenderIFrame; #if ENABLE(VIDEO) class RenderVideo; #endif @@ -121,11 +122,19 @@ public: RenderLayer* rootRenderLayer() const; GraphicsLayer* rootPlatformLayer() const; - void didMoveOnscreen(); - void willMoveOffscreen(); + enum RootLayerAttachment { + RootLayerUnattached, + RootLayerAttachedViaChromeClient, + RootLayerAttachedViaEnclosingIframe + }; + RootLayerAttachment rootLayerAttachment() const { return m_rootLayerAttachment; } + void updateRootLayerAttachment(); void updateRootLayerPosition(); + void didMoveOnscreen(); + void willMoveOffscreen(); + void didStartAcceleratedAnimation(); #if ENABLE(VIDEO) @@ -139,9 +148,17 @@ public: // Some platforms may wish to connect compositing layer trees between iframes and // their parent document. - static bool shouldPropagateCompositingToIFrameParent(); + bool shouldPropagateCompositingToEnclosingIFrame() const; + + Element* enclosingIFrameElement() const; - void setRootPlatformLayerClippingBox(const IntRect& contentsBox); + static RenderLayerCompositor* iframeContentsCompositor(RenderIFrame*); + // Return true if the layers changed. + static bool parentIFrameContentLayers(RenderIFrame*); + + // Update the geometry of the layers used for clipping and scrolling in frames. + void updateContentLayerOffset(const IntPoint& contentsOffset); + void updateContentLayerScrollPosition(const IntPoint&); private: // Whether the given RL needs a compositing layer. @@ -178,7 +195,14 @@ private: void ensureRootPlatformLayer(); void destroyRootPlatformLayer(); + + void attachRootPlatformLayer(RootLayerAttachment); + void detachRootPlatformLayer(); + + void rootLayerAttachmentChanged(); + void notifyIFramesOfCompositingChange(); + // Whether a running transition or animation enforces the need for a compositing layer. bool requiresCompositingForAnimation(RenderObject*) const; bool requiresCompositingForTransform(RenderObject*) const; @@ -201,11 +225,13 @@ private: bool m_showRepaintCounter; bool m_compositingConsultsOverlap; bool m_compositing; - bool m_rootLayerAttached; bool m_compositingLayersNeedRebuild; + + RootLayerAttachment m_rootLayerAttachment; // Enclosing clipping layer for iframe content - OwnPtr<GraphicsLayer> m_clippingLayer; + OwnPtr<GraphicsLayer> m_clipLayer; + OwnPtr<GraphicsLayer> m_scrollLayer; #if PROFILE_LAYER_REBUILD int m_rootLayerUpdateCount; diff --git a/WebCore/rendering/RenderLineBoxList.cpp b/WebCore/rendering/RenderLineBoxList.cpp index 3395347..92952b7 100644 --- a/WebCore/rendering/RenderLineBoxList.cpp +++ b/WebCore/rendering/RenderLineBoxList.cpp @@ -161,12 +161,21 @@ void RenderLineBoxList::paint(RenderBoxModelObject* renderer, RenderObject::Pain if (!firstLineBox()) return; + RenderView* v = renderer->view(); + bool usePrintRect = !v->printRect().isEmpty(); + // We can check the first box and last box and avoid painting if we don't // intersect. This is a quick short-circuit that we can take to avoid walking any lines. // FIXME: This check is flawed in the following extremely obscure way: // if some line in the middle has a huge overflow, it might actually extend below the last line. - int yPos = firstLineBox()->topVisibleOverflow() - renderer->maximalOutlineSize(paintInfo.phase); - int h = renderer->maximalOutlineSize(paintInfo.phase) + lastLineBox()->bottomVisibleOverflow() - yPos; + int firstLineTop = firstLineBox()->topVisibleOverflow(); + if (usePrintRect && !firstLineBox()->parent()) + firstLineTop = min(firstLineTop, firstLineBox()->root()->lineTop()); + int lastLineBottom = lastLineBox()->bottomVisibleOverflow(); + if (usePrintRect && !lastLineBox()->parent()) + lastLineBottom = max(lastLineBottom, lastLineBox()->root()->lineBottom()); + int yPos = firstLineTop - renderer->maximalOutlineSize(paintInfo.phase); + int h = renderer->maximalOutlineSize(paintInfo.phase) + lastLineBottom - yPos; yPos += ty; if (yPos >= paintInfo.rect.bottom() || yPos + h <= paintInfo.rect.y()) return; @@ -178,8 +187,6 @@ void RenderLineBoxList::paint(RenderBoxModelObject* renderer, RenderObject::Pain // See if our root lines intersect with the dirty rect. If so, then we paint // them. Note that boxes can easily overlap, so we can't make any assumptions // based off positions of our first line box or our last line box. - RenderView* v = renderer->view(); - bool usePrintRect = !v->printRect().isEmpty(); for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) { if (usePrintRect) { // FIXME: This is a feeble effort to avoid splitting a line across two pages. @@ -187,12 +194,19 @@ void RenderLineBoxList::paint(RenderBoxModelObject* renderer, RenderObject::Pain // The whole way objects break across pages needs to be redone. // Try to avoid splitting a line vertically, but only if it's less than the height // of the entire page. - if (curr->bottomVisibleOverflow() - curr->topVisibleOverflow() <= v->printRect().height()) { - if (ty + curr->bottomVisibleOverflow() > v->printRect().bottom()) { - if (ty + curr->topVisibleOverflow() < v->truncatedAt()) - v->setBestTruncatedAt(ty + curr->root()->topVisibleOverflow(), renderer); + int topForPaginationCheck = curr->topVisibleOverflow(); + int bottomForPaginationCheck = curr->bottomVisibleOverflow(); + if (!curr->parent()) { + // We're a root box. Use lineTop and lineBottom as well here. + topForPaginationCheck = min(topForPaginationCheck, curr->root()->lineTop()); + bottomForPaginationCheck = max(bottomForPaginationCheck, curr->root()->lineBottom()); + } + if (bottomForPaginationCheck - topForPaginationCheck <= v->printRect().height()) { + if (ty + bottomForPaginationCheck > v->printRect().bottom()) { + if (ty + topForPaginationCheck < v->truncatedAt()) + v->setBestTruncatedAt(ty + topForPaginationCheck, renderer); // If we were able to truncate, don't paint. - if (ty + curr->topVisibleOverflow() >= v->truncatedAt()) + if (ty + topForPaginationCheck >= v->truncatedAt()) break; } } diff --git a/WebCore/rendering/RenderMeter.cpp b/WebCore/rendering/RenderMeter.cpp new file mode 100644 index 0000000..9dc6a26 --- /dev/null +++ b/WebCore/rendering/RenderMeter.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). + * + * 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" +#if ENABLE(METER_TAG) + +#include "RenderMeter.h" + +#include "HTMLMeterElement.h" +#include "RenderTheme.h" + +using namespace std; + +namespace WebCore { + +using namespace HTMLNames; + +RenderMeter::RenderMeter(HTMLMeterElement* element) + : RenderBlock(element) +{ +} + +void RenderMeter::layout() +{ + ASSERT(needsLayout()); + + LayoutRepainter repainter(*this, checkForRepaintDuringLayout()); + + calcWidth(); + calcHeight(); + + m_overflow.clear(); + + repainter.repaintAfterLayout(); + + setNeedsLayout(false); +} + +void RenderMeter::updateFromElement() +{ + repaint(); +} + +} // namespace WebCore +#endif diff --git a/WebCore/rendering/RenderMeter.h b/WebCore/rendering/RenderMeter.h new file mode 100644 index 0000000..2fc7844 --- /dev/null +++ b/WebCore/rendering/RenderMeter.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * + * 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. + * + */ + +#ifndef RenderMeter_h +#define RenderMeter_h + +#if ENABLE(METER_TAG) +#include "RenderBlock.h" +#include "RenderWidget.h" + +namespace WebCore { + +class HTMLMeterElement; + +class RenderMeter : public RenderBlock { +public: + RenderMeter(HTMLMeterElement*); + +private: + virtual const char* renderName() const { return "RenderMeter"; } + virtual bool isMeter() const { return true; } + virtual void layout(); + virtual void updateFromElement(); +}; + +inline RenderMeter* toRenderMeter(RenderObject* object) +{ + ASSERT(!object || object->isMeter()); + return static_cast<RenderMeter*>(object); +} + +// This will catch anyone doing an unnecessary cast. +void toRenderMeter(const RenderMeter*); + +} // namespace WebCore + +#endif + +#endif // RenderMeter_h + diff --git a/WebCore/rendering/RenderObject.cpp b/WebCore/rendering/RenderObject.cpp index 1c93ac4..d7df436 100644 --- a/WebCore/rendering/RenderObject.cpp +++ b/WebCore/rendering/RenderObject.cpp @@ -1099,20 +1099,29 @@ RenderBoxModelObject* RenderObject::containerForRepaint() const void RenderObject::repaintUsingContainer(RenderBoxModelObject* repaintContainer, const IntRect& r, bool immediate) { - if (!repaintContainer || repaintContainer->isRenderView()) { - RenderView* v = repaintContainer ? toRenderView(repaintContainer) : view(); - v->repaintViewRectangle(r, immediate); - } else { + if (!repaintContainer) { + view()->repaintViewRectangle(r, immediate); + return; + } + #if USE(ACCELERATED_COMPOSITING) - RenderView* v = view(); - if (v->usesCompositing()) { - ASSERT(repaintContainer->hasLayer() && repaintContainer->layer()->isComposited()); - repaintContainer->layer()->setBackingNeedsRepaintInRect(r); + RenderView* v = view(); + if (repaintContainer->isRenderView()) { + ASSERT(repaintContainer == v); + if (!v->hasLayer() || !v->layer()->isComposited() || v->layer()->backing()->paintingGoesToWindow()) { + v->repaintViewRectangle(r, immediate); + return; } + } + + if (v->usesCompositing()) { + ASSERT(repaintContainer->hasLayer() && repaintContainer->layer()->isComposited()); + repaintContainer->layer()->setBackingNeedsRepaintInRect(r); + } #else - ASSERT_NOT_REACHED(); + if (repaintContainer->isRenderView()) + toRenderView(repaintContainer)->repaintViewRectangle(r, immediate); #endif - } } void RenderObject::repaint(bool immediate) diff --git a/WebCore/rendering/RenderObject.h b/WebCore/rendering/RenderObject.h index 9d8a306..3fce1ee 100644 --- a/WebCore/rendering/RenderObject.h +++ b/WebCore/rendering/RenderObject.h @@ -276,6 +276,9 @@ public: virtual bool isListMarker() const { return false; } virtual bool isMedia() const { return false; } virtual bool isMenuList() const { return false; } +#if ENABLE(METER_TAG) + virtual bool isMeter() const { return false; } +#endif #if ENABLE(PROGRESS_TAG) virtual bool isProgress() const { return false; } #endif diff --git a/WebCore/rendering/RenderProgress.cpp b/WebCore/rendering/RenderProgress.cpp index b42cc8b..cf98f18 100644 --- a/WebCore/rendering/RenderProgress.cpp +++ b/WebCore/rendering/RenderProgress.cpp @@ -167,11 +167,16 @@ PassRefPtr<RenderStyle> RenderProgress::createStyleForValuePart(RenderStyle* par return styleForValuePart.release(); } -double RenderProgress::animationProgress() +double RenderProgress::animationProgress() const { return m_animating ? (fmod((currentTime() - m_animationStartTime), m_animationDuration) / m_animationDuration) : 0; } +bool RenderProgress::isDeterminate() const +{ + return 0 <= position(); +} + void RenderProgress::animationTimerFired(Timer<RenderProgress>*) { repaint(); diff --git a/WebCore/rendering/RenderProgress.h b/WebCore/rendering/RenderProgress.h index 0d93ae7..2070974 100644 --- a/WebCore/rendering/RenderProgress.h +++ b/WebCore/rendering/RenderProgress.h @@ -34,9 +34,10 @@ public: RenderProgress(HTMLProgressElement*); virtual ~RenderProgress(); - double position() { return m_position; } - double animationProgress(); - + double position() const { return m_position; } + double animationProgress() const; + bool isDeterminate() const; + HTMLProgressElement* progressElement() const; private: diff --git a/WebCore/rendering/RenderSVGImage.cpp b/WebCore/rendering/RenderSVGImage.cpp index 1fb7c0f..006142c 100644 --- a/WebCore/rendering/RenderSVGImage.cpp +++ b/WebCore/rendering/RenderSVGImage.cpp @@ -33,6 +33,8 @@ #include "GraphicsContext.h" #include "PointerEventsHitRules.h" #include "RenderLayer.h" +#include "RenderSVGResourceContainer.h" +#include "RenderSVGResourceFilter.h" #include "SVGImageElement.h" #include "SVGLength.h" #include "SVGPreserveAspectRatio.h" @@ -174,6 +176,12 @@ FloatRect RenderSVGImage::repaintRectInLocalCoordinates() const void RenderSVGImage::imageChanged(WrappedImagePtr image, const IntRect* rect) { RenderImage::imageChanged(image, rect); +#if ENABLE(FILTERS) + // The image resource defaults to nullImage until the resource arrives. + // This empty image may be cached by SVG filter effects which must be invalidated. + if (RenderSVGResourceFilter* filter = getRenderSVGResourceById<RenderSVGResourceFilter>(document(), style()->svgStyle()->filterResource())) + filter->invalidateClient(this); +#endif repaint(); } diff --git a/WebCore/rendering/RenderSVGResource.h b/WebCore/rendering/RenderSVGResource.h index f14fa4a..4e33e55 100644 --- a/WebCore/rendering/RenderSVGResource.h +++ b/WebCore/rendering/RenderSVGResource.h @@ -60,7 +60,7 @@ public: virtual bool applyResource(RenderObject*, RenderStyle*, GraphicsContext*&, unsigned short resourceMode) = 0; virtual void postApplyResource(RenderObject*, GraphicsContext*&, unsigned short) { } - virtual FloatRect resourceBoundingBox(const FloatRect&) const = 0; + virtual FloatRect resourceBoundingBox(const FloatRect&) = 0; virtual RenderSVGResourceType resourceType() const = 0; diff --git a/WebCore/rendering/RenderSVGResourceClipper.cpp b/WebCore/rendering/RenderSVGResourceClipper.cpp index 2759976..0f82903 100644 --- a/WebCore/rendering/RenderSVGResourceClipper.cpp +++ b/WebCore/rendering/RenderSVGResourceClipper.cpp @@ -21,6 +21,7 @@ */ #include "config.h" +#if ENABLE(SVG) #include "RenderSVGResourceClipper.h" #include "AffineTransform.h" @@ -65,6 +66,7 @@ void RenderSVGResourceClipper::invalidateClients() } deleteAllValues(m_clipper); m_clipper.clear(); + m_clipBoundaries = FloatRect(); } void RenderSVGResourceClipper::invalidateClient(RenderObject* object) @@ -237,11 +239,10 @@ bool RenderSVGResourceClipper::createClipData(ClipperData* clipperData, const Fl svgStyle->setMaskerResource(String()); renderer->setStyle(newRenderStyle.release()); - // Get the renderer of the element, that is referenced by the <use>-element. - if (isUseElement) - renderer = childNode->renderer(); - - renderSubtreeToImage(clipperData->clipMaskImage.get(), renderer); + // In the case of a <use> element, we obtained its renderere above, to retrieve its clipRule. + // We hsve to pass the <use> renderer itself to renderSubtreeToImage() to apply it's x/y/transform/etc. values when rendering. + // So if isUseElement is true, refetch the childNode->renderer(), as renderer got overriden above. + renderSubtreeToImage(clipperData->clipMaskImage.get(), isUseElement ? childNode->renderer() : renderer); renderer->setStyle(oldRenderStyle.release()); } @@ -251,27 +252,37 @@ bool RenderSVGResourceClipper::createClipData(ClipperData* clipperData, const Fl return true; } -FloatRect RenderSVGResourceClipper::resourceBoundingBox(const FloatRect& objectBoundingBox) const +void RenderSVGResourceClipper::calculateClipContentRepaintRect() { // This is a rough heuristic to appraise the clip size and doesn't consider clip on clip. - FloatRect clipRect; for (Node* childNode = node()->firstChild(); childNode; childNode = childNode->nextSibling()) { RenderObject* renderer = childNode->renderer(); if (!childNode->isSVGElement() || !static_cast<SVGElement*>(childNode)->isStyled() || !renderer) continue; if (!renderer->isRenderPath() && !renderer->isSVGText() && !renderer->isSVGShadowTreeRootContainer()) continue; - clipRect.unite(renderer->localToParentTransform().mapRect(renderer->repaintRectInLocalCoordinates())); + RenderStyle* style = renderer->style(); + if (!style || style->display() == NONE || style->visibility() != VISIBLE) + continue; + m_clipBoundaries.unite(renderer->localToParentTransform().mapRect(renderer->repaintRectInLocalCoordinates())); } +} + +FloatRect RenderSVGResourceClipper::resourceBoundingBox(const FloatRect& objectBoundingBox) +{ + if (m_clipBoundaries.isEmpty()) + calculateClipContentRepaintRect(); if (static_cast<SVGClipPathElement*>(node())->clipPathUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { AffineTransform transform; transform.translate(objectBoundingBox.x(), objectBoundingBox.y()); transform.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height()); - return transform.mapRect(clipRect); + return transform.mapRect(m_clipBoundaries); } - return clipRect; + return m_clipBoundaries; } } + +#endif // ENABLE(SVG) diff --git a/WebCore/rendering/RenderSVGResourceClipper.h b/WebCore/rendering/RenderSVGResourceClipper.h index 0b6f2b3..d8e2eed 100644 --- a/WebCore/rendering/RenderSVGResourceClipper.h +++ b/WebCore/rendering/RenderSVGResourceClipper.h @@ -51,7 +51,7 @@ public: virtual void invalidateClient(RenderObject*); virtual bool applyResource(RenderObject*, RenderStyle*, GraphicsContext*&, unsigned short resourceMode); - virtual FloatRect resourceBoundingBox(const FloatRect&) const; + virtual FloatRect resourceBoundingBox(const FloatRect&); virtual RenderSVGResourceType resourceType() const { return ClipperResourceType; } @@ -64,7 +64,9 @@ private: bool applyClippingToContext(RenderObject*, const FloatRect&, const FloatRect&, GraphicsContext*); bool pathOnlyClipping(GraphicsContext*, const FloatRect&); bool createClipData(ClipperData*, const FloatRect&, const FloatRect&); + void calculateClipContentRepaintRect(); + FloatRect m_clipBoundaries; HashMap<RenderObject*, ClipperData*> m_clipper; }; diff --git a/WebCore/rendering/RenderSVGResourceFilter.cpp b/WebCore/rendering/RenderSVGResourceFilter.cpp index ac3ea49..ea30d77 100644 --- a/WebCore/rendering/RenderSVGResourceFilter.cpp +++ b/WebCore/rendering/RenderSVGResourceFilter.cpp @@ -281,7 +281,7 @@ void RenderSVGResourceFilter::postApplyResource(RenderObject* object, GraphicsCo m_sourceGraphicBuffer.clear(); } -FloatRect RenderSVGResourceFilter::resourceBoundingBox(const FloatRect& objectBoundingBox) const +FloatRect RenderSVGResourceFilter::resourceBoundingBox(const FloatRect& objectBoundingBox) { if (SVGFilterElement* element = static_cast<SVGFilterElement*>(node())) return element->filterBoundingBox(objectBoundingBox); diff --git a/WebCore/rendering/RenderSVGResourceFilter.h b/WebCore/rendering/RenderSVGResourceFilter.h index ce4a7e1..6e98492 100644 --- a/WebCore/rendering/RenderSVGResourceFilter.h +++ b/WebCore/rendering/RenderSVGResourceFilter.h @@ -68,7 +68,7 @@ public: virtual bool applyResource(RenderObject*, RenderStyle*, GraphicsContext*&, unsigned short resourceMode); virtual void postApplyResource(RenderObject*, GraphicsContext*&, unsigned short resourceMode); - virtual FloatRect resourceBoundingBox(const FloatRect&) const; + virtual FloatRect resourceBoundingBox(const FloatRect&); PassOwnPtr<SVGFilterBuilder> buildPrimitives(); diff --git a/WebCore/rendering/RenderSVGResourceGradient.h b/WebCore/rendering/RenderSVGResourceGradient.h index 2fd9cf4..4d848af 100644 --- a/WebCore/rendering/RenderSVGResourceGradient.h +++ b/WebCore/rendering/RenderSVGResourceGradient.h @@ -54,7 +54,7 @@ public: virtual bool applyResource(RenderObject*, RenderStyle*, GraphicsContext*&, unsigned short resourceMode); virtual void postApplyResource(RenderObject*, GraphicsContext*&, unsigned short resourceMode); - virtual FloatRect resourceBoundingBox(const FloatRect&) const { return FloatRect(); } + virtual FloatRect resourceBoundingBox(const FloatRect&) { return FloatRect(); } protected: void addStops(GradientData*, const Vector<Gradient::ColorStop>&) const; diff --git a/WebCore/rendering/RenderSVGResourceMarker.cpp b/WebCore/rendering/RenderSVGResourceMarker.cpp index 460239b..4a300c2 100644 --- a/WebCore/rendering/RenderSVGResourceMarker.cpp +++ b/WebCore/rendering/RenderSVGResourceMarker.cpp @@ -21,6 +21,7 @@ */ #include "config.h" +#if ENABLE(SVG) #include "RenderSVGResourceMarker.h" #include "GraphicsContext.h" @@ -198,3 +199,5 @@ void RenderSVGResourceMarker::calcViewport() } } + +#endif // ENABLE(SVG) diff --git a/WebCore/rendering/RenderSVGResourceMarker.h b/WebCore/rendering/RenderSVGResourceMarker.h index efbbdfa..fe848a9 100644 --- a/WebCore/rendering/RenderSVGResourceMarker.h +++ b/WebCore/rendering/RenderSVGResourceMarker.h @@ -58,7 +58,7 @@ public: AffineTransform markerTransformation(const FloatPoint& origin, float angle, float strokeWidth) const; virtual bool applyResource(RenderObject*, RenderStyle*, GraphicsContext*&, unsigned short) { return false; } - virtual FloatRect resourceBoundingBox(const FloatRect&) const { return FloatRect(); } + virtual FloatRect resourceBoundingBox(const FloatRect&) { return FloatRect(); } FloatPoint referencePoint() const; float angle() const; diff --git a/WebCore/rendering/RenderSVGResourceMasker.cpp b/WebCore/rendering/RenderSVGResourceMasker.cpp index abf8e48..2bfb283 100644 --- a/WebCore/rendering/RenderSVGResourceMasker.cpp +++ b/WebCore/rendering/RenderSVGResourceMasker.cpp @@ -19,6 +19,7 @@ */ #include "config.h" +#if ENABLE(SVG) #include "RenderSVGResourceMasker.h" #include "AffineTransform.h" @@ -65,6 +66,7 @@ void RenderSVGResourceMasker::invalidateClients() deleteAllValues(m_masker); m_masker.clear(); + m_maskBoundaries = FloatRect(); } void RenderSVGResourceMasker::invalidateClient(RenderObject* object) @@ -111,14 +113,6 @@ bool RenderSVGResourceMasker::applyResource(RenderObject* object, RenderStyle*, return true; } -FloatRect RenderSVGResourceMasker::resourceBoundingBox(const FloatRect& objectBoundingBox) const -{ - if (SVGMaskElement* element = static_cast<SVGMaskElement*>(node())) - return element->maskBoundingBox(objectBoundingBox); - - return FloatRect(); -} - void RenderSVGResourceMasker::createMaskImage(MaskerData* maskerData, const SVGMaskElement* maskElement, RenderObject* object) { FloatRect objectBoundingBox = object->objectBoundingBox(); @@ -129,19 +123,11 @@ void RenderSVGResourceMasker::createMaskImage(MaskerData* maskerData, const SVGM maskerData->emptyMask = true; return; } + + if (m_maskBoundaries.isEmpty()) + calculateMaskContentRepaintRect(); - // Calculate the smallest rect for the mask ImageBuffer. - FloatRect repaintRect; - Vector<RenderObject*> rendererList; - for (Node* node = maskElement->firstChild(); node; node = node->nextSibling()) { - RenderObject* renderer = node->renderer(); - if (!node->isSVGElement() || !static_cast<SVGElement*>(node)->isStyled() || !renderer) - continue; - - rendererList.append(renderer); - repaintRect.unite(renderer->localToParentTransform().mapRect(renderer->repaintRectInLocalCoordinates())); - } - + FloatRect repaintRect = m_maskBoundaries; AffineTransform contextTransform; // We need to scale repaintRect for objectBoundingBox to get the drawing area. if (maskElement->maskContentUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { @@ -180,9 +166,15 @@ void RenderSVGResourceMasker::createMaskImage(MaskerData* maskerData, const SVGM maskImageContext->concatCTM(contextTransform); // draw the content into the ImageBuffer - Vector<RenderObject*>::iterator end = rendererList.end(); - for (Vector<RenderObject*>::iterator it = rendererList.begin(); it != end; it++) - renderSubtreeToImage(maskerData->maskImage.get(), *it); + for (Node* node = maskElement->firstChild(); node; node = node->nextSibling()) { + RenderObject* renderer = node->renderer(); + if (!node->isSVGElement() || !static_cast<SVGElement*>(node)->isStyled() || !renderer) + continue; + RenderStyle* style = renderer->style(); + if (!style || style->display() == NONE || style->visibility() != VISIBLE) + continue; + renderSubtreeToImage(maskerData->maskImage.get(), renderer); + } maskImageContext->restore(); @@ -205,4 +197,40 @@ void RenderSVGResourceMasker::createMaskImage(MaskerData* maskerData, const SVGM maskerData->maskImage->putUnmultipliedImageData(imageData.get(), maskImageRect, IntPoint()); } +void RenderSVGResourceMasker::calculateMaskContentRepaintRect() +{ + for (Node* childNode = node()->firstChild(); childNode; childNode = childNode->nextSibling()) { + RenderObject* renderer = childNode->renderer(); + if (!childNode->isSVGElement() || !static_cast<SVGElement*>(childNode)->isStyled() || !renderer) + continue; + RenderStyle* style = renderer->style(); + if (!style || style->display() == NONE || style->visibility() != VISIBLE) + continue; + m_maskBoundaries.unite(renderer->localToParentTransform().mapRect(renderer->repaintRectInLocalCoordinates())); + } } + +FloatRect RenderSVGResourceMasker::resourceBoundingBox(const FloatRect& objectBoundingBox) +{ + if (m_maskBoundaries.isEmpty()) + calculateMaskContentRepaintRect(); + + SVGMaskElement* maskElement = static_cast<SVGMaskElement*>(node()); + if (!maskElement) + return FloatRect(); + + FloatRect maskRect = m_maskBoundaries; + if (maskElement->maskContentUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { + AffineTransform transform; + transform.translate(objectBoundingBox.x(), objectBoundingBox.y()); + transform.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height()); + maskRect = transform.mapRect(maskRect); + } + + maskRect.intersect(maskElement->maskBoundingBox(objectBoundingBox)); + return maskRect; +} + +} + +#endif // ENABLE(SVG) diff --git a/WebCore/rendering/RenderSVGResourceMasker.h b/WebCore/rendering/RenderSVGResourceMasker.h index b022f7b..2de5f3f 100644 --- a/WebCore/rendering/RenderSVGResourceMasker.h +++ b/WebCore/rendering/RenderSVGResourceMasker.h @@ -57,7 +57,7 @@ public: virtual void invalidateClient(RenderObject*); virtual bool applyResource(RenderObject*, RenderStyle*, GraphicsContext*&, unsigned short resourceMode); - virtual FloatRect resourceBoundingBox(const FloatRect&) const; + virtual FloatRect resourceBoundingBox(const FloatRect&); SVGUnitTypes::SVGUnitType maskUnits() const { return toUnitType(static_cast<SVGMaskElement*>(node())->maskUnits()); } SVGUnitTypes::SVGUnitType maskContentUnits() const { return toUnitType(static_cast<SVGMaskElement*>(node())->maskContentUnits()); } @@ -67,7 +67,9 @@ public: private: void createMaskImage(MaskerData*, const SVGMaskElement*, RenderObject*); + void calculateMaskContentRepaintRect(); + FloatRect m_maskBoundaries; HashMap<RenderObject*, MaskerData*> m_masker; }; diff --git a/WebCore/rendering/RenderSVGResourcePattern.h b/WebCore/rendering/RenderSVGResourcePattern.h index 2f9d553..4129934 100644 --- a/WebCore/rendering/RenderSVGResourcePattern.h +++ b/WebCore/rendering/RenderSVGResourcePattern.h @@ -54,7 +54,7 @@ public: virtual bool applyResource(RenderObject*, RenderStyle*, GraphicsContext*&, unsigned short resourceMode); virtual void postApplyResource(RenderObject*, GraphicsContext*&, unsigned short resourceMode); - virtual FloatRect resourceBoundingBox(const FloatRect&) const { return FloatRect(); } + virtual FloatRect resourceBoundingBox(const FloatRect&) { return FloatRect(); } virtual RenderSVGResourceType resourceType() const { return s_resourceType; } static RenderSVGResourceType s_resourceType; diff --git a/WebCore/rendering/RenderSVGResourceSolidColor.h b/WebCore/rendering/RenderSVGResourceSolidColor.h index a1a8863..a4de62d 100644 --- a/WebCore/rendering/RenderSVGResourceSolidColor.h +++ b/WebCore/rendering/RenderSVGResourceSolidColor.h @@ -38,7 +38,7 @@ public: virtual bool applyResource(RenderObject*, RenderStyle*, GraphicsContext*&, unsigned short resourceMode); virtual void postApplyResource(RenderObject*, GraphicsContext*&, unsigned short resourceMode); - virtual FloatRect resourceBoundingBox(const FloatRect&) const { return FloatRect(); } + virtual FloatRect resourceBoundingBox(const FloatRect&) { return FloatRect(); } virtual RenderSVGResourceType resourceType() const { return s_resourceType; } static RenderSVGResourceType s_resourceType; diff --git a/WebCore/rendering/RenderTextControlMultiLine.cpp b/WebCore/rendering/RenderTextControlMultiLine.cpp index 9fbde3a..76bf612 100644 --- a/WebCore/rendering/RenderTextControlMultiLine.cpp +++ b/WebCore/rendering/RenderTextControlMultiLine.cpp @@ -114,7 +114,7 @@ void RenderTextControlMultiLine::updateFromElement() HTMLTextAreaElement* textArea = static_cast<HTMLTextAreaElement*>(node()); if (m_placeholderVisible) - setInnerTextValue(textArea->getAttribute(HTMLNames::placeholderAttr)); + setInnerTextValue(textArea->strippedPlaceholder()); else setInnerTextValue(textArea->value()); } diff --git a/WebCore/rendering/RenderTextControlSingleLine.cpp b/WebCore/rendering/RenderTextControlSingleLine.cpp index 37d44c4..f454c63 100644 --- a/WebCore/rendering/RenderTextControlSingleLine.cpp +++ b/WebCore/rendering/RenderTextControlSingleLine.cpp @@ -569,8 +569,10 @@ void RenderTextControlSingleLine::updateFromElement() updateCancelButtonVisibility(); if (m_placeholderVisible) { + // node() must be an HTMLInputElement. WMLInputElement doesn't support placeholder. + ASSERT(node()->isHTMLElement()); ExceptionCode ec = 0; - innerTextElement()->setInnerText(static_cast<Element*>(node())->getAttribute(placeholderAttr), ec); + innerTextElement()->setInnerText(static_cast<HTMLInputElement*>(node())->strippedPlaceholder(), ec); ASSERT(!ec); } else { if (!inputElement()->suggestedValue().isNull()) diff --git a/WebCore/rendering/RenderTheme.cpp b/WebCore/rendering/RenderTheme.cpp index 76af001..b1c23b1 100644 --- a/WebCore/rendering/RenderTheme.cpp +++ b/WebCore/rendering/RenderTheme.cpp @@ -24,6 +24,7 @@ #include "CSSValueKeywords.h" #include "Document.h" +#include "FloatConversion.h" #include "FocusController.h" #include "FontSelector.h" #include "Frame.h" @@ -38,6 +39,11 @@ #include "Settings.h" #include "TextControlInnerElements.h" +#if ENABLE(METER_TAG) +#include "HTMLMeterElement.h" +#include "RenderMeter.h" +#endif + // The methods in this file are shared by all themes on every platform. namespace WebCore { @@ -218,6 +224,10 @@ void RenderTheme::adjustStyle(CSSStyleSelector* selector, RenderStyle* style, El case ProgressBarPart: return adjustProgressBarStyle(selector, style, e); #endif +#if ENABLE(Meter_TAG) + case MeterPart: + return adjustMeterStyle(selector, style, e); +#endif default: break; } @@ -276,6 +286,10 @@ bool RenderTheme::paint(RenderObject* o, const RenderObject::PaintInfo& paintInf #endif case MenulistPart: return paintMenuList(o, paintInfo, r); +#if ENABLE(METER_TAG) + case MeterPart: + return paintMeter(o, paintInfo, r); +#endif #if ENABLE(PROGRESS_TAG) case ProgressBarPart: return paintProgressBar(o, paintInfo, r); @@ -370,6 +384,9 @@ bool RenderTheme::paintBorderOnly(RenderObject* o, const RenderObject::PaintInfo case DefaultButtonPart: case ButtonPart: case MenulistPart: +#if ENABLE(METER_TAG) + case MeterPart: +#endif #if ENABLE(PROGRESS_TAG) case ProgressBarPart: #endif @@ -408,6 +425,9 @@ bool RenderTheme::paintDecorations(RenderObject* o, const RenderObject::PaintInf case DefaultButtonPart: case ButtonPart: case MenulistPart: +#if ENABLE(METER_TAG) + case MeterPart: +#endif #if ENABLE(PROGRESS_TAG) case ProgressBarPart: #endif @@ -871,6 +891,61 @@ void RenderTheme::adjustMenuListStyle(CSSStyleSelector*, RenderStyle*, Element*) { } +#if ENABLE(METER_TAG) +void RenderTheme::adjustMeterStyle(CSSStyleSelector*, RenderStyle* style, Element*) const +{ + style->setBoxShadow(0); +} + +bool RenderTheme::paintMeter(RenderObject* renderObject, const RenderObject::PaintInfo& paintInfo, const IntRect& rect) +{ + // Some platforms do not have a native gauge widget, so we draw here a default implementation. + RenderMeter* renderMeter = toRenderMeter(renderObject); + RenderStyle* style = renderObject->style(); + int left = style->borderLeft().width() + style->paddingLeft().value(); + int top = style->borderTop().width() + style->paddingTop().value(); + int right = style->borderRight().width() + style->paddingRight().value(); + int bottom = style->borderBottom().width() + style->paddingBottom().value(); + FloatRect innerRect(rect.x() + left, rect.y() + top, rect.width() - left - right, rect.height() - top - bottom); + + HTMLMeterElement* element = static_cast<HTMLMeterElement*>(renderMeter->node()); + double min = element->min(); + double max = element->max(); + double value = element->value(); + + if (min >= max) { + paintInfo.context->fillRect(innerRect, Color::black, style->colorSpace()); + return false; + } + + // Paint the background first + paintInfo.context->fillRect(innerRect, Color::lightGray, style->colorSpace()); + + FloatRect valueRect; + + if (rect.width() < rect.height()) { + // Vertical gauge + double scale = innerRect.height() / (max - min); + valueRect.setLocation(FloatPoint(innerRect.x(), innerRect.y() + narrowPrecisionToFloat((max - value) * scale))); + valueRect.setSize(FloatSize(innerRect.width(), narrowPrecisionToFloat((value - min) * scale))); + } else if (renderMeter->style()->direction() == RTL) { + // right to left horizontal gauge + double scale = innerRect.width() / (max - min); + valueRect.setLocation(FloatPoint(innerRect.x() + narrowPrecisionToFloat((max - value) * scale), innerRect.y())); + valueRect.setSize(FloatSize(narrowPrecisionToFloat((value - min) * scale), innerRect.height())); + } else { + // left to right horizontal gauge + double scale = innerRect.width() / (max - min); + valueRect.setLocation(innerRect.location()); + valueRect.setSize(FloatSize(narrowPrecisionToFloat((value - min)) * scale, innerRect.height())); + } + if (!valueRect.isEmpty()) + paintInfo.context->fillRect(valueRect, Color::black, style->colorSpace()); + + return false; +} +#endif + #if ENABLE(PROGRESS_TAG) double RenderTheme::animationRepeatIntervalForProgressBar(RenderProgress*) const { diff --git a/WebCore/rendering/RenderTheme.h b/WebCore/rendering/RenderTheme.h index 6edc878..a4514a5 100644 --- a/WebCore/rendering/RenderTheme.h +++ b/WebCore/rendering/RenderTheme.h @@ -240,6 +240,11 @@ protected: virtual void adjustMenuListButtonStyle(CSSStyleSelector*, RenderStyle*, Element*) const; virtual bool paintMenuListButton(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return true; } +#if ENABLE(METER_TAG) + virtual void adjustMeterStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual bool paintMeter(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); +#endif + #if ENABLE(PROGRESS_TAG) virtual void adjustProgressBarStyle(CSSStyleSelector*, RenderStyle*, Element*) const; virtual bool paintProgressBar(RenderObject*, const RenderObject::PaintInfo&, const IntRect&) { return true; } diff --git a/WebCore/rendering/RenderThemeChromiumWin.cpp b/WebCore/rendering/RenderThemeChromiumWin.cpp index db31825..5d39698 100644 --- a/WebCore/rendering/RenderThemeChromiumWin.cpp +++ b/WebCore/rendering/RenderThemeChromiumWin.cpp @@ -38,6 +38,7 @@ #include "HTMLNames.h" #include "MediaControlElements.h" #include "RenderBox.h" +#include "RenderProgress.h" #include "RenderSlider.h" #include "ScrollbarTheme.h" #include "TransparencyWin.h" @@ -653,4 +654,60 @@ bool RenderThemeChromiumWin::paintTextFieldInternal(RenderObject* o, return false; } +#if ENABLE(PROGRESS_TAG) + +// MSDN says that update intervals for the bar is 30ms. +// http://msdn.microsoft.com/en-us/library/bb760842(v=VS.85).aspx +static const double progressAnimationFrameRate = 0.033; +// There is no documentation about the animation speed, frame-rate, nor +// size of moving overlay of the indeterminate progress bar. +// So we just observed real-world programs and guessed following parameters. +static const double progressIndeterminateOverlayPixelsPerSecond = 175; +static const int progressIndeterminateOverlayWidth = 120; + +double RenderThemeChromiumWin::animationRepeatIntervalForProgressBar(RenderProgress*) const +{ + return progressAnimationFrameRate; +} + +double RenderThemeChromiumWin::animationDurationForProgressBar(RenderProgress* renderProgress) const +{ + if (renderProgress->isDeterminate()) + return 0; + return (renderProgress->width() + progressIndeterminateOverlayWidth) / progressIndeterminateOverlayPixelsPerSecond; +} + +void RenderThemeChromiumWin::adjustProgressBarStyle(CSSStyleSelector*, RenderStyle*, Element*) const +{ +} + +bool RenderThemeChromiumWin::paintProgressBar(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r) +{ + RenderProgress* renderProgress = toRenderProgress(o); + + int valuePart; + IntRect valueRect; + if (renderProgress->isDeterminate()) { + valuePart = PP_FILL; + int dx = r.width() * renderProgress->position(); + if (renderProgress->style()->direction() == RTL) + valueRect = IntRect(r.x() + r.width() - dx, r.y(), dx, r.height()); + else + valueRect = IntRect(r.x(), r.y(), dx, r.height()); + } else { + valuePart = PP_MOVEOVERLAY; + int dx = (r.width() + progressIndeterminateOverlayWidth) * renderProgress->animationProgress() - progressIndeterminateOverlayWidth; + valueRect = IntRect(r.x() + dx, r.y(), progressIndeterminateOverlayWidth, r.height()); + } + + ThemePainter painter(i.context, r); + ChromiumBridge::paintProgressBar(painter.context(), + r, + valuePart, + valueRect); + return true; +} + +#endif + } // namespace WebCore diff --git a/WebCore/rendering/RenderThemeChromiumWin.h b/WebCore/rendering/RenderThemeChromiumWin.h index bbc54a7..131314a 100644 --- a/WebCore/rendering/RenderThemeChromiumWin.h +++ b/WebCore/rendering/RenderThemeChromiumWin.h @@ -86,6 +86,14 @@ namespace WebCore { // See comment in RenderThemeChromiumSkia::setDefaultFontSize() regarding ugliness of this hack. static void setDefaultFontSize(int); + +#if ENABLE(PROGRESS_TAG) + virtual double animationRepeatIntervalForProgressBar(RenderProgress*) const; + virtual double animationDurationForProgressBar(RenderProgress*) const; + virtual void adjustProgressBarStyle(CSSStyleSelector*, RenderStyle*, Element*) const; + virtual bool paintProgressBar(RenderObject*, const RenderObject::PaintInfo&, const IntRect&); +#endif + protected: virtual double caretBlinkIntervalInternal() const; diff --git a/WebCore/rendering/RenderTreeAsText.cpp b/WebCore/rendering/RenderTreeAsText.cpp index 311854e..fd63c0e 100644 --- a/WebCore/rendering/RenderTreeAsText.cpp +++ b/WebCore/rendering/RenderTreeAsText.cpp @@ -81,7 +81,7 @@ static TextStream &operator<<(TextStream& ts, const IntRect& r) } #endif -static void writeIndent(TextStream& ts, int indent) +void writeIndent(TextStream& ts, int indent) { for (int i = 0; i != indent; ++i) ts << " "; @@ -185,7 +185,7 @@ static void writeRenderObject(TextStream& ts, const RenderObject& o, RenderAsTex ts << o.renderName(); if (behavior & RenderAsTextShowAddresses) - ts << " " << &o; + ts << " " << static_cast<const void*>(&o); if (o.style() && o.style()->zIndex()) ts << " zI: " << o.style()->zIndex(); @@ -476,7 +476,7 @@ static void write(TextStream& ts, RenderLayer& l, ts << "layer "; if (behavior & RenderAsTextShowAddresses) - ts << &l << " "; + ts << static_cast<const void*>(&l) << " "; ts << layerBounds; diff --git a/WebCore/rendering/RenderTreeAsText.h b/WebCore/rendering/RenderTreeAsText.h index 1427342..ecee7f9 100644 --- a/WebCore/rendering/RenderTreeAsText.h +++ b/WebCore/rendering/RenderTreeAsText.h @@ -47,6 +47,7 @@ typedef unsigned RenderAsTextBehavior; // You don't need pageWidthInPixels if you don't specify RenderAsTextInPrintingMode. String externalRepresentation(Frame*, RenderAsTextBehavior = RenderAsTextBehaviorNormal); void write(TextStream&, const RenderObject&, int indent = 0, RenderAsTextBehavior = RenderAsTextBehaviorNormal); +void writeIndent(TextStream&, int indent); // Helper function shared with SVGRenderTreeAsText String quoteAndEscapeNonPrintables(const String&); diff --git a/WebCore/rendering/RenderView.cpp b/WebCore/rendering/RenderView.cpp index 449e293..7a38e41 100644 --- a/WebCore/rendering/RenderView.cpp +++ b/WebCore/rendering/RenderView.cpp @@ -73,10 +73,6 @@ RenderView::RenderView(Node* node, FrameView* view) setPrefWidthsDirty(true, false); setPositioned(true); // to 0,0 :) - - // Create a new root layer for our layer hierarchy. - m_layer = new (node->document()->renderArena()) RenderLayer(this); - setHasLayer(true); } RenderView::~RenderView() @@ -216,6 +212,15 @@ void RenderView::paintBoxDecorations(PaintInfo& paintInfo, int, int) frameView()->setUseSlowRepaints(); break; } + +#if USE(ACCELERATED_COMPOSITING) + if (RenderLayer* compositingLayer = layer->enclosingCompositingLayer()) { + if (!compositingLayer->backing()->paintingGoesToWindow()) { + frameView()->setUseSlowRepaints(); + break; + } + } +#endif } // If painting will entirely fill the view, no need to fill the background. diff --git a/WebCore/rendering/RenderView.h b/WebCore/rendering/RenderView.h index 05c3876..799b206 100644 --- a/WebCore/rendering/RenderView.h +++ b/WebCore/rendering/RenderView.h @@ -44,6 +44,8 @@ public: virtual bool isRenderView() const { return true; } + virtual bool requiresLayer() const { return true; } + virtual void layout(); virtual void calcWidth(); virtual void calcHeight(); diff --git a/WebCore/rendering/RenderWidget.cpp b/WebCore/rendering/RenderWidget.cpp index 2c53da4..e477676 100644 --- a/WebCore/rendering/RenderWidget.cpp +++ b/WebCore/rendering/RenderWidget.cpp @@ -282,10 +282,15 @@ void RenderWidget::paint(PaintInfo& paintInfo, int tx, int ty) if (!paintOffset.isZero()) paintInfo.context->translate(-paintOffset); } - if (m_widget->isFrameView() && paintInfo.overlapTestRequests && !static_cast<FrameView*>(m_widget.get())->useSlowRepaintsIfNotOverlapped()) { - ASSERT(!paintInfo.overlapTestRequests->contains(this)); - paintInfo.overlapTestRequests->set(this, m_widget->frameRect()); - } + + if (m_widget->isFrameView()) { + FrameView* frameView = static_cast<FrameView*>(m_widget.get()); + bool runOverlapTests = !frameView->useSlowRepaintsIfNotOverlapped() || frameView->hasCompositedContent(); + if (paintInfo.overlapTestRequests && runOverlapTests) { + ASSERT(!paintInfo.overlapTestRequests->contains(this)); + paintInfo.overlapTestRequests->set(this, m_widget->frameRect()); + } + } } if (style()->hasBorderRadius()) diff --git a/WebCore/rendering/RootInlineBox.cpp b/WebCore/rendering/RootInlineBox.cpp index 23316f7..691179d 100644 --- a/WebCore/rendering/RootInlineBox.cpp +++ b/WebCore/rendering/RootInlineBox.cpp @@ -202,7 +202,7 @@ void RootInlineBox::childRemoved(InlineBox* box) } } -int RootInlineBox::verticallyAlignBoxes(int heightOfBlock) +int RootInlineBox::verticallyAlignBoxes(int heightOfBlock, GlyphOverflowAndFallbackFontsMap& textBoxDataMap) { int maxPositionTop = 0; int maxPositionBottom = 0; @@ -216,7 +216,7 @@ int RootInlineBox::verticallyAlignBoxes(int heightOfBlock) curr = curr->container(); bool strictMode = (curr && curr->document()->inStrictMode()); - computeLogicalBoxHeights(maxPositionTop, maxPositionBottom, maxAscent, maxDescent, strictMode); + computeLogicalBoxHeights(maxPositionTop, maxPositionBottom, maxAscent, maxDescent, strictMode, textBoxDataMap); if (maxAscent + maxDescent < max(maxPositionTop, maxPositionBottom)) adjustMaxAscentAndDescent(maxAscent, maxDescent, maxPositionTop, maxPositionBottom); @@ -225,7 +225,7 @@ int RootInlineBox::verticallyAlignBoxes(int heightOfBlock) int lineTop = heightOfBlock; int lineBottom = heightOfBlock; placeBoxesVertically(heightOfBlock, maxHeight, maxAscent, strictMode, lineTop, lineBottom); - computeVerticalOverflow(lineTop, lineBottom, strictMode); + computeVerticalOverflow(lineTop, lineBottom, strictMode, textBoxDataMap); setLineTopBottomPositions(lineTop, lineBottom); heightOfBlock += maxHeight; diff --git a/WebCore/rendering/RootInlineBox.h b/WebCore/rendering/RootInlineBox.h index fae0cba..cfa550b 100644 --- a/WebCore/rendering/RootInlineBox.h +++ b/WebCore/rendering/RootInlineBox.h @@ -61,7 +61,7 @@ public: int selectionBottom() const { return lineBottom(); } int selectionHeight() const { return max(0, selectionBottom() - selectionTop()); } - virtual int verticallyAlignBoxes(int heightOfBlock); + virtual int verticallyAlignBoxes(int heightOfBlock, GlyphOverflowAndFallbackFontsMap&); void setLineTopBottomPositions(int top, int bottom); virtual RenderLineBoxList* rendererLineBoxes() const; diff --git a/WebCore/rendering/SVGInlineFlowBox.cpp b/WebCore/rendering/SVGInlineFlowBox.cpp index 2649664..bbd61b3 100644 --- a/WebCore/rendering/SVGInlineFlowBox.cpp +++ b/WebCore/rendering/SVGInlineFlowBox.cpp @@ -37,13 +37,7 @@ void SVGInlineFlowBox::paint(RenderObject::PaintInfo&, int, int) ASSERT_NOT_REACHED(); } -int SVGInlineFlowBox::placeBoxesHorizontally(int, int&, int&, bool&) -{ - // no-op - return 0; -} - -int SVGInlineFlowBox::verticallyAlignBoxes(int) +int SVGInlineFlowBox::placeBoxesHorizontally(int, int&, int&, bool&, GlyphOverflowAndFallbackFontsMap&) { // no-op return 0; diff --git a/WebCore/rendering/SVGInlineFlowBox.h b/WebCore/rendering/SVGInlineFlowBox.h index f6eb87a..17ad528 100644 --- a/WebCore/rendering/SVGInlineFlowBox.h +++ b/WebCore/rendering/SVGInlineFlowBox.h @@ -41,8 +41,7 @@ public: void setHeight(int h) { m_height = h; } virtual void paint(RenderObject::PaintInfo&, int tx, int ty); - virtual int placeBoxesHorizontally(int x, int& leftPosition, int& rightPosition, bool& needsWordSpacing); - virtual int verticallyAlignBoxes(int heightOfBlock); + virtual int placeBoxesHorizontally(int x, int& leftPosition, int& rightPosition, bool& needsWordSpacing, GlyphOverflowAndFallbackFontsMap&); private: int m_height; diff --git a/WebCore/rendering/SVGInlineTextBox.cpp b/WebCore/rendering/SVGInlineTextBox.cpp index 8b35507..3ae272e 100644 --- a/WebCore/rendering/SVGInlineTextBox.cpp +++ b/WebCore/rendering/SVGInlineTextBox.cpp @@ -1,6 +1,7 @@ /** * Copyright (C) 2007 Rob Buis <buis@kde.org> * (C) 2007 Nikolas Zimmermann <zimmermann@kde.org> + * Copyright (C) Research In Motion Limited 2010. 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 @@ -24,14 +25,12 @@ #if ENABLE(SVG) #include "SVGInlineTextBox.h" -#include "Document.h" -#include "Editor.h" #include "Frame.h" #include "GraphicsContext.h" #include "InlineFlowBox.h" -#include "Range.h" #include "RenderSVGResource.h" #include "SVGRootInlineBox.h" +#include "SVGTextLayoutUtilities.h" #include "Text.h" #include <float.h> @@ -44,16 +43,6 @@ SVGInlineTextBox::SVGInlineTextBox(RenderObject* obj) { } -int SVGInlineTextBox::selectionTop() -{ - return m_y; -} - -int SVGInlineTextBox::selectionHeight() -{ - return m_height; -} - SVGRootInlineBox* SVGInlineTextBox::svgRootInlineBox() const { // Find associated root inline box @@ -74,7 +63,7 @@ SVGRootInlineBox* SVGInlineTextBox::svgRootInlineBox() const float SVGInlineTextBox::calculateGlyphWidth(RenderStyle* style, int offset, int extraCharsAvailable, int& charsConsumed, String& glyphName) const { ASSERT(style); - return style->font().floatWidth(svgTextRunForInlineTextBox(textRenderer()->text()->characters() + offset, 1, style, this, 0), extraCharsAvailable, charsConsumed, glyphName); + return style->font().floatWidth(svgTextRunForInlineTextBox(textRenderer()->characters() + offset, 1, style, this, 0), extraCharsAvailable, charsConsumed, glyphName); } float SVGInlineTextBox::calculateGlyphHeight(RenderStyle* style, int, int) const @@ -260,7 +249,7 @@ bool SVGInlineTextBox::svgCharacterHitsPosition(int x, int y, int& closestOffset if (x < charAtPos.x) { if (closestOffsetInBox > 0 && direction() == LTR) return true; - else if (closestOffsetInBox < (int) end() && direction() == RTL) + if (closestOffsetInBox < static_cast<int>(end()) && direction() == RTL) return true; return false; @@ -490,7 +479,7 @@ void SVGInlineTextBox::paintSelection(int boxStartOffset, const SVGChar& svgChar Color textColor = style->color(); Color color = renderer()->selectionBackgroundColor(); - if (!color.isValid() || color.alpha() == 0) + if (!color.isValid() || !color.alpha()) return; // If the text color ends up being the same as the selection background, invert the selection @@ -516,7 +505,7 @@ void SVGInlineTextBox::paintSelection(int boxStartOffset, const SVGChar& svgChar p->save(); int adjust = startPos >= boxStartOffset ? boxStartOffset : 0; - p->drawHighlightForText(font, svgTextRunForInlineTextBox(textRenderer()->text()->characters() + start() + boxStartOffset, length, style, this, svgChar.x), + p->drawHighlightForText(font, svgTextRunForInlineTextBox(textRenderer()->characters() + start() + boxStartOffset, length, style, this, svgChar.x), IntPoint((int) svgChar.x, (int) svgChar.y - font.ascent()), font.ascent() + font.descent(), color, style->colorSpace(), startPos - adjust, endPos - adjust); @@ -589,6 +578,233 @@ void SVGInlineTextBox::paintDecoration(ETextDecoration decoration, GraphicsConte context->restore(); } +void SVGInlineTextBox::buildLayoutInformation(SVGCharacterLayoutInfo& info, SVGLastGlyphInfo& lastGlyph) +{ + RenderText* textRenderer = this->textRenderer(); + ASSERT(textRenderer); + + RenderStyle* style = textRenderer->style(isFirstLineStyle()); + ASSERT(style); + + const Font& font = style->font(); + const UChar* characters = textRenderer->characters(); + + TextDirection textDirection = direction(); + unsigned startPosition = start(); + unsigned endPosition = end(); + unsigned length = len(); + + const SVGRenderStyle* svgStyle = style->svgStyle(); + bool isVerticalText = isVerticalWritingMode(svgStyle); + + int charsConsumed = 0; + for (unsigned i = 0; i < length; i += charsConsumed) { + SVGChar svgChar; + + if (info.inPathLayout()) + svgChar.pathData = SVGCharOnPath::create(); + + float glyphWidth = 0.0f; + float glyphHeight = 0.0f; + + int extraCharsAvailable = length - i - 1; + + String unicodeStr; + String glyphName; + if (textDirection == RTL) { + glyphWidth = calculateGlyphWidth(style, endPosition - i, extraCharsAvailable, charsConsumed, glyphName); + glyphHeight = calculateGlyphHeight(style, endPosition - i, extraCharsAvailable); + unicodeStr = String(characters + endPosition - i, charsConsumed); + } else { + glyphWidth = calculateGlyphWidth(style, startPosition + i, extraCharsAvailable, charsConsumed, glyphName); + glyphHeight = calculateGlyphHeight(style, startPosition + i, extraCharsAvailable); + unicodeStr = String(characters + startPosition + i, charsConsumed); + } + + bool assignedX = false; + bool assignedY = false; + + if (info.xValueAvailable() && (!info.inPathLayout() || (info.inPathLayout() && !isVerticalText))) { + if (!isVerticalText) + svgChar.newTextChunk = true; + + assignedX = true; + svgChar.drawnSeperated = true; + info.curx = info.xValueNext(); + } + + if (info.yValueAvailable() && (!info.inPathLayout() || (info.inPathLayout() && isVerticalText))) { + if (isVerticalText) + svgChar.newTextChunk = true; + + assignedY = true; + svgChar.drawnSeperated = true; + info.cury = info.yValueNext(); + } + + float dx = 0.0f; + float dy = 0.0f; + + // Apply x-axis shift + if (info.dxValueAvailable()) { + svgChar.drawnSeperated = true; + + dx = info.dxValueNext(); + info.dx += dx; + + if (!info.inPathLayout()) + info.curx += dx; + } + + // Apply y-axis shift + if (info.dyValueAvailable()) { + svgChar.drawnSeperated = true; + + dy = info.dyValueNext(); + info.dy += dy; + + if (!info.inPathLayout()) + info.cury += dy; + } + + // Take letter & word spacing and kerning into account + float spacing = font.letterSpacing() + calculateCSSKerning(style); + + const UChar* currentCharacter = characters + (textDirection == RTL ? endPosition - i : startPosition + i); + const UChar* lastCharacter = 0; + + if (textDirection == RTL) { + if (i < endPosition) + lastCharacter = characters + endPosition - i + 1; + } else { + if (i > 0) + lastCharacter = characters + startPosition + i - 1; + } + + // FIXME: SVG Kerning doesn't get applied on texts on path. + bool appliedSVGKerning = applySVGKerning(info, style, lastGlyph, unicodeStr, glyphName, isVerticalText); + if (info.nextDrawnSeperated || spacing != 0.0f || appliedSVGKerning) { + info.nextDrawnSeperated = false; + svgChar.drawnSeperated = true; + } + + if (currentCharacter && Font::treatAsSpace(*currentCharacter) && lastCharacter && !Font::treatAsSpace(*lastCharacter)) { + spacing += font.wordSpacing(); + + if (spacing != 0.0f && !info.inPathLayout()) + info.nextDrawnSeperated = true; + } + + float orientationAngle = glyphOrientationToAngle(svgStyle, isVerticalText, *currentCharacter); + + float xOrientationShift = 0.0f; + float yOrientationShift = 0.0f; + float glyphAdvance = applyGlyphAdvanceAndShiftRespectingOrientation(isVerticalText, orientationAngle, glyphWidth, glyphHeight, + font, svgChar, xOrientationShift, yOrientationShift); + + // Handle textPath layout mode + if (info.inPathLayout()) { + float extraAdvance = isVerticalText ? dy : dx; + float newOffset = FLT_MIN; + + if (assignedX && !isVerticalText) + newOffset = info.curx; + else if (assignedY && isVerticalText) + newOffset = info.cury; + + float correctedGlyphAdvance = glyphAdvance; + + // Handle lengthAdjust="spacingAndGlyphs" by specifying per-character scale operations + if (info.pathTextLength && info.pathChunkLength) { + if (isVerticalText) { + svgChar.pathData->yScale = info.pathChunkLength / info.pathTextLength; + spacing *= svgChar.pathData->yScale; + correctedGlyphAdvance *= svgChar.pathData->yScale; + } else { + svgChar.pathData->xScale = info.pathChunkLength / info.pathTextLength; + spacing *= svgChar.pathData->xScale; + correctedGlyphAdvance *= svgChar.pathData->xScale; + } + } + + // Handle letter & word spacing on text path + float pathExtraAdvance = info.pathExtraAdvance; + info.pathExtraAdvance += spacing; + + svgChar.pathData->hidden = !info.nextPathLayoutPointAndAngle(correctedGlyphAdvance, extraAdvance, newOffset); + svgChar.drawnSeperated = true; + + info.pathExtraAdvance = pathExtraAdvance; + } + + // Apply rotation + if (info.angleValueAvailable()) + info.angle = info.angleValueNext(); + + // Apply baseline-shift + if (info.baselineShiftValueAvailable()) { + svgChar.drawnSeperated = true; + float shift = info.baselineShiftValueNext(); + + if (isVerticalText) + info.shiftx += shift; + else + info.shifty -= shift; + } + + // Take dominant-baseline / alignment-baseline into account + yOrientationShift += alignmentBaselineToShift(isVerticalText, textRenderer, font); + + svgChar.x = info.curx; + svgChar.y = info.cury; + svgChar.angle = info.angle; + + // For text paths any shift (dx/dy/baseline-shift) has to be applied after the rotation + if (!info.inPathLayout()) { + svgChar.x += info.shiftx + xOrientationShift; + svgChar.y += info.shifty + yOrientationShift; + + if (orientationAngle != 0.0f) + svgChar.angle += orientationAngle; + + if (svgChar.angle != 0.0f) + svgChar.drawnSeperated = true; + } else { + svgChar.pathData->orientationAngle = orientationAngle; + + if (isVerticalText) + svgChar.angle -= 90.0f; + + svgChar.pathData->xShift = info.shiftx + xOrientationShift; + svgChar.pathData->yShift = info.shifty + yOrientationShift; + + // Translate to glyph midpoint + if (isVerticalText) { + svgChar.pathData->xShift += info.dx; + svgChar.pathData->yShift -= glyphAdvance / 2.0f; + } else { + svgChar.pathData->xShift -= glyphAdvance / 2.0f; + svgChar.pathData->yShift += info.dy; + } + } + + // Advance to new position + if (isVerticalText) { + svgChar.drawnSeperated = true; + info.cury += glyphAdvance + spacing; + } else + info.curx += glyphAdvance + spacing; + + // Advance to next character group + for (int k = 0; k < charsConsumed; ++k) { + info.svgChars.append(svgChar); + info.processedSingleCharacter(); + svgChar.drawnSeperated = false; + svgChar.newTextChunk = false; + } + } +} + } // namespace WebCore #endif diff --git a/WebCore/rendering/SVGInlineTextBox.h b/WebCore/rendering/SVGInlineTextBox.h index c586ddd..77b6498 100644 --- a/WebCore/rendering/SVGInlineTextBox.h +++ b/WebCore/rendering/SVGInlineTextBox.h @@ -28,72 +28,57 @@ namespace WebCore { - class SVGRootInlineBox; +class SVGRootInlineBox; - struct SVGChar; - struct SVGTextDecorationInfo; +struct SVGChar; +struct SVGCharacterLayoutInfo; +struct SVGLastGlyphInfo; +struct SVGTextDecorationInfo; +struct SVGTextPaintInfo; - enum SVGTextPaintSubphase { - SVGTextPaintSubphaseBackground, - SVGTextPaintSubphaseGlyphFill, - SVGTextPaintSubphaseGlyphFillSelection, - SVGTextPaintSubphaseGlyphStroke, - SVGTextPaintSubphaseGlyphStrokeSelection, - SVGTextPaintSubphaseForeground - }; +class SVGInlineTextBox : public InlineTextBox { +public: + SVGInlineTextBox(RenderObject* obj); - struct SVGTextPaintInfo { - SVGTextPaintInfo() - : activePaintingResource(0) - , subphase(SVGTextPaintSubphaseBackground) - { - } + virtual int virtualHeight() const { return m_height; } + void setHeight(int h) { m_height = h; } - RenderSVGResource* activePaintingResource; - SVGTextPaintSubphase subphase; - }; + virtual int selectionTop() { return m_y; } + virtual int selectionHeight() { return m_height; } - class SVGInlineTextBox : public InlineTextBox { - public: - SVGInlineTextBox(RenderObject* obj); + virtual int offsetForPosition(int x, bool includePartialGlyphs = true) const; + virtual int positionForOffset(int offset) const; - virtual int virtualHeight() const { return m_height; } - void setHeight(int h) { m_height = h; } + virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty); + virtual IntRect selectionRect(int absx, int absy, int startPos, int endPos); - virtual int selectionTop(); - virtual int selectionHeight(); + // SVGs custom paint text method + void paintCharacters(RenderObject::PaintInfo&, int tx, int ty, const SVGChar&, const UChar* chars, int length, SVGTextPaintInfo&); - virtual int offsetForPosition(int x, bool includePartialGlyphs = true) const; - virtual int positionForOffset(int offset) const; + // SVGs custom paint selection method + void paintSelection(int boxStartOffset, const SVGChar&, const UChar*, int length, GraphicsContext*, RenderStyle*, const Font&); - virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, int x, int y, int tx, int ty); - virtual IntRect selectionRect(int absx, int absy, int startPos, int endPos); + // SVGs custom paint decoration method + void paintDecoration(ETextDecoration, GraphicsContext*, int tx, int ty, int width, const SVGChar&, const SVGTextDecorationInfo&); + + SVGRootInlineBox* svgRootInlineBox() const; - // SVGs custom paint text method - void paintCharacters(RenderObject::PaintInfo&, int tx, int ty, const SVGChar&, const UChar* chars, int length, SVGTextPaintInfo&); + // Helper functions shared with SVGRootInlineBox + float calculateGlyphWidth(RenderStyle* style, int offset, int extraCharsAvailable, int& charsConsumed, String& glyphName) const; + float calculateGlyphHeight(RenderStyle*, int offset, int extraCharsAvailable) const; - // SVGs custom paint selection method - void paintSelection(int boxStartOffset, const SVGChar&, const UChar*, int length, GraphicsContext*, RenderStyle*, const Font&); + FloatRect calculateGlyphBoundaries(RenderStyle*, int offset, const SVGChar&) const; + SVGChar* closestCharacterToPosition(int x, int y, int& offset) const; - // SVGs custom paint decoration method - void paintDecoration(ETextDecoration, GraphicsContext*, int tx, int ty, int width, const SVGChar&, const SVGTextDecorationInfo&); - - SVGRootInlineBox* svgRootInlineBox() const; - - // Helper functions shared with SVGRootInlineBox - float calculateGlyphWidth(RenderStyle* style, int offset, int extraCharsAvailable, int& charsConsumed, String& glyphName) const; - float calculateGlyphHeight(RenderStyle*, int offset, int extraCharsAvailable) const; - - FloatRect calculateGlyphBoundaries(RenderStyle*, int offset, const SVGChar&) const; - SVGChar* closestCharacterToPosition(int x, int y, int& offset) const; - - private: - friend class RenderSVGInlineText; - bool svgCharacterHitsPosition(int x, int y, int& offset) const; - bool chunkSelectionStartEnd(const UChar* chunk, int chunkLength, int& selectionStart, int& selectionEnd); - - int m_height; - }; + void buildLayoutInformation(SVGCharacterLayoutInfo&, SVGLastGlyphInfo&); + +private: + friend class RenderSVGInlineText; + bool svgCharacterHitsPosition(int x, int y, int& offset) const; + bool chunkSelectionStartEnd(const UChar* chunk, int chunkLength, int& selectionStart, int& selectionEnd); + + int m_height; +}; } // namespace WebCore diff --git a/WebCore/rendering/SVGRenderTreeAsText.cpp b/WebCore/rendering/SVGRenderTreeAsText.cpp index f6fbae2..8b4c563 100644 --- a/WebCore/rendering/SVGRenderTreeAsText.cpp +++ b/WebCore/rendering/SVGRenderTreeAsText.cpp @@ -64,6 +64,7 @@ #include "SVGRootInlineBox.h" #include "SVGStopElement.h" #include "SVGStyledElement.h" +#include "SVGTextLayoutUtilities.h" #include <math.h> @@ -264,12 +265,6 @@ TextStream& operator<<(TextStream& ts, const Color& c) return ts << c.name(); } -static void writeIndent(TextStream& ts, int indent) -{ - for (int i = 0; i != indent; ++i) - ts << " "; -} - // FIXME: Maybe this should be in KCanvasRenderingStyle.cpp static TextStream& operator<<(TextStream& ts, const DashArray& a) { @@ -596,44 +591,31 @@ void writeSVGResourceContainer(TextStream& ts, const RenderObject& object, int i RenderSVGResourceMasker* masker = static_cast<RenderSVGResourceMasker*>(resource); writeNameValuePair(ts, "maskUnits", masker->maskUnits()); writeNameValuePair(ts, "maskContentUnits", masker->maskContentUnits()); + ts << "\n"; #if ENABLE(FILTERS) } else if (resource->resourceType() == FilterResourceType) { RenderSVGResourceFilter* filter = static_cast<RenderSVGResourceFilter*>(resource); writeNameValuePair(ts, "filterUnits", filter->filterUnits()); writeNameValuePair(ts, "primitiveUnits", filter->primitiveUnits()); + ts << "\n"; if (OwnPtr<SVGFilterBuilder> builder = filter->buildPrimitives()) { - ts << "\n"; - const HashMap<AtomicString, RefPtr<FilterEffect> >& effects = builder->namedEffects(); - HashMap<AtomicString, RefPtr<FilterEffect> >::const_iterator end = effects.end(); - for (HashMap<AtomicString, RefPtr<FilterEffect> >::const_iterator it = effects.begin(); it != end; ++it) { - writeIndent(ts, indent); - ts << " [primitve=\"" << it->first << "\" "; - it->second->externalRepresentation(ts); - ts << "]\n"; - } - writeIndent(ts, indent); - // FIXME: Some effects don't give a representation back. So we miss some more informations - // after '[last primitive' . - // We also just dump named effects and the last effect at the moment, more effects - // without a name might be in the pipe. - ts << " [last primitive "; if (FilterEffect* lastEffect = builder->lastEffect()) - lastEffect->externalRepresentation(ts); - ts << "]"; - } + lastEffect->externalRepresentation(ts, indent + 1); + } #endif } else if (resource->resourceType() == ClipperResourceType) { RenderSVGResourceClipper* clipper = static_cast<RenderSVGResourceClipper*>(resource); writeNameValuePair(ts, "clipPathUnits", clipper->clipPathUnits()); + ts << "\n"; } else if (resource->resourceType() == MarkerResourceType) { RenderSVGResourceMarker* marker = static_cast<RenderSVGResourceMarker*>(resource); writeNameValuePair(ts, "markerUnits", marker->markerUnits()); ts << " [ref at " << marker->referencePoint() << "]"; ts << " [angle="; if (marker->angle() == -1) - ts << "auto" << "]"; + ts << "auto" << "]\n"; else - ts << marker->angle() << "]"; + ts << marker->angle() << "]\n"; } else if (resource->resourceType() == PatternResourceType) { RenderSVGResourcePattern* pattern = static_cast<RenderSVGResourcePattern*>(resource); @@ -646,6 +628,7 @@ void writeSVGResourceContainer(TextStream& ts, const RenderObject& object, int i AffineTransform transform = attributes.patternTransform(); if (!transform.isIdentity()) ts << " [patternTransform=" << transform << "]"; + ts << "\n"; } else if (resource->resourceType() == LinearGradientResourceType) { RenderSVGResourceLinearGradient* gradient = static_cast<RenderSVGResourceLinearGradient*>(resource); @@ -660,7 +643,7 @@ void writeSVGResourceContainer(TextStream& ts, const RenderObject& object, int i FloatPoint endPoint; linearGradientElement->calculateStartEndPoints(attributes, startPoint, endPoint); - ts << " [start=" << startPoint << "] [end=" << endPoint << "]"; + ts << " [start=" << startPoint << "] [end=" << endPoint << "]\n"; } else if (resource->resourceType() == RadialGradientResourceType) { RenderSVGResourceRadialGradient* gradient = static_cast<RenderSVGResourceRadialGradient*>(resource); @@ -676,10 +659,9 @@ void writeSVGResourceContainer(TextStream& ts, const RenderObject& object, int i float radius; radialGradientElement->calculateFocalCenterPointsAndRadius(attributes, focalPoint, centerPoint, radius); - ts << " [center=" << centerPoint << "] [focal=" << focalPoint << "] [radius=" << radius << "]"; - } - - ts << "\n"; + ts << " [center=" << centerPoint << "] [focal=" << focalPoint << "] [radius=" << radius << "]\n"; + } else + ts << "\n"; writeChildren(ts, object, indent); } diff --git a/WebCore/rendering/SVGRootInlineBox.cpp b/WebCore/rendering/SVGRootInlineBox.cpp index 6c99b1a..8760fe5 100644 --- a/WebCore/rendering/SVGRootInlineBox.cpp +++ b/WebCore/rendering/SVGRootInlineBox.cpp @@ -1,6 +1,4 @@ /* - * This file is part of the WebKit project. - * * Copyright (C) 2006 Oliver Hunt <ojh16@student.canterbury.ac.nz> * (C) 2006 Apple Computer Inc. * (C) 2007 Nikolas Zimmermann <zimmermann@kde.org> @@ -28,25 +26,15 @@ #if ENABLE(SVG) #include "SVGRootInlineBox.h" -#include "Editor.h" -#include "FloatConversion.h" -#include "Frame.h" #include "GraphicsContext.h" #include "RenderBlock.h" -#include "RenderSVGResource.h" #include "RenderSVGResourceFilter.h" #include "RenderSVGRoot.h" #include "SVGInlineFlowBox.h" #include "SVGInlineTextBox.h" -#include "SVGFontElement.h" -#include "SVGRenderStyleDefs.h" #include "SVGRenderSupport.h" +#include "SVGTextLayoutUtilities.h" #include "SVGTextPositioningElement.h" -#include "SVGURIReference.h" -#include "Text.h" -#include "UnicodeRange.h" - -#include <float.h> // Text chunk creation is complex and the whole process // can easily be traced by setting this variable > 0. @@ -54,217 +42,6 @@ namespace WebCore { -static inline bool isVerticalWritingMode(const SVGRenderStyle* style) -{ - return style->writingMode() == WM_TBRL || style->writingMode() == WM_TB; -} - -static inline EAlignmentBaseline dominantBaselineToShift(bool isVerticalText, const RenderObject* text, const Font& font) -{ - ASSERT(text); - - const SVGRenderStyle* style = text->style() ? text->style()->svgStyle() : 0; - ASSERT(style); - - const SVGRenderStyle* parentStyle = text->parent() && text->parent()->style() ? text->parent()->style()->svgStyle() : 0; - - EDominantBaseline baseline = style->dominantBaseline(); - if (baseline == DB_AUTO) { - if (isVerticalText) - baseline = DB_CENTRAL; - else - baseline = DB_ALPHABETIC; - } - - switch (baseline) { - case DB_USE_SCRIPT: - // TODO: The dominant-baseline and the baseline-table components are set by - // determining the predominant script of the character data content. - return AB_ALPHABETIC; - case DB_NO_CHANGE: - { - if (parentStyle) - return dominantBaselineToShift(isVerticalText, text->parent(), font); - - ASSERT_NOT_REACHED(); - return AB_AUTO; - } - case DB_RESET_SIZE: - { - if (parentStyle) - return dominantBaselineToShift(isVerticalText, text->parent(), font); - - ASSERT_NOT_REACHED(); - return AB_AUTO; - } - case DB_IDEOGRAPHIC: - return AB_IDEOGRAPHIC; - case DB_ALPHABETIC: - return AB_ALPHABETIC; - case DB_HANGING: - return AB_HANGING; - case DB_MATHEMATICAL: - return AB_MATHEMATICAL; - case DB_CENTRAL: - return AB_CENTRAL; - case DB_MIDDLE: - return AB_MIDDLE; - case DB_TEXT_AFTER_EDGE: - return AB_TEXT_AFTER_EDGE; - case DB_TEXT_BEFORE_EDGE: - return AB_TEXT_BEFORE_EDGE; - default: - ASSERT_NOT_REACHED(); - return AB_AUTO; - } -} - -static inline float alignmentBaselineToShift(bool isVerticalText, const RenderObject* text, const Font& font) -{ - ASSERT(text); - - const SVGRenderStyle* style = text->style() ? text->style()->svgStyle() : 0; - ASSERT(style); - - const SVGRenderStyle* parentStyle = text->parent() && text->parent()->style() ? text->parent()->style()->svgStyle() : 0; - - EAlignmentBaseline baseline = style->alignmentBaseline(); - if (baseline == AB_AUTO) { - if (parentStyle && style->dominantBaseline() == DB_AUTO) - baseline = dominantBaselineToShift(isVerticalText, text->parent(), font); - else - baseline = dominantBaselineToShift(isVerticalText, text, font); - - ASSERT(baseline != AB_AUTO); - } - - // Note: http://wiki.apache.org/xmlgraphics-fop/LineLayout/AlignmentHandling - switch (baseline) { - case AB_BASELINE: - { - if (parentStyle) - return dominantBaselineToShift(isVerticalText, text->parent(), font); - - return 0.0f; - } - case AB_BEFORE_EDGE: - case AB_TEXT_BEFORE_EDGE: - return font.ascent(); - case AB_MIDDLE: - return font.xHeight() / 2.0f; - case AB_CENTRAL: - // Not needed, we're taking this into account already for vertical text! - // return (font.ascent() - font.descent()) / 2.0f; - return 0.0f; - case AB_AFTER_EDGE: - case AB_TEXT_AFTER_EDGE: - case AB_IDEOGRAPHIC: - return font.descent(); - case AB_ALPHABETIC: - return 0.0f; - case AB_HANGING: - return font.ascent() * 8.0f / 10.0f; - case AB_MATHEMATICAL: - return font.ascent() / 2.0f; - default: - ASSERT_NOT_REACHED(); - return 0.0f; - } -} - -static inline float glyphOrientationToAngle(const SVGRenderStyle* svgStyle, bool isVerticalText, const UChar& character) -{ - switch (isVerticalText ? svgStyle->glyphOrientationVertical() : svgStyle->glyphOrientationHorizontal()) { - case GO_AUTO: - { - // Spec: Fullwidth ideographic and fullwidth Latin text will be set with a glyph-orientation of 0-degrees. - // Text which is not fullwidth will be set with a glyph-orientation of 90-degrees. - unsigned int unicodeRange = findCharUnicodeRange(character); - if (unicodeRange == cRangeSetLatin || unicodeRange == cRangeArabic) - return 90.0f; - - return 0.0f; - } - case GO_90DEG: - return 90.0f; - case GO_180DEG: - return 180.0f; - case GO_270DEG: - return 270.0f; - case GO_0DEG: - default: - return 0.0f; - } -} - -static inline bool glyphOrientationIsMultiplyOf180Degrees(float orientationAngle) -{ - return fabsf(fmodf(orientationAngle, 180.0f)) == 0.0f; -} - -static inline float calculateGlyphAdvanceAndShiftRespectingOrientation(bool isVerticalText, float orientationAngle, float glyphWidth, float glyphHeight, const Font& font, SVGChar& svgChar, float& xOrientationShift, float& yOrientationShift) -{ - bool orientationIsMultiplyOf180Degrees = glyphOrientationIsMultiplyOf180Degrees(orientationAngle); - - // The function is based on spec requirements: - // - // Spec: If the 'glyph-orientation-horizontal' results in an orientation angle that is not a multiple of - // of 180 degrees, then the current text position is incremented according to the vertical metrics of the glyph. - // - // Spec: If if the 'glyph-orientation-vertical' results in an orientation angle that is not a multiple of - // 180 degrees,then the current text position is incremented according to the horizontal metrics of the glyph. - - // vertical orientation handling - if (isVerticalText) { - if (orientationAngle == 0.0f) { - xOrientationShift = -glyphWidth / 2.0f; - yOrientationShift = font.ascent(); - } else if (orientationAngle == 90.0f) { - xOrientationShift = -glyphHeight; - yOrientationShift = font.descent(); - svgChar.orientationShiftY = -font.ascent(); - } else if (orientationAngle == 270.0f) { - xOrientationShift = glyphHeight; - yOrientationShift = font.descent(); - svgChar.orientationShiftX = -glyphWidth; - svgChar.orientationShiftY = -font.ascent(); - } else if (orientationAngle == 180.0f) { - yOrientationShift = font.ascent(); - svgChar.orientationShiftX = -glyphWidth / 2.0f; - svgChar.orientationShiftY = font.ascent() - font.descent(); - } - - // vertical advance calculation - if (orientationAngle != 0.0f && !orientationIsMultiplyOf180Degrees) - return glyphWidth; - - return glyphHeight; - } - - // horizontal orientation handling - if (orientationAngle == 90.0f) { - xOrientationShift = glyphWidth / 2.0f; - yOrientationShift = -font.descent(); - svgChar.orientationShiftX = -glyphWidth / 2.0f - font.descent(); - svgChar.orientationShiftY = font.descent(); - } else if (orientationAngle == 270.0f) { - xOrientationShift = -glyphWidth / 2.0f; - yOrientationShift = -font.descent(); - svgChar.orientationShiftX = -glyphWidth / 2.0f + font.descent(); - svgChar.orientationShiftY = glyphHeight; - } else if (orientationAngle == 180.0f) { - xOrientationShift = glyphWidth / 2.0f; - svgChar.orientationShiftX = -glyphWidth / 2.0f; - svgChar.orientationShiftY = font.ascent() - font.descent(); - } - - // horizontal advance calculation - if (orientationAngle != 0.0f && !orientationIsMultiplyOf180Degrees) - return glyphHeight; - - return glyphWidth; -} - static inline void startTextChunk(SVGTextChunkLayoutInfo& info) { info.chunk.boxes.clear(); @@ -294,82 +71,6 @@ RenderSVGRoot* findSVGRootObject(RenderObject* start) return toRenderSVGRoot(start); } -static inline FloatPoint topLeftPositionOfCharacterRange(Vector<SVGChar>& chars) -{ - return topLeftPositionOfCharacterRange(chars.begin(), chars.end()); -} - -FloatPoint topLeftPositionOfCharacterRange(Vector<SVGChar>::iterator it, Vector<SVGChar>::iterator end) -{ - float lowX = FLT_MAX, lowY = FLT_MAX; - for (; it != end; ++it) { - if (it->isHidden()) - continue; - - float x = (*it).x; - float y = (*it).y; - - if (x < lowX) - lowX = x; - - if (y < lowY) - lowY = y; - } - - return FloatPoint(lowX, lowY); -} - -// Helper function -static float calculateCSSKerning(RenderObject* item) -{ - const Font& font = item->style()->font(); - const SVGRenderStyle* svgStyle = item->style()->svgStyle(); - - float kerning = 0.0f; - if (CSSPrimitiveValue* primitive = static_cast<CSSPrimitiveValue*>(svgStyle->kerning())) { - kerning = primitive->getFloatValue(); - - if (primitive->primitiveType() == CSSPrimitiveValue::CSS_PERCENTAGE && font.pixelSize() > 0) - kerning = kerning / 100.0f * font.pixelSize(); - } - - return kerning; -} - -static bool applySVGKerning(SVGCharacterLayoutInfo& info, RenderObject* item, LastGlyphInfo& lastGlyph, const String& unicodeString, const String& glyphName) -{ -#if ENABLE(SVG_FONTS) - float kerning = 0.0f; - const RenderStyle* style = item->style(); - SVGFontElement* svgFont = 0; - if (style->font().isSVGFont()) - svgFont = style->font().svgFont(); - - if (lastGlyph.isValid && style->font().isSVGFont()) - kerning = svgFont->getHorizontalKerningPairForStringsAndGlyphs(lastGlyph.unicode, lastGlyph.glyphName, unicodeString, glyphName); - - if (style->font().isSVGFont()) { - lastGlyph.unicode = unicodeString; - lastGlyph.glyphName = glyphName; - lastGlyph.isValid = true; - kerning *= style->font().size() / style->font().primaryFont()->unitsPerEm(); - } else - lastGlyph.isValid = false; - - if (kerning != 0.0f) { - info.curx -= kerning; - return true; - } -#else - UNUSED_PARAM(info); - UNUSED_PARAM(item); - UNUSED_PARAM(lastGlyph); - UNUSED_PARAM(unicodeString); - UNUSED_PARAM(glyphName); -#endif - return false; -} - // Helper class for paint() struct SVGRootInlineBoxPaintWalker { SVGRootInlineBoxPaintWalker(SVGRootInlineBox* rootBox, RenderSVGResourceFilter* rootFilter, RenderObject::PaintInfo paintInfo, int tx, int ty) @@ -744,7 +445,7 @@ void SVGRootInlineBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty) paintInfo.context->restore(); } -int SVGRootInlineBox::placeBoxesHorizontally(int, int& leftPosition, int& rightPosition, bool&) +int SVGRootInlineBox::placeBoxesHorizontally(int, int& leftPosition, int& rightPosition, bool&, GlyphOverflowAndFallbackFontsMap&) { // Remove any offsets caused by RTL text layout leftPosition = 0; @@ -752,54 +453,12 @@ int SVGRootInlineBox::placeBoxesHorizontally(int, int& leftPosition, int& rightP return 0; } -int SVGRootInlineBox::verticallyAlignBoxes(int) +int SVGRootInlineBox::verticallyAlignBoxes(int, GlyphOverflowAndFallbackFontsMap&) { // height is set by layoutInlineBoxes. return height(); } -float cummulatedWidthOfInlineBoxCharacterRange(SVGInlineBoxCharacterRange& range) -{ - ASSERT(!range.isOpen()); - ASSERT(range.isClosed()); - ASSERT(range.box->isInlineTextBox()); - - InlineTextBox* textBox = static_cast<InlineTextBox*>(range.box); - RenderText* text = textBox->textRenderer(); - RenderStyle* style = text->style(); - - return style->font().floatWidth(svgTextRunForInlineTextBox(text->characters() + textBox->start() + range.startOffset, range.endOffset - range.startOffset, style, textBox, 0)); -} - -float cummulatedHeightOfInlineBoxCharacterRange(SVGInlineBoxCharacterRange& range) -{ - ASSERT(!range.isOpen()); - ASSERT(range.isClosed()); - ASSERT(range.box->isInlineTextBox()); - - InlineTextBox* textBox = static_cast<InlineTextBox*>(range.box); - RenderText* text = textBox->textRenderer(); - const Font& font = text->style()->font(); - - return (range.endOffset - range.startOffset) * (font.ascent() + font.descent()); -} - -TextRun svgTextRunForInlineTextBox(const UChar* c, int len, RenderStyle* style, const InlineTextBox* textBox, float xPos) -{ - ASSERT(textBox); - ASSERT(style); - - TextRun run(c, len, false, static_cast<int>(xPos), textBox->toAdd(), textBox->direction() == RTL, textBox->m_dirOverride || style->visuallyOrdered()); - -#if ENABLE(SVG_FONTS) - run.setReferencingRenderObject(textBox->textRenderer()->parent()); -#endif - - // We handle letter & word spacing ourselves - run.disableSpacing(); - return run; -} - static float cummulatedWidthOrHeightOfTextChunk(SVGTextChunk& chunk, bool calcWidthOnly) { float length = 0.0f; @@ -948,8 +607,8 @@ static float calculateTextLengthCorrectionForTextChunk(SVGTextChunk& chunk, ELen float computedWidth = cummulatedWidthOfTextChunk(chunk); float computedHeight = cummulatedHeightOfTextChunk(chunk); - if ((computedWidth <= 0.0f && !chunk.isVerticalText) || - (computedHeight <= 0.0f && chunk.isVerticalText)) + if ((computedWidth <= 0.0f && !chunk.isVerticalText) + || (computedHeight <= 0.0f && chunk.isVerticalText)) return 0.0f; if (chunk.isVerticalText) @@ -1025,7 +684,7 @@ void SVGRootInlineBox::computePerCharacterLayoutInformation() // Finally the top left position of our box is known. // Propogate this knownledge to our RenderSVGText parent. - FloatPoint topLeft = topLeftPositionOfCharacterRange(m_svgChars); + FloatPoint topLeft = topLeftPositionOfCharacterRange(m_svgChars.begin(), m_svgChars.end()); block()->setLocation((int) floorf(topLeft.x()), (int) floorf(topLeft.y())); // Layout all InlineText/Flow boxes @@ -1045,11 +704,11 @@ void SVGRootInlineBox::buildLayoutInformation(InlineFlowBox* start, SVGCharacter info.addLayoutInformation(positioningElement); } - LastGlyphInfo lastGlyph; + SVGLastGlyphInfo lastGlyph; for (InlineBox* curr = start->firstChild(); curr; curr = curr->nextOnLine()) { if (curr->renderer()->isText()) - buildLayoutInformationForTextBox(info, static_cast<InlineTextBox*>(curr), lastGlyph); + static_cast<SVGInlineTextBox*>(curr)->buildLayoutInformation(info, lastGlyph); else { ASSERT(curr->isInlineFlowBox()); InlineFlowBox* flowBox = static_cast<InlineFlowBox*>(curr); @@ -1236,235 +895,12 @@ void SVGRootInlineBox::layoutInlineBoxes(InlineFlowBox* start, Vector<SVGChar>:: start->setWidth(highX - lowX); static_cast<SVGRootInlineBox*>(start)->setHeight(highY - lowY); - start->computeVerticalOverflow(top, bottom, true); + GlyphOverflowAndFallbackFontsMap textBoxDataMap; + start->computeVerticalOverflow(top, bottom, true, textBoxDataMap); static_cast<SVGRootInlineBox*>(start)->setLineTopBottomPositions(top, bottom); } } -void SVGRootInlineBox::buildLayoutInformationForTextBox(SVGCharacterLayoutInfo& info, InlineTextBox* textBox, LastGlyphInfo& lastGlyph) -{ - RenderText* text = textBox->textRenderer(); - ASSERT(text); - - RenderStyle* style = text->style(textBox->isFirstLineStyle()); - ASSERT(style); - - const Font& font = style->font(); - SVGInlineTextBox* svgTextBox = static_cast<SVGInlineTextBox*>(textBox); - - unsigned length = textBox->len(); - - const SVGRenderStyle* svgStyle = style->svgStyle(); - bool isVerticalText = isVerticalWritingMode(svgStyle); - - int charsConsumed = 0; - for (unsigned i = 0; i < length; i += charsConsumed) { - SVGChar svgChar; - - if (info.inPathLayout()) - svgChar.pathData = SVGCharOnPath::create(); - - float glyphWidth = 0.0f; - float glyphHeight = 0.0f; - - int extraCharsAvailable = length - i - 1; - - String unicodeStr; - String glyphName; - if (textBox->direction() == RTL) { - glyphWidth = svgTextBox->calculateGlyphWidth(style, textBox->end() - i, extraCharsAvailable, charsConsumed, glyphName); - glyphHeight = svgTextBox->calculateGlyphHeight(style, textBox->end() - i, extraCharsAvailable); - unicodeStr = String(textBox->textRenderer()->text()->characters() + textBox->end() - i, charsConsumed); - } else { - glyphWidth = svgTextBox->calculateGlyphWidth(style, textBox->start() + i, extraCharsAvailable, charsConsumed, glyphName); - glyphHeight = svgTextBox->calculateGlyphHeight(style, textBox->start() + i, extraCharsAvailable); - unicodeStr = String(textBox->textRenderer()->text()->characters() + textBox->start() + i, charsConsumed); - } - - bool assignedX = false; - bool assignedY = false; - - if (info.xValueAvailable() && (!info.inPathLayout() || (info.inPathLayout() && !isVerticalText))) { - if (!isVerticalText) - svgChar.newTextChunk = true; - - assignedX = true; - svgChar.drawnSeperated = true; - info.curx = info.xValueNext(); - } - - if (info.yValueAvailable() && (!info.inPathLayout() || (info.inPathLayout() && isVerticalText))) { - if (isVerticalText) - svgChar.newTextChunk = true; - - assignedY = true; - svgChar.drawnSeperated = true; - info.cury = info.yValueNext(); - } - - float dx = 0.0f; - float dy = 0.0f; - - // Apply x-axis shift - if (info.dxValueAvailable()) { - svgChar.drawnSeperated = true; - - dx = info.dxValueNext(); - info.dx += dx; - - if (!info.inPathLayout()) - info.curx += dx; - } - - // Apply y-axis shift - if (info.dyValueAvailable()) { - svgChar.drawnSeperated = true; - - dy = info.dyValueNext(); - info.dy += dy; - - if (!info.inPathLayout()) - info.cury += dy; - } - - // Take letter & word spacing and kerning into account - float spacing = font.letterSpacing() + calculateCSSKerning(textBox->renderer()->node()->renderer()); - - const UChar* currentCharacter = text->characters() + (textBox->direction() == RTL ? textBox->end() - i : textBox->start() + i); - const UChar* lastCharacter = 0; - - if (textBox->direction() == RTL) { - if (i < textBox->end()) - lastCharacter = text->characters() + textBox->end() - i + 1; - } else { - if (i > 0) - lastCharacter = text->characters() + textBox->start() + i - 1; - } - - // FIXME: SVG Kerning doesn't get applied on texts on path. - bool appliedSVGKerning = applySVGKerning(info, textBox->renderer()->node()->renderer(), lastGlyph, unicodeStr, glyphName); - if (info.nextDrawnSeperated || spacing != 0.0f || appliedSVGKerning) { - info.nextDrawnSeperated = false; - svgChar.drawnSeperated = true; - } - - if (currentCharacter && Font::treatAsSpace(*currentCharacter) && lastCharacter && !Font::treatAsSpace(*lastCharacter)) { - spacing += font.wordSpacing(); - - if (spacing != 0.0f && !info.inPathLayout()) - info.nextDrawnSeperated = true; - } - - float orientationAngle = glyphOrientationToAngle(svgStyle, isVerticalText, *currentCharacter); - - float xOrientationShift = 0.0f; - float yOrientationShift = 0.0f; - float glyphAdvance = calculateGlyphAdvanceAndShiftRespectingOrientation(isVerticalText, orientationAngle, glyphWidth, glyphHeight, - font, svgChar, xOrientationShift, yOrientationShift); - - // Handle textPath layout mode - if (info.inPathLayout()) { - float extraAdvance = isVerticalText ? dy : dx; - float newOffset = FLT_MIN; - - if (assignedX && !isVerticalText) - newOffset = info.curx; - else if (assignedY && isVerticalText) - newOffset = info.cury; - - float correctedGlyphAdvance = glyphAdvance; - - // Handle lengthAdjust="spacingAndGlyphs" by specifying per-character scale operations - if (info.pathTextLength > 0.0f && info.pathChunkLength > 0.0f) { - if (isVerticalText) { - svgChar.pathData->yScale = info.pathChunkLength / info.pathTextLength; - spacing *= svgChar.pathData->yScale; - correctedGlyphAdvance *= svgChar.pathData->yScale; - } else { - svgChar.pathData->xScale = info.pathChunkLength / info.pathTextLength; - spacing *= svgChar.pathData->xScale; - correctedGlyphAdvance *= svgChar.pathData->xScale; - } - } - - // Handle letter & word spacing on text path - float pathExtraAdvance = info.pathExtraAdvance; - info.pathExtraAdvance += spacing; - - svgChar.pathData->hidden = !info.nextPathLayoutPointAndAngle(correctedGlyphAdvance, extraAdvance, newOffset); - svgChar.drawnSeperated = true; - - info.pathExtraAdvance = pathExtraAdvance; - } - - // Apply rotation - if (info.angleValueAvailable()) - info.angle = info.angleValueNext(); - - // Apply baseline-shift - if (info.baselineShiftValueAvailable()) { - svgChar.drawnSeperated = true; - float shift = info.baselineShiftValueNext(); - - if (isVerticalText) - info.shiftx += shift; - else - info.shifty -= shift; - } - - // Take dominant-baseline / alignment-baseline into account - yOrientationShift += alignmentBaselineToShift(isVerticalText, text, font); - - svgChar.x = info.curx; - svgChar.y = info.cury; - svgChar.angle = info.angle; - - // For text paths any shift (dx/dy/baseline-shift) has to be applied after the rotation - if (!info.inPathLayout()) { - svgChar.x += info.shiftx + xOrientationShift; - svgChar.y += info.shifty + yOrientationShift; - - if (orientationAngle != 0.0f) - svgChar.angle += orientationAngle; - - if (svgChar.angle != 0.0f) - svgChar.drawnSeperated = true; - } else { - svgChar.pathData->orientationAngle = orientationAngle; - - if (isVerticalText) - svgChar.angle -= 90.0f; - - svgChar.pathData->xShift = info.shiftx + xOrientationShift; - svgChar.pathData->yShift = info.shifty + yOrientationShift; - - // Translate to glyph midpoint - if (isVerticalText) { - svgChar.pathData->xShift += info.dx; - svgChar.pathData->yShift -= glyphAdvance / 2.0f; - } else { - svgChar.pathData->xShift -= glyphAdvance / 2.0f; - svgChar.pathData->yShift += info.dy; - } - } - - // Advance to new position - if (isVerticalText) { - svgChar.drawnSeperated = true; - info.cury += glyphAdvance + spacing; - } else - info.curx += glyphAdvance + spacing; - - // Advance to next character group - for (int k = 0; k < charsConsumed; ++k) { - info.svgChars.append(svgChar); - info.processedSingleCharacter(); - svgChar.drawnSeperated = false; - svgChar.newTextChunk = false; - } - } -} - void SVGRootInlineBox::buildTextChunks(Vector<SVGChar>& svgChars, Vector<SVGTextChunk>& svgTextChunks, InlineFlowBox* start) { SVGTextChunkLayoutInfo info(svgTextChunks); @@ -1524,7 +960,7 @@ void SVGRootInlineBox::buildTextChunks(Vector<SVGChar>& svgChars, InlineFlowBox* SVGInlineBoxCharacterRange& range = info.chunk.boxes.last(); if (range.isOpen()) { range.box = curr; - range.startOffset = (i == 0 ? 0 : i - 1); + range.startOffset = i == 0 ? 0 : i - 1; #if DEBUG_CHUNK_BUILDING > 1 fprintf(stderr, " | -> Range is open! box=%p, startOffset=%i\n", range.box, range.startOffset); @@ -1662,11 +1098,6 @@ void SVGRootInlineBox::buildTextChunks(Vector<SVGChar>& svgChars, InlineFlowBox* #endif } -const Vector<SVGTextChunk>& SVGRootInlineBox::svgTextChunks() const -{ - return m_svgTextChunks; -} - void SVGRootInlineBox::layoutTextChunks() { Vector<SVGTextChunk>::iterator it = m_svgTextChunks.begin(); @@ -1686,7 +1117,8 @@ void SVGRootInlineBox::layoutTextChunks() unsigned int i = 0; for (; boxIt != boxEnd; ++boxIt) { - SVGInlineBoxCharacterRange& range = *boxIt; i++; + SVGInlineBoxCharacterRange& range = *boxIt; + ++i; fprintf(stderr, " -> RANGE %i STARTOFFSET: %i, ENDOFFSET: %i, BOX: %p\n", i, range.startOffset, range.endOffset, range.box); } } diff --git a/WebCore/rendering/SVGRootInlineBox.h b/WebCore/rendering/SVGRootInlineBox.h index 73c88a1..c3e1028 100644 --- a/WebCore/rendering/SVGRootInlineBox.h +++ b/WebCore/rendering/SVGRootInlineBox.h @@ -29,22 +29,15 @@ #include "RootInlineBox.h" #include "SVGCharacterData.h" #include "SVGCharacterLayoutInfo.h" -#include "SVGTextChunkLayoutInfo.h" #include "SVGRenderSupport.h" +#include "SVGTextChunkLayoutInfo.h" namespace WebCore { class InlineTextBox; class RenderSVGRoot; class SVGInlineTextBox; - -struct LastGlyphInfo { - LastGlyphInfo() : isValid(false) { } - - String unicode; - String glyphName; - bool isValid; -}; +struct SVGLastGlyphInfo; class SVGRootInlineBox : public RootInlineBox, protected SVGRenderBase { public: @@ -61,8 +54,8 @@ public: virtual void paint(RenderObject::PaintInfo&, int tx, int ty); - virtual int placeBoxesHorizontally(int x, int& leftPosition, int& rightPosition, bool& needsWordSpacing); - virtual int verticallyAlignBoxes(int heightOfBlock); + virtual int placeBoxesHorizontally(int x, int& leftPosition, int& rightPosition, bool& needsWordSpacing, GlyphOverflowAndFallbackFontsMap&); + virtual int verticallyAlignBoxes(int heightOfBlock, GlyphOverflowAndFallbackFontsMap&); virtual void computePerCharacterLayoutInformation(); @@ -70,7 +63,7 @@ public: virtual FloatRect repaintRectInLocalCoordinates() const { return FloatRect(); } // Used by SVGInlineTextBox - const Vector<SVGTextChunk>& svgTextChunks() const; + const Vector<SVGTextChunk>& svgTextChunks() const { return m_svgTextChunks; } void walkTextChunks(SVGTextChunkWalkerBase*, const SVGInlineTextBox* textBox = 0); @@ -81,7 +74,6 @@ private: void layoutInlineBoxes(InlineFlowBox* start, Vector<SVGChar>::iterator& it, int& minX, int& maxX, int& minY, int& maxY); void buildLayoutInformation(InlineFlowBox* start, SVGCharacterLayoutInfo&); - void buildLayoutInformationForTextBox(SVGCharacterLayoutInfo&, InlineTextBox*, LastGlyphInfo&); void buildTextChunks(Vector<SVGChar>&, Vector<SVGTextChunk>&, InlineFlowBox* start); void buildTextChunks(Vector<SVGChar>&, InlineFlowBox* start, SVGTextChunkLayoutInfo&); @@ -96,11 +88,6 @@ private: }; // Shared with SVGRenderTreeAsText / SVGInlineTextBox -TextRun svgTextRunForInlineTextBox(const UChar*, int len, RenderStyle* style, const InlineTextBox* textBox, float xPos); -FloatPoint topLeftPositionOfCharacterRange(Vector<SVGChar>::iterator start, Vector<SVGChar>::iterator end); -float cummulatedWidthOfInlineBoxCharacterRange(SVGInlineBoxCharacterRange& range); -float cummulatedHeightOfInlineBoxCharacterRange(SVGInlineBoxCharacterRange& range); - RenderSVGRoot* findSVGRootObject(RenderObject* start); } // namespace WebCore diff --git a/WebCore/rendering/SVGTextLayoutUtilities.cpp b/WebCore/rendering/SVGTextLayoutUtilities.cpp new file mode 100644 index 0000000..39705e9 --- /dev/null +++ b/WebCore/rendering/SVGTextLayoutUtilities.cpp @@ -0,0 +1,374 @@ +/* + Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org> + Copyright (C) Research In Motion Limited 2010. 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 "SVGTextLayoutUtilities.h" + +#if ENABLE(SVG) +#include "FloatPoint.h" +#include "InlineTextBox.h" +#include "RenderObject.h" +#include "SVGCharacterData.h" +#include "SVGCharacterLayoutInfo.h" +#include "SVGFontElement.h" +#include "SVGRenderStyle.h" +#include "SVGTextChunkLayoutInfo.h" +#include "TextRun.h" +#include "UnicodeRange.h" + +#include <float.h> + +namespace WebCore { + +bool isVerticalWritingMode(const SVGRenderStyle* style) +{ + return style->writingMode() == WM_TBRL || style->writingMode() == WM_TB; +} + +static inline EAlignmentBaseline dominantBaselineToShift(bool isVerticalText, const RenderObject* text, const Font& font) +{ + ASSERT(text); + + const SVGRenderStyle* style = text->style() ? text->style()->svgStyle() : 0; + ASSERT(style); + + const SVGRenderStyle* parentStyle = text->parent() && text->parent()->style() ? text->parent()->style()->svgStyle() : 0; + + EDominantBaseline baseline = style->dominantBaseline(); + if (baseline == DB_AUTO) { + if (isVerticalText) + baseline = DB_CENTRAL; + else + baseline = DB_ALPHABETIC; + } + + switch (baseline) { + case DB_USE_SCRIPT: + // TODO: The dominant-baseline and the baseline-table components are set by + // determining the predominant script of the character data content. + return AB_ALPHABETIC; + case DB_NO_CHANGE: + { + if (parentStyle) + return dominantBaselineToShift(isVerticalText, text->parent(), font); + + ASSERT_NOT_REACHED(); + return AB_AUTO; + } + case DB_RESET_SIZE: + { + if (parentStyle) + return dominantBaselineToShift(isVerticalText, text->parent(), font); + + ASSERT_NOT_REACHED(); + return AB_AUTO; + } + case DB_IDEOGRAPHIC: + return AB_IDEOGRAPHIC; + case DB_ALPHABETIC: + return AB_ALPHABETIC; + case DB_HANGING: + return AB_HANGING; + case DB_MATHEMATICAL: + return AB_MATHEMATICAL; + case DB_CENTRAL: + return AB_CENTRAL; + case DB_MIDDLE: + return AB_MIDDLE; + case DB_TEXT_AFTER_EDGE: + return AB_TEXT_AFTER_EDGE; + case DB_TEXT_BEFORE_EDGE: + return AB_TEXT_BEFORE_EDGE; + default: + ASSERT_NOT_REACHED(); + return AB_AUTO; + } +} + +float alignmentBaselineToShift(bool isVerticalText, const RenderObject* text, const Font& font) +{ + ASSERT(text); + + const SVGRenderStyle* style = text->style() ? text->style()->svgStyle() : 0; + ASSERT(style); + + const SVGRenderStyle* parentStyle = text->parent() && text->parent()->style() ? text->parent()->style()->svgStyle() : 0; + + EAlignmentBaseline baseline = style->alignmentBaseline(); + if (baseline == AB_AUTO) { + if (parentStyle && style->dominantBaseline() == DB_AUTO) + baseline = dominantBaselineToShift(isVerticalText, text->parent(), font); + else + baseline = dominantBaselineToShift(isVerticalText, text, font); + + ASSERT(baseline != AB_AUTO); + } + + // Note: http://wiki.apache.org/xmlgraphics-fop/LineLayout/AlignmentHandling + switch (baseline) { + case AB_BASELINE: + { + if (parentStyle) + return dominantBaselineToShift(isVerticalText, text->parent(), font); + + return 0.0f; + } + case AB_BEFORE_EDGE: + case AB_TEXT_BEFORE_EDGE: + return font.ascent(); + case AB_MIDDLE: + return font.xHeight() / 2.0f; + case AB_CENTRAL: + // Not needed, we're taking this into account already for vertical text! + // return (font.ascent() - font.descent()) / 2.0f; + return 0.0f; + case AB_AFTER_EDGE: + case AB_TEXT_AFTER_EDGE: + case AB_IDEOGRAPHIC: + return font.descent(); + case AB_ALPHABETIC: + return 0.0f; + case AB_HANGING: + return font.ascent() * 8.0f / 10.0f; + case AB_MATHEMATICAL: + return font.ascent() / 2.0f; + default: + ASSERT_NOT_REACHED(); + return 0.0f; + } +} + +float glyphOrientationToAngle(const SVGRenderStyle* svgStyle, bool isVerticalText, const UChar& character) +{ + switch (isVerticalText ? svgStyle->glyphOrientationVertical() : svgStyle->glyphOrientationHorizontal()) { + case GO_AUTO: + { + // Spec: Fullwidth ideographic and fullwidth Latin text will be set with a glyph-orientation of 0-degrees. + // Text which is not fullwidth will be set with a glyph-orientation of 90-degrees. + unsigned int unicodeRange = findCharUnicodeRange(character); + if (unicodeRange == cRangeSetLatin || unicodeRange == cRangeArabic) + return 90.0f; + + return 0.0f; + } + case GO_90DEG: + return 90.0f; + case GO_180DEG: + return 180.0f; + case GO_270DEG: + return 270.0f; + case GO_0DEG: + default: + return 0.0f; + } +} + +static inline bool glyphOrientationIsMultiplyOf180Degrees(float orientationAngle) +{ + return fabsf(fmodf(orientationAngle, 180.0f)) == 0.0f; +} + +float applyGlyphAdvanceAndShiftRespectingOrientation(bool isVerticalText, float orientationAngle, float glyphWidth, float glyphHeight, const Font& font, SVGChar& svgChar, float& xOrientationShift, float& yOrientationShift) +{ + bool orientationIsMultiplyOf180Degrees = glyphOrientationIsMultiplyOf180Degrees(orientationAngle); + + // The function is based on spec requirements: + // + // Spec: If the 'glyph-orientation-horizontal' results in an orientation angle that is not a multiple of + // of 180 degrees, then the current text position is incremented according to the vertical metrics of the glyph. + // + // Spec: If if the 'glyph-orientation-vertical' results in an orientation angle that is not a multiple of + // 180 degrees,then the current text position is incremented according to the horizontal metrics of the glyph. + + // vertical orientation handling + if (isVerticalText) { + if (orientationAngle == 0.0f) { + xOrientationShift = -glyphWidth / 2.0f; + yOrientationShift = font.ascent(); + } else if (orientationAngle == 90.0f) { + xOrientationShift = -glyphHeight; + yOrientationShift = font.descent(); + svgChar.orientationShiftY = -font.ascent(); + } else if (orientationAngle == 270.0f) { + xOrientationShift = glyphHeight; + yOrientationShift = font.descent(); + svgChar.orientationShiftX = -glyphWidth; + svgChar.orientationShiftY = -font.ascent(); + } else if (orientationAngle == 180.0f) { + yOrientationShift = font.ascent(); + svgChar.orientationShiftX = -glyphWidth / 2.0f; + svgChar.orientationShiftY = font.ascent() - font.descent(); + } + + // vertical advance calculation + if (orientationAngle != 0.0f && !orientationIsMultiplyOf180Degrees) + return glyphWidth; + + return glyphHeight; + } + + // horizontal orientation handling + if (orientationAngle == 90.0f) { + xOrientationShift = glyphWidth / 2.0f; + yOrientationShift = -font.descent(); + svgChar.orientationShiftX = -glyphWidth / 2.0f - font.descent(); + svgChar.orientationShiftY = font.descent(); + } else if (orientationAngle == 270.0f) { + xOrientationShift = -glyphWidth / 2.0f; + yOrientationShift = -font.descent(); + svgChar.orientationShiftX = -glyphWidth / 2.0f + font.descent(); + svgChar.orientationShiftY = glyphHeight; + } else if (orientationAngle == 180.0f) { + xOrientationShift = glyphWidth / 2.0f; + svgChar.orientationShiftX = -glyphWidth / 2.0f; + svgChar.orientationShiftY = font.ascent() - font.descent(); + } + + // horizontal advance calculation + if (orientationAngle != 0.0f && !orientationIsMultiplyOf180Degrees) + return glyphHeight; + + return glyphWidth; +} + +FloatPoint topLeftPositionOfCharacterRange(Vector<SVGChar>::iterator it, Vector<SVGChar>::iterator end) +{ + float lowX = FLT_MAX, lowY = FLT_MAX; + for (; it != end; ++it) { + if (it->isHidden()) + continue; + + float x = (*it).x; + float y = (*it).y; + + if (x < lowX) + lowX = x; + + if (y < lowY) + lowY = y; + } + + return FloatPoint(lowX, lowY); +} + +float cummulatedWidthOfInlineBoxCharacterRange(SVGInlineBoxCharacterRange& range) +{ + ASSERT(!range.isOpen()); + ASSERT(range.isClosed()); + ASSERT(range.box->isInlineTextBox()); + + InlineTextBox* textBox = static_cast<InlineTextBox*>(range.box); + RenderText* text = textBox->textRenderer(); + RenderStyle* style = text->style(); + + return style->font().floatWidth(svgTextRunForInlineTextBox(text->characters() + textBox->start() + range.startOffset, range.endOffset - range.startOffset, style, textBox, 0)); +} + +float cummulatedHeightOfInlineBoxCharacterRange(SVGInlineBoxCharacterRange& range) +{ + ASSERT(!range.isOpen()); + ASSERT(range.isClosed()); + ASSERT(range.box->isInlineTextBox()); + + InlineTextBox* textBox = static_cast<InlineTextBox*>(range.box); + RenderText* text = textBox->textRenderer(); + const Font& font = text->style()->font(); + + return (range.endOffset - range.startOffset) * (font.ascent() + font.descent()); +} + +TextRun svgTextRunForInlineTextBox(const UChar* characters, int length, const RenderStyle* style, const InlineTextBox* textBox, float xPosition) +{ + ASSERT(textBox); + ASSERT(style); + + TextRun run(characters, length, false, static_cast<int>(xPosition), textBox->toAdd(), textBox->direction() == RTL, textBox->m_dirOverride || style->visuallyOrdered()); + +#if ENABLE(SVG_FONTS) + run.setReferencingRenderObject(textBox->textRenderer()->parent()); +#endif + + // We handle letter & word spacing ourselves + run.disableSpacing(); + return run; +} + +float calculateCSSKerning(const RenderStyle* style) +{ + const Font& font = style->font(); + const SVGRenderStyle* svgStyle = style->svgStyle(); + + float kerning = 0.0f; + if (CSSPrimitiveValue* primitive = static_cast<CSSPrimitiveValue*>(svgStyle->kerning())) { + kerning = primitive->getFloatValue(); + + if (primitive->primitiveType() == CSSPrimitiveValue::CSS_PERCENTAGE && font.pixelSize()) + kerning = kerning / 100.0f * font.pixelSize(); + } + + return kerning; +} + +bool applySVGKerning(SVGCharacterLayoutInfo& info, const RenderStyle* style, SVGLastGlyphInfo& lastGlyph, const String& unicodeString, const String& glyphName, bool isVerticalText) +{ +#if ENABLE(SVG_FONTS) + float kerning = 0.0f; + + const Font& font = style->font(); + if (!font.isSVGFont()) { + lastGlyph.isValid = false; + return false; + } + + SVGFontElement* svgFont = font.svgFont(); + ASSERT(svgFont); + + if (lastGlyph.isValid) { + if (isVerticalText) + kerning = svgFont->verticalKerningForPairOfStringsAndGlyphs(lastGlyph.unicode, lastGlyph.glyphName, unicodeString, glyphName); + else + kerning = svgFont->horizontalKerningForPairOfStringsAndGlyphs(lastGlyph.unicode, lastGlyph.glyphName, unicodeString, glyphName); + } + + lastGlyph.unicode = unicodeString; + lastGlyph.glyphName = glyphName; + lastGlyph.isValid = true; + kerning *= style->font().size() / style->font().primaryFont()->unitsPerEm(); + + if (kerning != 0.0f) { + if (isVerticalText) + info.cury -= kerning; + else + info.curx -= kerning; + return true; + } +#else + UNUSED_PARAM(info); + UNUSED_PARAM(item); + UNUSED_PARAM(lastGlyph); + UNUSED_PARAM(unicodeString); + UNUSED_PARAM(glyphName); +#endif + return false; +} + +} + +#endif diff --git a/WebCore/rendering/SVGTextLayoutUtilities.h b/WebCore/rendering/SVGTextLayoutUtilities.h new file mode 100644 index 0000000..196a09c --- /dev/null +++ b/WebCore/rendering/SVGTextLayoutUtilities.h @@ -0,0 +1,90 @@ +/* + Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org> + Copyright (C) Research In Motion Limited 2010. 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. +*/ + +#ifndef SVGTextLayoutUtilities_h +#define SVGTextLayoutUtilities_h + +#if ENABLE(SVG) +#include <wtf/Vector.h> +#include <wtf/text/WTFString.h> + +namespace WebCore { + +class FloatPoint; +class Font; +class InlineTextBox; +class RenderObject; +class RenderStyle; +class RenderSVGResource; +class SVGRenderStyle; +class TextRun; + +struct SVGChar; +struct SVGCharacterLayoutInfo; +struct SVGInlineBoxCharacterRange; + +enum SVGTextPaintSubphase { + SVGTextPaintSubphaseBackground, + SVGTextPaintSubphaseGlyphFill, + SVGTextPaintSubphaseGlyphFillSelection, + SVGTextPaintSubphaseGlyphStroke, + SVGTextPaintSubphaseGlyphStrokeSelection, + SVGTextPaintSubphaseForeground +}; + +struct SVGTextPaintInfo { + SVGTextPaintInfo() + : activePaintingResource(0) + , subphase(SVGTextPaintSubphaseBackground) + { + } + + RenderSVGResource* activePaintingResource; + SVGTextPaintSubphase subphase; +}; + +struct SVGLastGlyphInfo { + SVGLastGlyphInfo() + : isValid(false) + { + } + + bool isValid; + String unicode; + String glyphName; +}; + +bool isVerticalWritingMode(const SVGRenderStyle*); +float alignmentBaselineToShift(bool isVerticalText, const RenderObject* text, const Font&); +float glyphOrientationToAngle(const SVGRenderStyle*, bool isVerticalText, const UChar&); +float applyGlyphAdvanceAndShiftRespectingOrientation(bool isVerticalText, float orientationAngle, float glyphWidth, float glyphHeight, const Font&, + SVGChar&, float& xOrientationShift, float& yOrientationShift); +FloatPoint topLeftPositionOfCharacterRange(Vector<SVGChar>::iterator start, Vector<SVGChar>::iterator end); +float cummulatedWidthOfInlineBoxCharacterRange(SVGInlineBoxCharacterRange&); +float cummulatedHeightOfInlineBoxCharacterRange(SVGInlineBoxCharacterRange&); +TextRun svgTextRunForInlineTextBox(const UChar*, int length, const RenderStyle*, const InlineTextBox*, float xPos); + +float calculateCSSKerning(const RenderStyle*); +bool applySVGKerning(SVGCharacterLayoutInfo&, const RenderStyle*, SVGLastGlyphInfo&, const String& unicodeString, const String& glyphName, bool isVerticalText); + +} + +#endif +#endif diff --git a/WebCore/rendering/style/FillLayer.cpp b/WebCore/rendering/style/FillLayer.cpp index 597e919..59f3bb2 100644 --- a/WebCore/rendering/style/FillLayer.cpp +++ b/WebCore/rendering/style/FillLayer.cpp @@ -25,7 +25,8 @@ namespace WebCore { FillLayer::FillLayer(EFillLayerType type) - : m_image(FillLayer::initialFillImage(type)) + : m_next(0) + , m_image(FillLayer::initialFillImage(type)) , m_xPosition(FillLayer::initialFillXPosition(type)) , m_yPosition(FillLayer::initialFillYPosition(type)) , m_attachment(FillLayer::initialFillAttachment(type)) @@ -46,12 +47,12 @@ FillLayer::FillLayer(EFillLayerType type) , m_yPosSet(false) , m_compositeSet(type == MaskFillLayer) , m_type(type) - , m_next(0) { } FillLayer::FillLayer(const FillLayer& o) - : m_image(o.m_image) + : m_next(o.m_next ? new FillLayer(*o.m_next) : 0) + , m_image(o.m_image) , m_xPosition(o.m_xPosition) , m_yPosition(o.m_yPosition) , m_attachment(o.m_attachment) @@ -72,7 +73,6 @@ FillLayer::FillLayer(const FillLayer& o) , m_yPosSet(o.m_yPosSet) , m_compositeSet(o.m_compositeSet) , m_type(o.m_type) - , m_next(o.m_next ? new FillLayer(*o.m_next) : 0) { } diff --git a/WebCore/rendering/style/FillLayer.h b/WebCore/rendering/style/FillLayer.h index eb21ec3..49fb294 100644 --- a/WebCore/rendering/style/FillLayer.h +++ b/WebCore/rendering/style/FillLayer.h @@ -166,6 +166,8 @@ private: FillLayer() { } + FillLayer* m_next; + RefPtr<StyleImage> m_image; Length m_xPosition; @@ -192,8 +194,6 @@ private: bool m_compositeSet : 1; unsigned m_type : 1; // EFillLayerType - - FillLayer* m_next; }; } // namespace WebCore diff --git a/WebCore/rendering/style/RenderStyle.cpp b/WebCore/rendering/style/RenderStyle.cpp index f3b3f0c..7ef580f 100644 --- a/WebCore/rendering/style/RenderStyle.cpp +++ b/WebCore/rendering/style/RenderStyle.cpp @@ -379,6 +379,8 @@ StyleDifference RenderStyle::diff(const RenderStyle* other, unsigned& changedCon if (rareInheritedData.get() != other->rareInheritedData.get()) { if (rareInheritedData->highlight != other->rareInheritedData->highlight || + rareInheritedData->indent != other->rareInheritedData->indent || + rareInheritedData->m_effectiveZoom != other->rareInheritedData->m_effectiveZoom || rareInheritedData->textSizeAdjust != other->rareInheritedData->textSizeAdjust || rareInheritedData->wordBreak != other->rareInheritedData->wordBreak || rareInheritedData->wordWrap != other->rareInheritedData->wordWrap || @@ -394,8 +396,7 @@ StyleDifference RenderStyle::diff(const RenderStyle* other, unsigned& changedCon return StyleDifferenceLayout; } - if (inherited->indent != other->inherited->indent || - inherited->line_height != other->inherited->line_height || + if (inherited->line_height != other->inherited->line_height || inherited->list_style_image != other->inherited->list_style_image || inherited->font != other->inherited->font || inherited->horizontal_border_spacing != other->inherited->horizontal_border_spacing || @@ -461,11 +462,8 @@ StyleDifference RenderStyle::diff(const RenderStyle* other, unsigned& changedCon const CounterDirectiveMap* mapB = other->rareNonInheritedData->m_counterDirectives.get(); if (!(mapA == mapB || (mapA && mapB && *mapA == *mapB))) return StyleDifferenceLayout; - if (visual->counterIncrement != other->visual->counterIncrement || - visual->counterReset != other->visual->counterReset) - return StyleDifferenceLayout; - - if (inherited->m_effectiveZoom != other->inherited->m_effectiveZoom) + if (rareNonInheritedData->m_counterIncrement != other->rareNonInheritedData->m_counterIncrement || + rareNonInheritedData->m_counterReset != other->rareNonInheritedData->m_counterReset) return StyleDifferenceLayout; if ((rareNonInheritedData->opacity == 1 && other->rareNonInheritedData->opacity < 1) || @@ -553,20 +551,20 @@ void RenderStyle::setClip(Length top, Length right, Length bottom, Length left) void RenderStyle::addCursor(CachedImage* image, const IntPoint& hotSpot) { - if (!inherited.access()->cursorData) - inherited.access()->cursorData = CursorList::create(); - inherited.access()->cursorData->append(CursorData(image, hotSpot)); + if (!rareInheritedData.access()->cursorData) + rareInheritedData.access()->cursorData = CursorList::create(); + rareInheritedData.access()->cursorData->append(CursorData(image, hotSpot)); } void RenderStyle::setCursorList(PassRefPtr<CursorList> other) { - inherited.access()->cursorData = other; + rareInheritedData.access()->cursorData = other; } void RenderStyle::clearCursorList() { - if (inherited->cursorData) - inherited.access()->cursorData = 0; + if (rareInheritedData->cursorData) + rareInheritedData.access()->cursorData = 0; } void RenderStyle::clearContent() @@ -1035,7 +1033,6 @@ static Color colorIncludingFallback(const RenderStyle* style, int colorProperty, result = style->textStrokeColor(); break; default: - // FIXME: Add SVG fill and stroke. ASSERT_NOT_REACHED(); break; } diff --git a/WebCore/rendering/style/RenderStyle.h b/WebCore/rendering/style/RenderStyle.h index 815fb30..970b26a 100644 --- a/WebCore/rendering/style/RenderStyle.h +++ b/WebCore/rendering/style/RenderStyle.h @@ -452,7 +452,7 @@ public: int fontSize() const { return inherited->font.pixelSize(); } const Color& color() const { return inherited->color; } - Length textIndent() const { return inherited->indent; } + Length textIndent() const { return rareInheritedData->indent; } ETextAlign textAlign() const { return static_cast<ETextAlign>(inherited_flags._text_align); } ETextTransform textTransform() const { return static_cast<ETextTransform>(inherited_flags._text_transform); } int textDecorationsInEffect() const { return inherited_flags._text_decorations; } @@ -461,7 +461,7 @@ public: int letterSpacing() const { return inherited->font.letterSpacing(); } float zoom() const { return visual->m_zoom; } - float effectiveZoom() const { return inherited->m_effectiveZoom; } + float effectiveZoom() const { return rareInheritedData->m_effectiveZoom; } TextDirection direction() const { return static_cast<TextDirection>(inherited_flags._direction); } Length lineHeight() const { return inherited->line_height; } @@ -572,8 +572,8 @@ public: EEmptyCell emptyCells() const { return static_cast<EEmptyCell>(inherited_flags._empty_cells); } ECaptionSide captionSide() const { return static_cast<ECaptionSide>(inherited_flags._caption_side); } - short counterIncrement() const { return visual->counterIncrement; } - short counterReset() const { return visual->counterReset; } + short counterIncrement() const { return rareNonInheritedData->m_counterIncrement; } + short counterReset() const { return rareNonInheritedData->m_counterReset; } EListStyleType listStyleType() const { return static_cast<EListStyleType>(inherited_flags._list_style_type); } StyleImage* listStyleImage() const { return inherited->list_style_image.get(); } @@ -592,13 +592,13 @@ public: ECursor cursor() const { return static_cast<ECursor>(inherited_flags._cursor_style); } - CursorList* cursors() const { return inherited->cursorData.get(); } + CursorList* cursors() const { return rareInheritedData->cursorData.get(); } EInsideLink insideLink() const { return static_cast<EInsideLink>(inherited_flags._insideLink); } bool isLink() const { return noninherited_flags._isLink; } - short widows() const { return inherited->widows; } - short orphans() const { return inherited->orphans; } + short widows() const { return rareInheritedData->widows; } + short orphans() const { return rareInheritedData->orphans; } EPageBreak pageBreakInside() const { return static_cast<EPageBreak>(noninherited_flags._page_break_inside); } EPageBreak pageBreakBefore() const { return static_cast<EPageBreak>(noninherited_flags._page_break_before); } EPageBreak pageBreakAfter() const { return static_cast<EPageBreak>(noninherited_flags._page_break_after); } @@ -661,6 +661,7 @@ public: bool hasAutoColumnWidth() const { return rareNonInheritedData->m_multiCol->m_autoWidth; } unsigned short columnCount() const { return rareNonInheritedData->m_multiCol->m_count; } bool hasAutoColumnCount() const { return rareNonInheritedData->m_multiCol->m_autoCount; } + bool specifiesColumns() const { return !hasAutoColumnCount() || !hasAutoColumnWidth(); } float columnGap() const { return rareNonInheritedData->m_multiCol->m_gap; } bool hasNormalColumnGap() const { return rareNonInheritedData->m_multiCol->m_normalGap; } const Color& columnRuleColor() const { return rareNonInheritedData->m_multiCol->m_rule.color(); } @@ -852,7 +853,7 @@ public: void setBlendedFontSize(int); void setColor(const Color& v) { SET_VAR(inherited, color, v) } - void setTextIndent(Length v) { SET_VAR(inherited, indent, v) } + void setTextIndent(Length v) { SET_VAR(rareInheritedData, indent, v) } void setTextAlign(ETextAlign v) { inherited_flags._text_align = v; } void setTextTransform(ETextTransform v) { inherited_flags._text_transform = v; } void addToTextDecorationsInEffect(int v) { inherited_flags._text_decorations |= v; } @@ -861,7 +862,7 @@ public: void setDirection(TextDirection v) { inherited_flags._direction = v; } void setLineHeight(Length v) { SET_VAR(inherited, line_height, v) } void setZoom(float f) { SET_VAR(visual, m_zoom, f); setEffectiveZoom(effectiveZoom() * zoom()); } - void setEffectiveZoom(float f) { SET_VAR(inherited, m_effectiveZoom, f) } + void setEffectiveZoom(float f) { SET_VAR(rareInheritedData, m_effectiveZoom, f) } void setWhiteSpace(EWhiteSpace v) { inherited_flags._white_space = v; } @@ -901,8 +902,8 @@ public: void setEmptyCells(EEmptyCell v) { inherited_flags._empty_cells = v; } void setCaptionSide(ECaptionSide v) { inherited_flags._caption_side = v; } - void setCounterIncrement(short v) { SET_VAR(visual, counterIncrement, v) } - void setCounterReset(short v) { SET_VAR(visual, counterReset, v) } + void setCounterIncrement(short v) { SET_VAR(rareNonInheritedData, m_counterIncrement, v) } + void setCounterReset(short v) { SET_VAR(rareNonInheritedData, m_counterReset, v) } void setListStyleType(EListStyleType v) { inherited_flags._list_style_type = v; } void setListStyleImage(StyleImage* v) { if (inherited->list_style_image != v) inherited.access()->list_style_image = v; } @@ -940,8 +941,8 @@ public: int zIndex() const { return m_box->zIndex(); } void setZIndex(int v) { SET_VAR(m_box, m_hasAutoZIndex, false); SET_VAR(m_box, m_zIndex, v) } - void setWidows(short w) { SET_VAR(inherited, widows, w); } - void setOrphans(short o) { SET_VAR(inherited, orphans, o); } + void setWidows(short w) { SET_VAR(rareInheritedData, widows, w); } + void setOrphans(short o) { SET_VAR(rareInheritedData, orphans, o); } void setPageBreakInside(EPageBreak b) { noninherited_flags._page_break_inside = b; } void setPageBreakBefore(EPageBreak b) { noninherited_flags._page_break_before = b; } void setPageBreakAfter(EPageBreak b) { noninherited_flags._page_break_after = b; } diff --git a/WebCore/rendering/style/StyleInheritedData.cpp b/WebCore/rendering/style/StyleInheritedData.cpp index c73497f..874d053 100644 --- a/WebCore/rendering/style/StyleInheritedData.cpp +++ b/WebCore/rendering/style/StyleInheritedData.cpp @@ -28,15 +28,11 @@ namespace WebCore { StyleInheritedData::StyleInheritedData() - : indent(RenderStyle::initialTextIndent()) - , line_height(RenderStyle::initialLineHeight()) + : line_height(RenderStyle::initialLineHeight()) , list_style_image(RenderStyle::initialListStyleImage()) , color(RenderStyle::initialColor()) - , m_effectiveZoom(RenderStyle::initialZoom()) , horizontal_border_spacing(RenderStyle::initialHorizontalBorderSpacing()) , vertical_border_spacing(RenderStyle::initialVerticalBorderSpacing()) - , widows(RenderStyle::initialWidows()) - , orphans(RenderStyle::initialOrphans()) { } @@ -46,43 +42,24 @@ StyleInheritedData::~StyleInheritedData() StyleInheritedData::StyleInheritedData(const StyleInheritedData& o) : RefCounted<StyleInheritedData>() - , indent(o.indent) , line_height(o.line_height) , list_style_image(o.list_style_image) - , cursorData(o.cursorData) , font(o.font) , color(o.color) - , m_effectiveZoom(o.m_effectiveZoom) , horizontal_border_spacing(o.horizontal_border_spacing) , vertical_border_spacing(o.vertical_border_spacing) - , widows(o.widows) - , orphans(o.orphans) { } -static bool cursorDataEquivalent(const CursorList* c1, const CursorList* c2) -{ - if (c1 == c2) - return true; - if ((!c1 && c2) || (c1 && !c2)) - return false; - return (*c1 == *c2); -} - bool StyleInheritedData::operator==(const StyleInheritedData& o) const { return - indent == o.indent && line_height == o.line_height && StyleImage::imagesEquivalent(list_style_image.get(), o.list_style_image.get()) && - cursorDataEquivalent(cursorData.get(), o.cursorData.get()) && font == o.font && color == o.color && - m_effectiveZoom == o.m_effectiveZoom && horizontal_border_spacing == o.horizontal_border_spacing && - vertical_border_spacing == o.vertical_border_spacing && - widows == o.widows && - orphans == o.orphans; + vertical_border_spacing == o.vertical_border_spacing; } } // namespace WebCore diff --git a/WebCore/rendering/style/StyleInheritedData.h b/WebCore/rendering/style/StyleInheritedData.h index 3b30b8f..ea398db 100644 --- a/WebCore/rendering/style/StyleInheritedData.h +++ b/WebCore/rendering/style/StyleInheritedData.h @@ -35,7 +35,6 @@ namespace WebCore { class StyleImage; -class CursorList; class StyleInheritedData : public RefCounted<StyleInheritedData> { public: @@ -49,26 +48,17 @@ public: return !(*this == o); } - Length indent; // could be packed in a short but doesn't // make a difference currently because of padding Length line_height; RefPtr<StyleImage> list_style_image; - RefPtr<CursorList> cursorData; Font font; Color color; - - float m_effectiveZoom; short horizontal_border_spacing; short vertical_border_spacing; - - // Paged media properties. - short widows; - short orphans; - private: StyleInheritedData(); StyleInheritedData(const StyleInheritedData&); diff --git a/WebCore/rendering/style/StyleRareInheritedData.cpp b/WebCore/rendering/style/StyleRareInheritedData.cpp index ff626b7..04923d5 100644 --- a/WebCore/rendering/style/StyleRareInheritedData.cpp +++ b/WebCore/rendering/style/StyleRareInheritedData.cpp @@ -33,6 +33,10 @@ StyleRareInheritedData::StyleRareInheritedData() , tapHighlightColor(RenderStyle::initialTapHighlightColor()) #endif , textShadow(0) + , indent(RenderStyle::initialTextIndent()) + , m_effectiveZoom(RenderStyle::initialZoom()) + , widows(RenderStyle::initialWidows()) + , orphans(RenderStyle::initialOrphans()) , textSecurity(RenderStyle::initialTextSecurity()) , userModify(READ_ONLY) , wordBreak(RenderStyle::initialWordBreak()) @@ -56,6 +60,11 @@ StyleRareInheritedData::StyleRareInheritedData(const StyleRareInheritedData& o) #endif , textShadow(o.textShadow ? new ShadowData(*o.textShadow) : 0) , highlight(o.highlight) + , cursorData(o.cursorData) + , indent(o.indent) + , m_effectiveZoom(o.m_effectiveZoom) + , widows(o.widows) + , orphans(o.orphans) , textSecurity(o.textSecurity) , userModify(o.userModify) , wordBreak(o.wordBreak) @@ -74,6 +83,15 @@ StyleRareInheritedData::~StyleRareInheritedData() delete textShadow; } +static bool cursorDataEquivalent(const CursorList* c1, const CursorList* c2) +{ + if (c1 == c2) + return true; + if ((!c1 && c2) || (c1 && !c2)) + return false; + return (*c1 == *c2); +} + bool StyleRareInheritedData::operator==(const StyleRareInheritedData& o) const { return textStrokeColor == o.textStrokeColor @@ -81,6 +99,11 @@ bool StyleRareInheritedData::operator==(const StyleRareInheritedData& o) const && textFillColor == o.textFillColor && shadowDataEquivalent(o) && highlight == o.highlight + && cursorDataEquivalent(cursorData.get(), o.cursorData.get()) + && indent == o.indent + && m_effectiveZoom == o.m_effectiveZoom + && widows == o.widows + && orphans == o.orphans && textSecurity == o.textSecurity && userModify == o.userModify && wordBreak == o.wordBreak diff --git a/WebCore/rendering/style/StyleRareInheritedData.h b/WebCore/rendering/style/StyleRareInheritedData.h index 8f128fd..3ad8b0b 100644 --- a/WebCore/rendering/style/StyleRareInheritedData.h +++ b/WebCore/rendering/style/StyleRareInheritedData.h @@ -27,11 +27,13 @@ #include "AtomicString.h" #include "Color.h" +#include "Length.h" #include <wtf/RefCounted.h> #include <wtf/PassRefPtr.h> namespace WebCore { +class CursorList; class ShadowData; // This struct is for rarely used inherited CSS3, CSS2, and WebKit-specific properties. @@ -59,6 +61,15 @@ public: ShadowData* textShadow; // Our text shadow information for shadowed text drawing. AtomicString highlight; // Apple-specific extension for custom highlight rendering. + + RefPtr<CursorList> cursorData; + Length indent; + float m_effectiveZoom; + + // Paged media properties. + short widows; + short orphans; + unsigned textSecurity : 2; // ETextSecurity unsigned userModify : 2; // EUserModify (editing) unsigned wordBreak : 2; // EWordBreak diff --git a/WebCore/rendering/style/StyleRareNonInheritedData.cpp b/WebCore/rendering/style/StyleRareNonInheritedData.cpp index 401c04f..e3367d1 100644 --- a/WebCore/rendering/style/StyleRareNonInheritedData.cpp +++ b/WebCore/rendering/style/StyleRareNonInheritedData.cpp @@ -42,6 +42,8 @@ StyleRareNonInheritedData::StyleRareNonInheritedData() , matchNearestMailBlockquoteColor(RenderStyle::initialMatchNearestMailBlockquoteColor()) , m_appearance(RenderStyle::initialAppearance()) , m_borderFit(RenderStyle::initialBorderFit()) + , m_counterIncrement(0) + , m_counterReset(0) #if USE(ACCELERATED_COMPOSITING) , m_runningAcceleratedAnimation(false) #endif @@ -77,6 +79,8 @@ StyleRareNonInheritedData::StyleRareNonInheritedData(const StyleRareNonInherited , matchNearestMailBlockquoteColor(o.matchNearestMailBlockquoteColor) , m_appearance(o.m_appearance) , m_borderFit(o.m_borderFit) + , m_counterIncrement(o.m_counterIncrement) + , m_counterReset(o.m_counterReset) #if USE(ACCELERATED_COMPOSITING) , m_runningAcceleratedAnimation(o.m_runningAcceleratedAnimation) #endif @@ -133,6 +137,8 @@ bool StyleRareNonInheritedData::operator==(const StyleRareNonInheritedData& o) c && matchNearestMailBlockquoteColor == o.matchNearestMailBlockquoteColor && m_appearance == o.m_appearance && m_borderFit == o.m_borderFit + && m_counterIncrement == o.m_counterIncrement + && m_counterReset == o.m_counterReset #if USE(ACCELERATED_COMPOSITING) && !m_runningAcceleratedAnimation && !o.m_runningAcceleratedAnimation #endif diff --git a/WebCore/rendering/style/StyleRareNonInheritedData.h b/WebCore/rendering/style/StyleRareNonInheritedData.h index 21bbe94..d6fe96e 100644 --- a/WebCore/rendering/style/StyleRareNonInheritedData.h +++ b/WebCore/rendering/style/StyleRareNonInheritedData.h @@ -100,9 +100,13 @@ public: unsigned matchNearestMailBlockquoteColor : 1; // EMatchNearestMailBlockquoteColor, FIXME: This property needs to be eliminated. It should never have been added. unsigned m_appearance : 6; // EAppearance unsigned m_borderFit : 1; // EBorderFit + + short m_counterIncrement; + short m_counterReset; + #if USE(ACCELERATED_COMPOSITING) bool m_runningAcceleratedAnimation : 1; -#endif +#endif OwnPtr<ShadowData> m_boxShadow; // For box-shadow decorations. RefPtr<StyleReflection> m_boxReflect; diff --git a/WebCore/rendering/style/StyleVisualData.cpp b/WebCore/rendering/style/StyleVisualData.cpp index 91690cf..14996c9 100644 --- a/WebCore/rendering/style/StyleVisualData.cpp +++ b/WebCore/rendering/style/StyleVisualData.cpp @@ -29,8 +29,6 @@ namespace WebCore { StyleVisualData::StyleVisualData() : hasClip(false) , textDecoration(RenderStyle::initialTextDecoration()) - , counterIncrement(0) - , counterReset(0) , m_zoom(RenderStyle::initialZoom()) { } @@ -44,8 +42,6 @@ StyleVisualData::StyleVisualData(const StyleVisualData& o) , clip(o.clip) , hasClip(o.hasClip) , textDecoration(o.textDecoration) - , counterIncrement(o.counterIncrement) - , counterReset(o.counterReset) , m_zoom(RenderStyle::initialZoom()) { } diff --git a/WebCore/rendering/style/StyleVisualData.h b/WebCore/rendering/style/StyleVisualData.h index 613ef2f..d1f0f83 100644 --- a/WebCore/rendering/style/StyleVisualData.h +++ b/WebCore/rendering/style/StyleVisualData.h @@ -41,8 +41,6 @@ public: { return ( clip == o.clip && hasClip == o.hasClip && - counterIncrement == o.counterIncrement && - counterReset == o.counterReset && textDecoration == o.textDecoration && m_zoom == o.m_zoom); } @@ -52,9 +50,6 @@ public: bool hasClip : 1; unsigned textDecoration : 4; // Text decorations defined *only* by this element. - short counterIncrement; // ok, so these are not visual mode specific - short counterReset; // can't go to inherited, since these are not inherited - float m_zoom; private: |