Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(819)

Unified Diff: Source/core/dom/FirstLetterHelper.cpp

Issue 571603003: Convert first letter into a pseudo element. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: Source/core/dom/FirstLetterHelper.cpp
diff --git a/Source/core/dom/FirstLetterHelper.cpp b/Source/core/dom/FirstLetterHelper.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..90c8203f403755de77792c1d44d66d9939f31bdd
--- /dev/null
+++ b/Source/core/dom/FirstLetterHelper.cpp
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (C) 2007 David Smith (catfish.man@gmail.com)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
+ * 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 "core/dom/FirstLetterHelper.h"
+
+#include "core/dom/Element.h"
+#include "core/rendering/RenderObject.h"
+#include "core/rendering/RenderText.h"
+#include "wtf/text/WTFString.h"
+#include "wtf/unicode/icu/UnicodeIcu.h"
+
+namespace blink {
+
+using namespace WTF;
+using namespace Unicode;
+
+// CSS 2.1 http://www.w3.org/TR/CSS21/selector.html#first-letter
+// "Punctuation (i.e, characters defined in Unicode [UNICODE] in the "open" (Ps), "close" (Pe),
+// "initial" (Pi). "final" (Pf) and "other" (Po) punctuation classes), that precedes or follows the first letter should be included"
+static inline bool isPunctuationForFirstLetter(UChar c)
+{
+ CharCategory charCategory = category(c);
+ return charCategory == Punctuation_Open
+ || charCategory == Punctuation_Close
+ || charCategory == Punctuation_InitialQuote
+ || charCategory == Punctuation_FinalQuote
+ || charCategory == Punctuation_Other;
+}
+
+static inline bool isSpaceOrNewline(UChar c)
+{
+ // Use isASCIISpace() for basic Latin-1.
+ // This will include newlines, which aren't included in Unicode DirWS.
+ return c <= 0x7F ? WTF::isASCIISpace(c) : WTF::Unicode::direction(c) == WTF::Unicode::WhiteSpaceNeutral;
+}
+
+static inline bool isSpaceForFirstLetter(UChar c)
+{
+ return isSpaceOrNewline(c) || c == noBreakSpace;
+}
+
+unsigned FirstLetterHelper::firstLetterLength(const String& text)
+{
+ unsigned length = 0;
+ unsigned textLength = text.length();
+
+ // Account for leading spaces first.
+ while (length < textLength && isSpaceForFirstLetter(text[length]))
+ length++;
+
+ // Now account for leading punctuation.
+ while (length < textLength && isPunctuationForFirstLetter(text[length]))
+ length++;
+
+ // Bail if we didn't find a letter before the end of the text or before a space.
+ if (isSpaceForFirstLetter(text[length]) || (textLength && length == textLength))
+ return 0;
+
+ // Account the next character for first letter.
+ length++;
+
+ // Keep looking allowed punctuation for the :first-letter.
Julien - ping for review 2014/10/01 21:14:47 Keep looking *for* allowed punctuation?
dsinclair 2014/10/04 02:01:34 Done.
+ for (unsigned scanLength = length; scanLength < textLength; ++scanLength) {
+ UChar c = text[scanLength];
+
+ if (!isPunctuationForFirstLetter(c))
+ break;
+
+ length = scanLength + 1;
Julien - ping for review 2014/10/01 21:14:47 It seems wasteful to do this update in the loop in
dsinclair 2014/10/04 02:01:34 Fixed the code. We don't need scanLength at all as
+ }
+
+ // FIXME: If textLength is 0, length may still be 1!
+ return length;
+}
+
+
+RenderObject* FirstLetterHelper::firstLetterTextRenderer(const Element& element)
+{
+ RenderObject* parentRenderer;
+
+ // If we are looking at a first letter element then we need to find the
+ // first letter text renderer from the parent node, and not ourselves.
+ if (element.isFirstLetterPseudoElement())
+ parentRenderer = element.parentOrShadowHostElement()->renderer();
+ else
+ parentRenderer = element.renderer();
+
+ if (!parentRenderer
+ || !parentRenderer->style()->hasPseudoStyle(FIRST_LETTER)
+ || !parentRenderer->canHaveGeneratedChildren()
+ || !(parentRenderer->isRenderBlockFlow() || parentRenderer->isRenderButton()))
+ return nullptr;
+
+ // Drill down into our children and look for our first text child.
+ RenderObject* firstLetterTextRenderer = parentRenderer->slowFirstChild();
+ while (firstLetterTextRenderer) {
+
+ // This can be called when the first letter renderer is already in the tree. We do not
+ // want to consider that renderer for our text renderer so we go the sibling.
+ if (firstLetterTextRenderer->style() && firstLetterTextRenderer->style()->styleType() == FIRST_LETTER) {
+ firstLetterTextRenderer = firstLetterTextRenderer->nextSibling();
+
Julien - ping for review 2014/10/01 21:14:47 While helpful, those extra spaces are not consiste
dsinclair 2014/10/04 02:01:34 Done.
+ } else if (firstLetterTextRenderer->isText()) {
+ // FIXME: If there is leading punctuation in a different RenderText than
+ // the first letter, we'll not apply the correct style to it.
Julien - ping for review 2014/10/01 21:14:47 Could you give an example of when this would happe
Julien - ping for review 2014/10/01 21:14:47 Could you give an example of when this would happe
dsinclair 2014/10/04 02:01:34 I don't know. This is from the original code. I'll
+ if (firstLetterLength(toRenderText(firstLetterTextRenderer)->originalText()))
+ break;
+ firstLetterTextRenderer = firstLetterTextRenderer->nextSibling();
+
+ } else if (firstLetterTextRenderer->isListMarker()) {
+ firstLetterTextRenderer = firstLetterTextRenderer->nextSibling();
+
+ } else if (firstLetterTextRenderer->isFloatingOrOutOfFlowPositioned()) {
+ if (firstLetterTextRenderer->style()->styleType() == FIRST_LETTER) {
+ firstLetterTextRenderer = firstLetterTextRenderer->slowFirstChild();
+ break;
+ }
+ firstLetterTextRenderer = firstLetterTextRenderer->nextSibling();
+
+ } else if (firstLetterTextRenderer->isReplaced() || firstLetterTextRenderer->isRenderButton()
+ || firstLetterTextRenderer->isMenuList()) {
+ return nullptr;
+
+ } else if (firstLetterTextRenderer->style()->hasPseudoStyle(FIRST_LETTER)
+ && firstLetterTextRenderer->canHaveGeneratedChildren()) {
+ // Let the child handle it when it's attached.
+ return nullptr;
+
+ } else {
+ firstLetterTextRenderer = firstLetterTextRenderer->slowFirstChild();
+ }
+ }
+
+ // No first letter text to display, we're done.
+ // FIXME: This black-list of disallowed RenderText subclasses is fragile.
+ // Should counter be on this list? What about RenderTextFragment?
+ if (!firstLetterTextRenderer || !firstLetterTextRenderer->isText()
+ || firstLetterTextRenderer->isBR() || toRenderText(firstLetterTextRenderer)->isWordBreak())
+ return nullptr;
+
+ return firstLetterTextRenderer;
+}
+
+} // namespace blink

Powered by Google App Engine
This is Rietveld 408576698