| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) | 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) |
| 3 * (C) 1999 Antti Koivisto (koivisto@kde.org) | 3 * (C) 1999 Antti Koivisto (koivisto@kde.org) |
| 4 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserv
ed. | 4 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserv
ed. |
| 5 * Copyright (C) 2006 Andrew Wellington (proton@wiretapped.net) | 5 * Copyright (C) 2006 Andrew Wellington (proton@wiretapped.net) |
| 6 * Copyright (C) 2010 Daniel Bates (dbates@intudata.com) | 6 * Copyright (C) 2010 Daniel Bates (dbates@intudata.com) |
| 7 * | 7 * |
| 8 * This library is free software; you can redistribute it and/or | 8 * This library is free software; you can redistribute it and/or |
| 9 * modify it under the terms of the GNU Library General Public | 9 * modify it under the terms of the GNU Library General Public |
| 10 * License as published by the Free Software Foundation; either | 10 * License as published by the Free Software Foundation; either |
| 11 * version 2 of the License, or (at your option) any later version. | 11 * version 2 of the License, or (at your option) any later version. |
| 12 * | 12 * |
| 13 * This library is distributed in the hope that it will be useful, | 13 * This library is distributed in the hope that it will be useful, |
| 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 16 * Library General Public License for more details. | 16 * Library General Public License for more details. |
| 17 * | 17 * |
| 18 * You should have received a copy of the GNU Library General Public License | 18 * You should have received a copy of the GNU Library General Public License |
| 19 * along with this library; see the file COPYING.LIB. If not, write to | 19 * along with this library; see the file COPYING.LIB. If not, write to |
| 20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | 20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
| 21 * Boston, MA 02110-1301, USA. | 21 * Boston, MA 02110-1301, USA. |
| 22 * | 22 * |
| 23 */ | 23 */ |
| 24 | 24 |
| 25 #include "config.h" | 25 #include "config.h" |
| 26 #include "core/rendering/RenderListMarker.h" | 26 #include "core/rendering/RenderListMarker.h" |
| 27 | 27 |
| 28 #include "core/fetch/ImageResource.h" | 28 #include "core/fetch/ImageResource.h" |
| 29 #include "core/rendering/GraphicsContextAnnotator.h" | 29 #include "core/paint/ListMarkerPainter.h" |
| 30 #include "core/rendering/RenderLayer.h" | 30 #include "core/rendering/RenderLayer.h" |
| 31 #include "core/rendering/RenderListItem.h" | 31 #include "core/rendering/RenderListItem.h" |
| 32 #include "core/rendering/TextRunConstructor.h" | 32 #include "core/rendering/TextRunConstructor.h" |
| 33 #include "platform/fonts/Font.h" | 33 #include "platform/fonts/Font.h" |
| 34 #include "platform/graphics/GraphicsContextStateSaver.h" | |
| 35 #include "wtf/text/StringBuilder.h" | 34 #include "wtf/text/StringBuilder.h" |
| 36 #include "wtf/unicode/CharacterNames.h" | |
| 37 | |
| 38 using namespace WTF; | |
| 39 using namespace Unicode; | |
| 40 | 35 |
| 41 namespace blink { | 36 namespace blink { |
| 42 | 37 |
| 43 const int cMarkerPadding = 7; | 38 const int cMarkerPadding = 7; |
| 44 | 39 |
| 45 enum SequenceType { NumericSequence, AlphabeticSequence }; | 40 enum SequenceType { NumericSequence, AlphabeticSequence }; |
| 46 | 41 |
| 47 static String toRoman(int number, bool upper) | 42 static String toRoman(int number, bool upper) |
| 48 { | 43 { |
| 49 // FIXME: CSS3 describes how to make this work for much larger numbers, | 44 // FIXME: CSS3 describes how to make this work for much larger numbers, |
| (...skipping 445 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 495 case UpperGreek: | 490 case UpperGreek: |
| 496 case UpperLatin: | 491 case UpperLatin: |
| 497 case UpperNorwegian: | 492 case UpperNorwegian: |
| 498 return (value < 1) ? DecimalListStyle : type; | 493 return (value < 1) ? DecimalListStyle : type; |
| 499 } | 494 } |
| 500 | 495 |
| 501 ASSERT_NOT_REACHED(); | 496 ASSERT_NOT_REACHED(); |
| 502 return type; | 497 return type; |
| 503 } | 498 } |
| 504 | 499 |
| 505 static UChar listMarkerSuffix(EListStyleType type, int value) | 500 UChar RenderListMarker::listMarkerSuffix(EListStyleType type, int value) |
| 506 { | 501 { |
| 507 // If the list-style-type cannot represent |value| because it's outside its | 502 // If the list-style-type cannot represent |value| because it's outside its |
| 508 // ordinal range then we fall back to some list style that can represent |va
lue|. | 503 // ordinal range then we fall back to some list style that can represent |va
lue|. |
| 509 EListStyleType effectiveType = effectiveListMarkerType(type, value); | 504 EListStyleType effectiveType = effectiveListMarkerType(type, value); |
| 510 | 505 |
| 511 // Note, the following switch statement has been explicitly | 506 // Note, the following switch statement has been explicitly |
| 512 // grouped by list-style-type suffix. | 507 // grouped by list-style-type suffix. |
| 513 switch (effectiveType) { | 508 switch (effectiveType) { |
| 514 case Asterisks: | 509 case Asterisks: |
| 515 case Circle: | 510 case Circle: |
| (...skipping 610 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1126 return LayoutRect(LayoutPoint(), size()); | 1121 return LayoutRect(LayoutPoint(), size()); |
| 1127 RootInlineBox& root = inlineBoxWrapper()->root(); | 1122 RootInlineBox& root = inlineBoxWrapper()->root(); |
| 1128 LayoutUnit newLogicalTop = root.block().style()->isFlippedBlocksWritingMode(
) ? inlineBoxWrapper()->logicalBottom() - root.selectionBottom() : root.selectio
nTop() - inlineBoxWrapper()->logicalTop(); | 1123 LayoutUnit newLogicalTop = root.block().style()->isFlippedBlocksWritingMode(
) ? inlineBoxWrapper()->logicalBottom() - root.selectionBottom() : root.selectio
nTop() - inlineBoxWrapper()->logicalTop(); |
| 1129 if (root.block().style()->isHorizontalWritingMode()) | 1124 if (root.block().style()->isHorizontalWritingMode()) |
| 1130 return LayoutRect(0, newLogicalTop, width(), root.selectionHeight()); | 1125 return LayoutRect(0, newLogicalTop, width(), root.selectionHeight()); |
| 1131 return LayoutRect(newLogicalTop, 0, root.selectionHeight(), height()); | 1126 return LayoutRect(newLogicalTop, 0, root.selectionHeight(), height()); |
| 1132 } | 1127 } |
| 1133 | 1128 |
| 1134 void RenderListMarker::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffse
t) | 1129 void RenderListMarker::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffse
t) |
| 1135 { | 1130 { |
| 1136 ANNOTATE_GRAPHICS_CONTEXT(paintInfo, this); | 1131 ListMarkerPainter(*this).paint(paintInfo, paintOffset); |
| 1137 | |
| 1138 if (paintInfo.phase != PaintPhaseForeground) | |
| 1139 return; | |
| 1140 | |
| 1141 if (style()->visibility() != VISIBLE) | |
| 1142 return; | |
| 1143 | |
| 1144 LayoutPoint boxOrigin(paintOffset + location()); | |
| 1145 LayoutRect overflowRect(visualOverflowRect()); | |
| 1146 overflowRect.moveBy(boxOrigin); | |
| 1147 | |
| 1148 if (!paintInfo.rect.intersects(pixelSnappedIntRect(overflowRect))) | |
| 1149 return; | |
| 1150 | |
| 1151 LayoutRect box(boxOrigin, size()); | |
| 1152 | |
| 1153 IntRect marker = getRelativeMarkerRect(); | |
| 1154 marker.moveBy(roundedIntPoint(boxOrigin)); | |
| 1155 | |
| 1156 GraphicsContext* context = paintInfo.context; | |
| 1157 | |
| 1158 if (isImage()) { | |
| 1159 context->drawImage(m_image->image(this, marker.size()).get(), marker); | |
| 1160 if (selectionState() != SelectionNone) { | |
| 1161 LayoutRect selRect = localSelectionRect(); | |
| 1162 selRect.moveBy(boxOrigin); | |
| 1163 context->fillRect(pixelSnappedIntRect(selRect), selectionBackgroundC
olor()); | |
| 1164 } | |
| 1165 return; | |
| 1166 } | |
| 1167 | |
| 1168 if (selectionState() != SelectionNone) { | |
| 1169 LayoutRect selRect = localSelectionRect(); | |
| 1170 selRect.moveBy(boxOrigin); | |
| 1171 context->fillRect(pixelSnappedIntRect(selRect), selectionBackgroundColor
()); | |
| 1172 } | |
| 1173 | |
| 1174 const Color color(resolveColor(CSSPropertyColor)); | |
| 1175 context->setStrokeColor(color); | |
| 1176 context->setStrokeStyle(SolidStroke); | |
| 1177 context->setStrokeThickness(1.0f); | |
| 1178 context->setFillColor(color); | |
| 1179 | |
| 1180 EListStyleType type = style()->listStyleType(); | |
| 1181 switch (type) { | |
| 1182 case Disc: | |
| 1183 context->fillEllipse(marker); | |
| 1184 return; | |
| 1185 case Circle: | |
| 1186 context->strokeEllipse(marker); | |
| 1187 return; | |
| 1188 case Square: | |
| 1189 context->fillRect(marker); | |
| 1190 return; | |
| 1191 case NoneListStyle: | |
| 1192 return; | |
| 1193 case Afar: | |
| 1194 case Amharic: | |
| 1195 case AmharicAbegede: | |
| 1196 case ArabicIndic: | |
| 1197 case Armenian: | |
| 1198 case BinaryListStyle: | |
| 1199 case Bengali: | |
| 1200 case Cambodian: | |
| 1201 case CJKIdeographic: | |
| 1202 case CjkEarthlyBranch: | |
| 1203 case CjkHeavenlyStem: | |
| 1204 case DecimalLeadingZero: | |
| 1205 case DecimalListStyle: | |
| 1206 case Devanagari: | |
| 1207 case Ethiopic: | |
| 1208 case EthiopicAbegede: | |
| 1209 case EthiopicAbegedeAmEt: | |
| 1210 case EthiopicAbegedeGez: | |
| 1211 case EthiopicAbegedeTiEr: | |
| 1212 case EthiopicAbegedeTiEt: | |
| 1213 case EthiopicHalehameAaEr: | |
| 1214 case EthiopicHalehameAaEt: | |
| 1215 case EthiopicHalehameAmEt: | |
| 1216 case EthiopicHalehameGez: | |
| 1217 case EthiopicHalehameOmEt: | |
| 1218 case EthiopicHalehameSidEt: | |
| 1219 case EthiopicHalehameSoEt: | |
| 1220 case EthiopicHalehameTiEr: | |
| 1221 case EthiopicHalehameTiEt: | |
| 1222 case EthiopicHalehameTig: | |
| 1223 case Georgian: | |
| 1224 case Gujarati: | |
| 1225 case Gurmukhi: | |
| 1226 case Hangul: | |
| 1227 case HangulConsonant: | |
| 1228 case Hebrew: | |
| 1229 case Hiragana: | |
| 1230 case HiraganaIroha: | |
| 1231 case Kannada: | |
| 1232 case Katakana: | |
| 1233 case KatakanaIroha: | |
| 1234 case Khmer: | |
| 1235 case Lao: | |
| 1236 case LowerAlpha: | |
| 1237 case LowerArmenian: | |
| 1238 case LowerGreek: | |
| 1239 case LowerHexadecimal: | |
| 1240 case LowerLatin: | |
| 1241 case LowerNorwegian: | |
| 1242 case LowerRoman: | |
| 1243 case Malayalam: | |
| 1244 case Mongolian: | |
| 1245 case Myanmar: | |
| 1246 case Octal: | |
| 1247 case Oriya: | |
| 1248 case Oromo: | |
| 1249 case Persian: | |
| 1250 case Sidama: | |
| 1251 case Somali: | |
| 1252 case Telugu: | |
| 1253 case Thai: | |
| 1254 case Tibetan: | |
| 1255 case Tigre: | |
| 1256 case TigrinyaEr: | |
| 1257 case TigrinyaErAbegede: | |
| 1258 case TigrinyaEt: | |
| 1259 case TigrinyaEtAbegede: | |
| 1260 case UpperAlpha: | |
| 1261 case UpperArmenian: | |
| 1262 case UpperGreek: | |
| 1263 case UpperHexadecimal: | |
| 1264 case UpperLatin: | |
| 1265 case UpperNorwegian: | |
| 1266 case UpperRoman: | |
| 1267 case Urdu: | |
| 1268 case Asterisks: | |
| 1269 case Footnotes: | |
| 1270 break; | |
| 1271 } | |
| 1272 if (m_text.isEmpty()) | |
| 1273 return; | |
| 1274 | |
| 1275 const Font& font = style()->font(); | |
| 1276 TextRun textRun = constructTextRun(this, font, m_text, style()); | |
| 1277 | |
| 1278 GraphicsContextStateSaver stateSaver(*context, false); | |
| 1279 if (!style()->isHorizontalWritingMode()) { | |
| 1280 marker.moveBy(roundedIntPoint(-boxOrigin)); | |
| 1281 marker = marker.transposedRect(); | |
| 1282 marker.moveBy(IntPoint(roundToInt(box.x()), roundToInt(box.y() - logical
Height()))); | |
| 1283 stateSaver.save(); | |
| 1284 context->translate(marker.x(), marker.maxY()); | |
| 1285 context->rotate(static_cast<float>(deg2rad(90.))); | |
| 1286 context->translate(-marker.x(), -marker.maxY()); | |
| 1287 } | |
| 1288 | |
| 1289 TextRunPaintInfo textRunPaintInfo(textRun); | |
| 1290 textRunPaintInfo.bounds = marker; | |
| 1291 IntPoint textOrigin = IntPoint(marker.x(), marker.y() + style()->fontMetrics
().ascent()); | |
| 1292 | |
| 1293 if (type == Asterisks || type == Footnotes) { | |
| 1294 context->drawText(font, textRunPaintInfo, textOrigin); | |
| 1295 } | |
| 1296 else { | |
| 1297 // Text is not arbitrary. We can judge whether it's RTL from the first c
haracter, | |
| 1298 // and we only need to handle the direction RightToLeft for now. | |
| 1299 bool textNeedsReversing = direction(m_text[0]) == RightToLeft; | |
| 1300 StringBuilder reversedText; | |
| 1301 if (textNeedsReversing) { | |
| 1302 int length = m_text.length(); | |
| 1303 reversedText.reserveCapacity(length); | |
| 1304 for (int i = length - 1; i >= 0; --i) | |
| 1305 reversedText.append(m_text[i]); | |
| 1306 ASSERT(reversedText.length() == reversedText.capacity()); | |
| 1307 textRun.setText(reversedText.toString()); | |
| 1308 } | |
| 1309 | |
| 1310 const UChar suffix = listMarkerSuffix(type, m_listItem->value()); | |
| 1311 UChar suffixStr[2] = { | |
| 1312 style()->isLeftToRightDirection() ? suffix : ' ', | |
| 1313 style()->isLeftToRightDirection() ? ' ' : suffix | |
| 1314 }; | |
| 1315 TextRun suffixRun = constructTextRun(this, font, suffixStr, 2, style(),
style()->direction()); | |
| 1316 TextRunPaintInfo suffixRunInfo(suffixRun); | |
| 1317 suffixRunInfo.bounds = marker; | |
| 1318 | |
| 1319 if (style()->isLeftToRightDirection()) { | |
| 1320 context->drawText(font, textRunPaintInfo, textOrigin); | |
| 1321 context->drawText(font, suffixRunInfo, textOrigin + IntSize(font.wid
th(textRun), 0)); | |
| 1322 } else { | |
| 1323 context->drawText(font, suffixRunInfo, textOrigin); | |
| 1324 context->drawText(font, textRunPaintInfo, textOrigin + IntSize(font.
width(suffixRun), 0)); | |
| 1325 } | |
| 1326 } | |
| 1327 } | 1132 } |
| 1328 | 1133 |
| 1329 void RenderListMarker::layout() | 1134 void RenderListMarker::layout() |
| 1330 { | 1135 { |
| 1331 ASSERT(needsLayout()); | 1136 ASSERT(needsLayout()); |
| 1332 | 1137 |
| 1333 if (isImage()) { | 1138 if (isImage()) { |
| 1334 updateMarginsAndContent(); | 1139 updateMarginsAndContent(); |
| 1335 setWidth(m_image->imageSize(this, style()->effectiveZoom()).width()); | 1140 setWidth(m_image->imageSize(this, style()->effectiveZoom()).width()); |
| 1336 setHeight(m_image->imageSize(this, style()->effectiveZoom()).height()); | 1141 setHeight(m_image->imageSize(this, style()->effectiveZoom()).height()); |
| (...skipping 485 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1822 if (selectionState() == SelectionNone || !inlineBoxWrapper()) | 1627 if (selectionState() == SelectionNone || !inlineBoxWrapper()) |
| 1823 return LayoutRect(); | 1628 return LayoutRect(); |
| 1824 | 1629 |
| 1825 RootInlineBox& root = inlineBoxWrapper()->root(); | 1630 RootInlineBox& root = inlineBoxWrapper()->root(); |
| 1826 LayoutRect rect(0, root.selectionTop() - y(), width(), root.selectionHeight(
)); | 1631 LayoutRect rect(0, root.selectionTop() - y(), width(), root.selectionHeight(
)); |
| 1827 | 1632 |
| 1828 return localToContainerQuad(FloatRect(rect), paintInvalidationContainer).enc
losingBoundingBox(); | 1633 return localToContainerQuad(FloatRect(rect), paintInvalidationContainer).enc
losingBoundingBox(); |
| 1829 } | 1634 } |
| 1830 | 1635 |
| 1831 } // namespace blink | 1636 } // namespace blink |
| OLD | NEW |