Changeset 30949 in webkit
- Timestamp:
- Mar 10, 2008, 5:45:47 PM (17 years ago)
- Location:
- trunk/WebCore
- Files:
-
- 15 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/WebCore/ChangeLog
r30947 r30949 1 2008-03-10 Darin Adler <darin@apple.com> 2 3 Reviewed by Antti. 4 5 - fix <rdar://problem/3059610> VIP: links opened in new frame, window, or tab 6 should be redrawn as visited immediately 7 - fix <rdar://problem/4382809> Going "back" a page doesn't change the color of 8 the visited URL at directory.umi 9 - fix http://bugs.webkit.org/show_bug.cgi?id=4941 10 Visited links should be marked as visited 11 - fix http://bugs.webkit.org/show_bug.cgi?id=7960 12 REGRESSION: Visited link color doesn't displayed after loading page from cache 13 14 We now mark all links on a page as "changed" at the appropriate times. 15 16 * WebCore.base.exp: Update since I made completeURL be a const member function. 17 18 * css/CSSStyleSelector.cpp: Got rid of some unneeded globals that could be turned 19 into locals. Also changed some static data members to file-scoped globals with 20 internal linkage. Renamed the globals to get rid of the m_ prefix. Changed the 21 prefix on m_styleNotYetAvailable to s_styleNotYetAvailable. 22 (WebCore::CSSStyleSelector::CSSStyleSelector): Updated for name changes. 23 (WebCore::parseUASheet): Tweak the comment. 24 (WebCore::CSSStyleSelector::loadDefaultStyle): Updated for name changes and to 25 use local variables instead of globals where possible. 26 (WebCore::CSSStyleSelector::checkPseudoState): Made this a member function so 27 it can store the link in a hash. Also changed it to have a return value instead 28 of having it modify a global variable. Added code to put the hash into a set so 29 we can tell later if this is one of the links that affects this page. 30 (WebCore::CSSStyleSelector::canShareStyleWithElement): Updated for the change to 31 checkPseudoState. 32 (WebCore::CSSStyleSelector::matchUARules): Updated for name changes. 33 (WebCore::CSSStyleSelector::styleForElement): Ditto. 34 (WebCore::CSSStyleSelector::adjustRenderStyle): Ditto. 35 (WebCore::CSSStyleSelector::pseudoStyleRulesForElement): Changed code to read 36 the SVG style sheet to use a boolean global and put it right here in the function 37 since this is the only code that needs to know about it. 38 (WebCore::CSSStyleSelector::checkOneSelector): Updated for name changes. 39 (WebCore::colorForCSSValue): Moved code inside the function that is not needed 40 anywhere else. 41 (WebCore::CSSStyleSelector::getColorFromPrimitiveValue): Updaed for the change 42 to checkPseudoState. 43 (WebCore::CSSStyleSelector::allVisitedStateChanged): Added. Calls setChanged on 44 all links if there were any in the set. 45 (WebCore::CSSStyleSelector::visitedStateChanged): Added. Calls setChanged on all 46 links if the one that changed is in the set. 47 48 * css/CSSStyleSelector.h: Removed unused StyleSelector class and State enum. Made 49 CSSStyleSelector derive from Noncopyable. Made lots of member functions private that 50 didn't need to be public, and removed others that could be made into non-member 51 functions. Changed pseudoStyleRulesForElement to take a const String& instead of 52 a StringImpl*. Added new allVisitedStateChanged and visitedStateChanged functions. 53 Got rid of unneeded friend declarations. 54 55 * dom/Document.cpp: 56 (WebCore::Document::completeURL): Made const. 57 (WebCore::findSlashDotDotSlash): Moved here from PageGroup. 58 (WebCore::findSlashSlash): Ditto. 59 (WebCore::findSlashDotSlash): Ditto. 60 (WebCore::containsColonSlashSlash): 61 (WebCore::cleanPath): Ditto. 62 (WebCore::matchLetter): Ditto. 63 (WebCore::needsTrailingSlash): Ditto. 64 (WebCore::Document::visitedLinkHash): Moved this here from PageGroup. This is 65 the poor-man's completeURL function. The idea of putting it here is that this 66 way it can be alongside the real completeURL function. Later we should figure out 67 a way to make this function share more code with the real thing and match behavior. 68 69 * dom/Document.h: Marked completeURL function const. Added visitedLinkHash function. 70 71 * page/DOMWindow.cpp: 72 (WebCore::DOMWindow::getMatchedCSSRules): Updated for change to CSSStyleSelector. 73 74 * page/Page.cpp: 75 (WebCore::Page::allVisitedStateChanged): Added. Calls allVisitedStateChanged on all 76 style selectors. 77 (WebCore::Page::visitedStateChanged): Ditto. 78 * page/Page.h: Added the above functions. 79 80 * page/PageGroup.cpp: 81 (WebCore::PageGroup::isLinkVisited): Changed to take a visitedLinkHash parameter. 82 The CSSStyleSelector now handles actually computing the hash, and it does so by 83 calling code in Document. 84 (WebCore::PageGroup::addVisitedLink): Refactored so the two overloaded copies share 85 a bit more code. Added code that calls visitedStateChanged if a new link was added. 86 (WebCore::PageGroup::removeVisitedLinks): Added code to call allVisitedStateChanged 87 if any visited links are removed. 88 * page/PageGroup.h: Include StringHash.h instead of having the AlreadyHashed struct 89 definition here. 90 91 * platform/text/StringHash.h: 92 (WebCore::CaseFoldingHash::hash): Tweaked to make this a bit more consistent with 93 the StringImpl::computeHash function, using the same technique for avoiding 0. 94 (WebCore::AlreadyHashed::hash): Added. Was formerly in PageGroup.h. 95 (WebCore::AlreadyHashed::avoidDeletedValue): Added. Was formerly in PageGroup.cpp. 96 97 * rendering/RenderStyle.cpp: 98 (WebCore::RenderStyle::isStyleAvailable): Changed to use an inline function instead 99 of getting directly at a data member so the data member could be made private. 100 101 * loader/FrameLoader.cpp: 102 (WebCore::FrameLoader::scrollToAnchor): Added call to updateHistoryForAnchorScroll. 103 (WebCore::FrameLoader::updateHistoryForAnchorScroll): Added. 104 * loader/FrameLoader.h: Added updateHistoryForAnchorScroll. 105 1 106 2008-03-10 Adam Roben <aroben@apple.com> 2 107 -
trunk/WebCore/WebCore.base.exp
r30897 r30949 466 466 __ZN7WebCore7IntSizeC1ERK7_NSSize 467 467 __ZN7WebCore7nsColorERKNS_5ColorE 468 __ZN7WebCore8Document11completeURLERKNS_6StringE469 468 __ZN7WebCore8Document13removeMarkersENS_14DocumentMarker10MarkerTypeE 470 469 __ZN7WebCore8Document14setFocusedNodeEN3WTF10PassRefPtrINS_4NodeEEE … … 706 705 __ZNK7WebCore7Element12getAttributeERKNS_13QualifiedNameE 707 706 __ZNK7WebCore7IntRectcv7_NSRectEv 707 __ZNK7WebCore8Document11completeURLERKNS_6StringE 708 708 __ZNK7WebCore8Document11defaultViewEv 709 709 __ZNK7WebCore8IntPointcv8_NSPointEv -
trunk/WebCore/css/CSSStyleSelector.cpp
r30893 r30949 189 189 } 190 190 191 class CSSRuleSet 192 { 191 class CSSRuleSet { 193 192 public: 194 193 CSSRuleSet(); … … 216 215 }; 217 216 218 CSSRuleSet* CSSStyleSelector::m_defaultStyle = 0; 219 CSSRuleSet* CSSStyleSelector::m_defaultQuirksStyle = 0; 220 CSSRuleSet* CSSStyleSelector::m_defaultPrintStyle = 0; 221 CSSRuleSet* CSSStyleSelector::m_defaultViewSourceStyle = 0; 222 223 CSSStyleSheet* CSSStyleSelector::m_defaultSheet = 0; 224 RenderStyle* CSSStyleSelector::m_styleNotYetAvailable = 0; 225 CSSStyleSheet* CSSStyleSelector::m_quirksSheet = 0; 226 CSSStyleSheet* CSSStyleSelector::m_viewSourceSheet = 0; 227 228 #if ENABLE(SVG) 229 CSSStyleSheet *CSSStyleSelector::m_svgSheet = 0; 230 #endif 217 static CSSRuleSet* defaultStyle; 218 static CSSRuleSet* defaultQuirksStyle; 219 static CSSRuleSet* defaultPrintStyle; 220 static CSSRuleSet* defaultViewSourceStyle; 221 222 RenderStyle* CSSStyleSelector::s_styleNotYetAvailable; 231 223 232 224 static PseudoState pseudoState; 225 226 static void loadDefaultStyle(); 233 227 234 228 static const MediaQueryEvaluator& screenEval() … … 244 238 } 245 239 246 CSSStyleSelector::CSSStyleSelector(Document* doc, const String& userStyleSheet, StyleSheetList *styleSheets, CSSStyleSheet* mappedElementSheet, bool _strictParsing, bool matchAuthorAndUserStyles) 240 CSSStyleSelector::CSSStyleSelector(Document* doc, const String& userStyleSheet, StyleSheetList* styleSheets, CSSStyleSheet* mappedElementSheet, bool strictParsing, bool matchAuthorAndUserStyles) 241 : m_strictParsing(strictParsing) 247 242 { 248 243 init(); … … 253 248 m_matchAuthorAndUserStyles = matchAuthorAndUserStyles; 254 249 255 strictParsing = _strictParsing;256 if (! m_defaultStyle)250 m_strictParsing = strictParsing; 251 if (!defaultStyle) 257 252 loadDefaultStyle(); 258 253 … … 325 320 CSSStyleSheet* const parent = 0; 326 321 CSSStyleSheet* sheet = new CSSStyleSheet(parent); 327 sheet->ref(); // leak the sheet on purpose since it will be stored in a global variable322 sheet->ref(); // leak the sheet on purpose 328 323 sheet->parseString(String(characters, size)); 329 324 return sheet; … … 335 330 } 336 331 337 void CSSStyleSelector::loadDefaultStyle() 338 { 339 if (m_defaultStyle) 340 return; 341 342 m_defaultStyle = new CSSRuleSet; 343 m_defaultPrintStyle = new CSSRuleSet; 344 m_defaultQuirksStyle = new CSSRuleSet; 345 m_defaultViewSourceStyle = new CSSRuleSet; 332 static void loadDefaultStyle() 333 { 334 ASSERT(!defaultStyle); 335 336 defaultStyle = new CSSRuleSet; 337 defaultPrintStyle = new CSSRuleSet; 338 defaultQuirksStyle = new CSSRuleSet; 339 defaultViewSourceStyle = new CSSRuleSet; 346 340 347 341 // Strict-mode rules. 348 m_defaultSheet = parseUASheet(html4UserAgentStyleSheet);349 m_defaultStyle->addRulesFromSheet(m_defaultSheet, screenEval());350 m_defaultPrintStyle->addRulesFromSheet(m_defaultSheet, printEval());342 CSSStyleSheet* defaultSheet = parseUASheet(html4UserAgentStyleSheet); 343 defaultStyle->addRulesFromSheet(defaultSheet, screenEval()); 344 defaultPrintStyle->addRulesFromSheet(defaultSheet, printEval()); 351 345 352 346 // Quirks-mode rules. 353 m_quirksSheet = parseUASheet(quirksUserAgentStyleSheet); 354 m_defaultQuirksStyle->addRulesFromSheet(m_quirksSheet, screenEval()); 347 defaultQuirksStyle->addRulesFromSheet(parseUASheet(quirksUserAgentStyleSheet), screenEval()); 355 348 356 349 // View source rules. 357 m_viewSourceSheet = parseUASheet(sourceUserAgentStyleSheet); 358 m_defaultViewSourceStyle->addRulesFromSheet(m_viewSourceSheet, screenEval()); 350 defaultViewSourceStyle->addRulesFromSheet(parseUASheet(sourceUserAgentStyleSheet), screenEval()); 359 351 } 360 352 … … 546 538 } 547 539 548 static void checkPseudoState(Element* e, bool checkVisited = true) 549 { 550 if (!e->isLink()) { 551 pseudoState = PseudoNone; 552 return; 553 } 554 555 const AtomicString* attr; 556 if (e->isHTMLElement()) 557 attr = &e->getAttribute(hrefAttr); 540 static inline const AtomicString* linkAttribute(Node* node) 541 { 542 if (!node->isLink()) 543 return 0; 544 545 ASSERT(node->isElementNode()); 546 Element* element = static_cast<Element*>(node); 547 if (element->isHTMLElement()) 548 return &element->getAttribute(hrefAttr); 558 549 #if ENABLE(SVG) 559 else if (e->isSVGElement())560 attr = &e->getAttribute(XLinkNames::hrefAttr);550 if (element->isSVGElement()) 551 return &element->getAttribute(XLinkNames::hrefAttr); 561 552 #endif 562 else { 563 pseudoState = PseudoNone; 564 return; 565 } 566 567 if (attr->isNull()) { 568 pseudoState = PseudoNone; 569 return; 570 } 571 572 if (!checkVisited) { 573 pseudoState = PseudoAnyLink; 574 return; 575 } 576 577 Document* document = e->document(); 578 579 Frame* frame = document->frame(); 580 if (!frame) { 581 pseudoState = PseudoLink; 582 return; 583 } 553 return 0; 554 } 555 556 PseudoState CSSStyleSelector::checkPseudoState(Element* element, bool checkVisited) 557 { 558 const AtomicString* attr = linkAttribute(element); 559 if (!attr || attr->isNull()) 560 return PseudoNone; 561 562 if (!checkVisited) 563 return PseudoAnyLink; 564 565 unsigned hash = m_document->visitedLinkHash(*attr); 566 if (!hash) 567 return PseudoLink; 568 569 Frame* frame = m_document->frame(); 570 if (!frame) 571 return PseudoLink; 584 572 585 573 Page* page = frame->page(); 586 if (!page) { 587 pseudoState = PseudoLink; 588 return; 589 } 590 591 pseudoState = page->group().isLinkVisited(document, *attr) ? PseudoVisited : PseudoLink; 574 if (!page) 575 return PseudoLink; 576 577 m_linksCheckedForVisitedState.add(hash); 578 return page->group().isLinkVisited(hash) ? PseudoVisited : PseudoLink; 592 579 } 593 580 … … 734 721 const Color& linkColor = m_element->document()->linkColor(); 735 722 const Color& visitedColor = m_element->document()->visitedLinkColor(); 736 checkPseudoState(m_element, style->pseudoState() != PseudoAnyLink || linkColor != visitedColor);723 pseudoState = checkPseudoState(m_element, style->pseudoState() != PseudoAnyLink || linkColor != visitedColor); 737 724 } 738 725 linksMatch = (pseudoState == style->pseudoState()); … … 779 766 // First we match rules from the user agent sheet. 780 767 CSSRuleSet* userAgentStyleSheet = m_medium->mediaTypeMatchSpecific("print") 781 ? m_defaultPrintStyle : m_defaultStyle;768 ? defaultPrintStyle : defaultStyle; 782 769 matchRules(userAgentStyleSheet, firstUARule, lastUARule); 783 770 784 771 // In quirks mode, we match rules from the quirks user agent sheet. 785 if (! strictParsing)786 matchRules( m_defaultQuirksStyle, firstUARule, lastUARule);772 if (!m_strictParsing) 773 matchRules(defaultQuirksStyle, firstUARule, lastUARule); 787 774 788 775 // If we're in view source mode, then we match rules from the view source style sheet. 789 776 if (m_document->frame() && m_document->frame()->inViewSourceMode()) 790 matchRules( m_defaultViewSourceStyle, firstUARule, lastUARule);777 matchRules(defaultViewSourceStyle, firstUARule, lastUARule); 791 778 } 792 779 … … 799 786 // will vanish if a style recalc happens during loading. 800 787 if (allowSharing && !e->document()->haveStylesheetsLoaded() && !e->renderer()) { 801 if (! m_styleNotYetAvailable) {802 m_styleNotYetAvailable = ::new RenderStyle;803 m_styleNotYetAvailable->ref();804 m_styleNotYetAvailable->setDisplay(NONE);805 m_styleNotYetAvailable->font().update(m_fontSelector);806 } 807 m_styleNotYetAvailable->ref();788 if (!s_styleNotYetAvailable) { 789 s_styleNotYetAvailable = ::new RenderStyle; 790 s_styleNotYetAvailable->ref(); 791 s_styleNotYetAvailable->setDisplay(NONE); 792 s_styleNotYetAvailable->font().update(m_fontSelector); 793 } 794 s_styleNotYetAvailable->ref(); 808 795 e->document()->setHasNodesWithPlaceholderStyle(); 809 return m_styleNotYetAvailable;796 return s_styleNotYetAvailable; 810 797 } 811 798 … … 838 825 839 826 #if ENABLE(SVG) 840 if (e->isSVGElement() && !m_svgSheet) { 827 static bool loadedSVGUserAgentSheet; 828 if (e->isSVGElement() && !loadedSVGUserAgentSheet) { 841 829 // SVG rules. 842 m_svgSheet = parseUASheet(svgUserAgentStyleSheet); 843 m_defaultStyle->addRulesFromSheet(m_svgSheet, screenEval()); 844 m_defaultPrintStyle->addRulesFromSheet(m_svgSheet, printEval()); 830 loadedSVGUserAgentSheet = true; 831 CSSStyleSheet* svgSheet = parseUASheet(svgUserAgentStyleSheet); 832 defaultStyle->addRulesFromSheet(svgSheet, screenEval()); 833 defaultPrintStyle->addRulesFromSheet(svgSheet, printEval()); 845 834 } 846 835 #endif … … 1062 1051 // Sites also commonly use display:inline/block on <td>s and <table>s. In quirks mode we force 1063 1052 // these tags to retain their display types. 1064 if (! strictParsing && e) {1053 if (!m_strictParsing && e) { 1065 1054 if (e->hasTagName(tdTag)) { 1066 1055 style->setDisplay(TABLE_CELL); … … 1100 1089 // It is a WinIE bug that floated list items lose their bullets, so we'll emulate the quirk, 1101 1090 // but only in quirks mode. 1102 if (! strictParsing && style->floating() != FNONE)1091 if (!m_strictParsing && style->floating() != FNONE) 1103 1092 style->setDisplay(BLOCK); 1104 1093 } … … 1253 1242 } 1254 1243 1255 RefPtr<CSSRuleList> CSSStyleSelector::pseudoStyleRulesForElement(Element* e, StringImpl*pseudoStyle, bool authorOnly)1244 RefPtr<CSSRuleList> CSSStyleSelector::pseudoStyleRulesForElement(Element*, const String& pseudoStyle, bool authorOnly) 1256 1245 { 1257 1246 // FIXME: Implement this. … … 1838 1827 case CSSSelector::PseudoAnyLink: 1839 1828 if (pseudoState == PseudoUnknown) 1840 checkPseudoState(e, false);1829 pseudoState = checkPseudoState(e, false); 1841 1830 if (pseudoState == PseudoAnyLink || pseudoState == PseudoLink || pseudoState == PseudoVisited) 1842 1831 return true; … … 1848 1837 case CSSSelector::PseudoLink: 1849 1838 if (pseudoState == PseudoUnknown || pseudoState == PseudoAnyLink) 1850 checkPseudoState(e);1839 pseudoState = checkPseudoState(e); 1851 1840 if (pseudoState == PseudoLink) 1852 1841 return true; … … 1854 1843 case CSSSelector::PseudoVisited: 1855 1844 if (pseudoState == PseudoUnknown || pseudoState == PseudoAnyLink) 1856 checkPseudoState(e);1845 pseudoState = checkPseudoState(e); 1857 1846 if (pseudoState == PseudoVisited) 1858 1847 return true; … … 1874 1863 // If we're in quirks mode, then hover should never match anchors with no 1875 1864 // href and *:hover should not match anything. This is important for sites like wsj.com. 1876 if ( strictParsing || isSubSelector || (sel->hasTag() && !e->hasTagName(aTag)) || e->isLink()) {1865 if (m_strictParsing || isSubSelector || (sel->hasTag() && !e->hasTagName(aTag)) || e->isLink()) { 1877 1866 if (m_element == e && m_style) 1878 1867 m_style->setAffectedByHoverRules(true); … … 1887 1876 // If we're in quirks mode, then :active should never match anchors with no 1888 1877 // href and *:active should not match anything. 1889 if ( strictParsing || isSubSelector || (sel->hasTag() && !e->hasTagName(aTag)) || e->isLink()) {1878 if (m_strictParsing || isSubSelector || (sel->hasTag() && !e->hasTagName(aTag)) || e->isLink()) { 1890 1879 if (m_element == e && m_style) 1891 1880 m_style->setAffectedByActiveRules(true); … … 4991 4980 } 4992 4981 4993 struct ColorValue {4994 int cssValueId;4995 RGBA32 color;4996 };4997 4998 static const ColorValue colorValues[] = {4999 { CSS_VAL_AQUA, 0xFF00FFFF },5000 { CSS_VAL_BLACK, 0xFF000000 },5001 { CSS_VAL_BLUE, 0xFF0000FF },5002 { CSS_VAL_FUCHSIA, 0xFFFF00FF },5003 { CSS_VAL_GRAY, 0xFF808080 },5004 { CSS_VAL_GREEN, 0xFF008000 },5005 { CSS_VAL_LIME, 0xFF00FF00 },5006 { CSS_VAL_MAROON, 0xFF800000 },5007 { CSS_VAL_NAVY, 0xFF000080 },5008 { CSS_VAL_OLIVE, 0xFF808000 },5009 { CSS_VAL_ORANGE, 0xFFFFA500 },5010 { CSS_VAL_PURPLE, 0xFF800080 },5011 { CSS_VAL_RED, 0xFFFF0000 },5012 { CSS_VAL_SILVER, 0xFFC0C0C0 },5013 { CSS_VAL_TEAL, 0xFF008080 },5014 { CSS_VAL_WHITE, 0xFFFFFFFF },5015 { CSS_VAL_YELLOW, 0xFFFFFF00 },5016 { CSS_VAL_TRANSPARENT, 0x00000000 },5017 { CSS_VAL_GREY, 0xFF808080 },5018 { 0, 0 }5019 };5020 5021 4982 static Color colorForCSSValue(int cssValueId) 5022 4983 { 5023 for (const ColorValue* col = colorValues; col->cssValueId; ++col) 4984 struct ColorValue { 4985 int cssValueId; 4986 RGBA32 color; 4987 }; 4988 4989 static const ColorValue colorValues[] = { 4990 { CSS_VAL_AQUA, 0xFF00FFFF }, 4991 { CSS_VAL_BLACK, 0xFF000000 }, 4992 { CSS_VAL_BLUE, 0xFF0000FF }, 4993 { CSS_VAL_FUCHSIA, 0xFFFF00FF }, 4994 { CSS_VAL_GRAY, 0xFF808080 }, 4995 { CSS_VAL_GREEN, 0xFF008000 }, 4996 { CSS_VAL_GREY, 0xFF808080 }, 4997 { CSS_VAL_LIME, 0xFF00FF00 }, 4998 { CSS_VAL_MAROON, 0xFF800000 }, 4999 { CSS_VAL_NAVY, 0xFF000080 }, 5000 { CSS_VAL_OLIVE, 0xFF808000 }, 5001 { CSS_VAL_ORANGE, 0xFFFFA500 }, 5002 { CSS_VAL_PURPLE, 0xFF800080 }, 5003 { CSS_VAL_RED, 0xFFFF0000 }, 5004 { CSS_VAL_SILVER, 0xFFC0C0C0 }, 5005 { CSS_VAL_TEAL, 0xFF008080 }, 5006 { CSS_VAL_TRANSPARENT, 0x00000000 }, 5007 { CSS_VAL_WHITE, 0xFFFFFFFF }, 5008 { CSS_VAL_YELLOW, 0xFFFFFF00 }, 5009 { 0, 0 } 5010 }; 5011 5012 for (const ColorValue* col = colorValues; col->cssValueId; ++col) { 5024 5013 if (col->cssValueId == cssValueId) 5025 5014 return col->color; 5015 } 5026 5016 return theme()->systemColor(cssValueId); 5027 5017 } … … 5041 5031 else { 5042 5032 if (pseudoState == PseudoUnknown || pseudoState == PseudoAnyLink) 5043 checkPseudoState(m_element);5033 pseudoState = checkPseudoState(m_element); 5044 5034 col = (pseudoState == PseudoLink) ? linkColor : visitedColor; 5045 5035 } … … 5075 5065 } 5076 5066 5067 void CSSStyleSelector::allVisitedStateChanged() 5068 { 5069 if (m_linksCheckedForVisitedState.isEmpty()) 5070 return; 5071 for (Node* node = m_document; node; node = node->traverseNextNode()) { 5072 if (node->isLink()) 5073 node->setChanged(); 5074 } 5075 } 5076 5077 void CSSStyleSelector::visitedStateChanged(unsigned visitedHash) 5078 { 5079 if (!m_linksCheckedForVisitedState.contains(visitedHash)) 5080 return; 5081 for (Node* node = m_document; node; node = node->traverseNextNode()) { 5082 const AtomicString* attr = linkAttribute(node); 5083 if (attr && m_document->visitedLinkHash(*attr) == visitedHash) 5084 node->setChanged(); 5085 } 5086 } 5087 5077 5088 } // namespace WebCore -
trunk/WebCore/css/CSSStyleSelector.h
r30840 r30949 26 26 #include "MediaQueryExp.h" 27 27 #include "RenderStyle.h" 28 #include "StringHash.h" 28 29 #include <wtf/HashSet.h> 30 #include <wtf/HashMap.h> 29 31 #include <wtf/Vector.h> 30 32 #include <wtf/RefPtr.h> … … 57 59 class StyledElement; 58 60 59 class MediaQueryResult 60 { 61 class MediaQueryResult { 61 62 public: 62 63 MediaQueryResult(const MediaQueryExp& expr, bool result) 63 : m_expression(expr) 64 , m_result(result) 65 {} 64 : m_expression(expr) 65 , m_result(result) 66 { 67 } 66 68 67 69 MediaQueryExp m_expression; … … 69 71 }; 70 72 71 /** 72 * this class selects a RenderStyle for a given Element based on the 73 * collection of styleshets it contains. This is just a vrtual base class 74 * for specific implementations of the Selector. At the moment only CSSStyleSelector 75 * exists, but someone may wish to implement XSL. 76 */ 77 class StyleSelector { 78 public: 79 enum State { 80 None = 0x00, 81 Hover = 0x01, 82 Focus = 0x02, 83 Active = 0x04, 84 Drag = 0x08 85 }; 86 }; 87 88 /** 89 * the StyleSelector implementation for CSS. 90 */ 91 class CSSStyleSelector : public StyleSelector { 73 // This class selects a RenderStyle for a given element based on a collection of stylesheets. 74 class CSSStyleSelector : Noncopyable { 92 75 public: 93 76 CSSStyleSelector(Document*, const String& userStyleSheet, StyleSheetList*, CSSStyleSheet*, bool strictParsing, bool matchAuthorAndUserStyles); 94 77 ~CSSStyleSelector(); 95 96 static void loadDefaultStyle();97 78 98 79 void initElementAndPseudoState(Element*); 99 80 void initForStyleResolve(Element*, RenderStyle* parentStyle); 100 81 RenderStyle* styleForElement(Element*, RenderStyle* parentStyle = 0, bool allowSharing = true, bool resolveForRootDefault = false); 82 101 83 RenderStyle* pseudoStyleForElement(RenderStyle::PseudoId, Element*, RenderStyle* parentStyle = 0); 102 84 85 private: 103 86 RenderStyle* locateSharedStyle(); 104 87 Node* locateCousinList(Element* parent, unsigned depth = 1); 105 bool canShareStyleWithElement(Node* n); 106 88 bool canShareStyleWithElement(Node*); 89 90 public: 107 91 // These methods will give back the set of rules that matched for a given element (or a pseudo-element). 108 92 RefPtr<CSSRuleList> styleRulesForElement(Element*, bool authorOnly); 109 RefPtr<CSSRuleList> pseudoStyleRulesForElement(Element*, StringImpl* pseudoStyle, bool authorOnly); 110 111 bool strictParsing; 93 RefPtr<CSSRuleList> pseudoStyleRulesForElement(Element*, const String& pseudoStyle, bool authorOnly); 112 94 113 95 // Given a CSS keyword in the range (xx-small to -webkit-xxx-large), this function will return … … 115 97 float fontSizeForKeyword(int keyword, bool quirksMode, bool monospace) const; 116 98 99 private: 117 100 // When the CSS keyword "larger" is used, this function will attempt to match within the keyword 118 101 // table, and failing that, will simply multiply by 1.2. … … 122 105 float smallerFontSize(float size, bool quirksMode) const; 123 106 107 public: 124 108 void setFontSize(FontDescription&, float size); 109 110 private: 125 111 float getComputedSizeFromSpecifiedSize(bool isAbsoluteSize, float specifiedSize); 126 112 113 public: 127 114 Color getColorFromPrimitiveValue(CSSPrimitiveValue*); 128 115 … … 131 118 CSSFontSelector* fontSelector() { return m_fontSelector.get(); } 132 119 133 /* checks if a compound selector (which can consist of multiple simple selectors) 134 matches the given Element */ 120 // Checks if a compound selector (which can consist of multiple simple selectors) matches the current element. 135 121 bool checkSelector(CSSSelector*); 136 122 137 123 void addViewportDependentMediaQueryResult(const MediaQueryExp*, bool result); 124 138 125 bool affectedByViewportChange() const; 139 140 protected: 141 enum SelectorMatch { 142 SelectorMatches = 0, 143 SelectorFailsLocally, 144 SelectorFailsCompletely 145 }; 146 147 SelectorMatch checkSelector(CSSSelector*, Element *, bool isAncestor, bool isSubSelector); 148 149 /* checks if the selector matches the given Element */ 126 127 void allVisitedStateChanged(); 128 void visitedStateChanged(unsigned visitedHash); 129 130 private: 131 enum SelectorMatch { SelectorMatches, SelectorFailsLocally, SelectorFailsCompletely }; 132 SelectorMatch checkSelector(CSSSelector*, Element*, bool isAncestor, bool isSubSelector); 133 134 // Checks if the selector matches the given Element. 150 135 bool checkOneSelector(CSSSelector*, Element*, bool isAncestor, bool isSubSelector = false); 151 136 152 /* This function fixes up the default font size if it detects that the 153 current generic font family has changed. -dwh */ 154 void checkForGenericFamilyChange(RenderStyle* style, RenderStyle* parentStyle); 137 // This function fixes up the default font size if it detects that the current generic font family has changed. -dwh 138 void checkForGenericFamilyChange(RenderStyle*, RenderStyle* parentStyle); 155 139 void checkForTextSizeAdjust(); 156 140 … … 161 145 162 146 void matchRules(CSSRuleSet*, int& firstRuleIndex, int& lastRuleIndex); 163 void matchRulesForList(CSSRuleDataList* rules, int& firstRuleIndex, int& lastRuleIndex);147 void matchRulesForList(CSSRuleDataList*, int& firstRuleIndex, int& lastRuleIndex); 164 148 void sortMatchedRules(unsigned start, unsigned end); 165 149 166 150 void applyDeclarations(bool firstPass, bool important, int startIndex, int endIndex); 167 151 168 static CSSStyleSheet* m_defaultSheet; 169 static CSSStyleSheet* m_quirksSheet; 170 static CSSStyleSheet* m_viewSourceSheet; 171 #if ENABLE(SVG) 172 static CSSStyleSheet* m_svgSheet; 173 #endif 174 175 static CSSRuleSet* m_defaultStyle; 176 static CSSRuleSet* m_defaultQuirksStyle; 177 static CSSRuleSet* m_defaultPrintStyle; 178 static CSSRuleSet* m_defaultViewSourceStyle; 152 bool m_strictParsing; 179 153 180 154 CSSRuleSet* m_authorStyle; … … 188 162 189 163 public: 190 static RenderStyle* m_styleNotYetAvailable; 191 192 private: 164 static RenderStyle* styleNotYetAvailable() { return s_styleNotYetAvailable; } 165 166 private: 167 static RenderStyle* s_styleNotYetAvailable; 168 193 169 void init(); 194 170 … … 211 187 void mapTransitionTimingFunction(Transition*, CSSValue*); 212 188 void mapTransitionProperty(Transition*, CSSValue*); 189 190 void applyProperty(int id, CSSValue*); 191 #if ENABLE(SVG) 192 void applySVGProperty(int id, CSSValue*); 193 #endif 194 195 PseudoState checkPseudoState(Element*, bool checkVisited = true); 213 196 214 197 // We collect the set of decls that match in |m_matchedDecls|. We then walk the … … 247 230 Vector<MediaQueryResult*> m_viewportDependentMediaQueryResults; 248 231 249 void applyProperty(int id, CSSValue*); 250 251 #if ENABLE(SVG) 252 void applySVGProperty(int id, CSSValue*); 253 #endif 254 255 friend class CSSRuleSet; 256 friend class Node; 232 HashSet<unsigned, AlreadyHashed> m_linksCheckedForVisitedState; 257 233 }; 258 234 -
trunk/WebCore/dom/Document.cpp
r30942 r30949 2786 2786 } 2787 2787 2788 KURL Document::completeURL(const String& url) 2788 KURL Document::completeURL(const String& url) const 2789 2789 { 2790 2790 // Always return a null URL when passed a null string. … … 3772 3772 } 3773 3773 3774 static inline int findSlashDotDotSlash(const UChar* characters, size_t length) 3775 { 3776 if (length < 4) 3777 return -1; 3778 unsigned loopLimit = length - 3; 3779 for (unsigned i = 0; i < loopLimit; ++i) { 3780 if (characters[i] == '/' && characters[i + 1] == '.' && characters[i + 2] == '.' && characters[i + 3] == '/') 3781 return i; 3782 } 3783 return -1; 3784 } 3785 3786 static inline int findSlashSlash(const UChar* characters, size_t length, int position) 3787 { 3788 if (length < 2) 3789 return -1; 3790 unsigned loopLimit = length - 1; 3791 for (unsigned i = position; i < loopLimit; ++i) { 3792 if (characters[i] == '/' && characters[i + 1] == '/') 3793 return i; 3794 } 3795 return -1; 3796 } 3797 3798 static inline int findSlashDotSlash(const UChar* characters, size_t length) 3799 { 3800 if (length < 3) 3801 return -1; 3802 unsigned loopLimit = length - 2; 3803 for (unsigned i = 0; i < loopLimit; ++i) { 3804 if (characters[i] == '/' && characters[i + 1] == '.' && characters[i + 2] == '/') 3805 return i; 3806 } 3807 return -1; 3808 } 3809 3810 static inline bool containsColonSlashSlash(const UChar* characters, unsigned length) 3811 { 3812 if (length < 3) 3813 return false; 3814 unsigned loopLimit = length - 2; 3815 for (unsigned i = 0; i < loopLimit; ++i) { 3816 if (characters[i] == ':' && characters[i + 1] == '/' && characters[i + 2] == '/') 3817 return true; 3818 } 3819 return false; 3820 } 3821 3822 static inline void cleanPath(Vector<UChar, 512>& path) 3823 { 3824 // FIXME: Shold not do this in the query or anchor part. 3825 int pos; 3826 while ((pos = findSlashDotDotSlash(path.data(), path.size())) != -1) { 3827 int prev = reverseFind(path.data(), path.size(), '/', pos - 1); 3828 // don't remove the host, i.e. http://foo.org/../foo.html 3829 if (prev < 0 || (prev > 3 && path[prev - 2] == ':' && path[prev - 1] == '/')) 3830 path.remove(pos, 3); 3831 else 3832 path.remove(prev, pos - prev + 3); 3833 } 3834 3835 // FIXME: Shold not do this in the query part. 3836 // Set refPos to -2 to mean "I haven't looked for the anchor yet". 3837 // We don't want to waste a function call on the search for the the anchor 3838 // in the vast majority of cases where there is no "//" in the path. 3839 pos = 0; 3840 int refPos = -2; 3841 while ((pos = findSlashSlash(path.data(), path.size(), pos)) != -1) { 3842 if (refPos == -2) 3843 refPos = find(path.data(), path.size(), '#'); 3844 if (refPos > 0 && pos >= refPos) 3845 break; 3846 3847 if (pos == 0 || path[pos - 1] != ':') 3848 path.remove(pos); 3849 else 3850 pos += 2; 3851 } 3852 3853 // FIXME: Shold not do this in the query or anchor part. 3854 while ((pos = findSlashDotSlash(path.data(), path.size())) != -1) 3855 path.remove(pos, 2); 3856 } 3857 3858 static inline bool matchLetter(UChar c, UChar lowercaseLetter) 3859 { 3860 return (c | 0x20) == lowercaseLetter; 3861 } 3862 3863 static inline bool needsTrailingSlash(const UChar* characters, unsigned length) 3864 { 3865 if (length < 6) 3866 return false; 3867 if (!matchLetter(characters[0], 'h') 3868 || !matchLetter(characters[1], 't') 3869 || !matchLetter(characters[2], 't') 3870 || !matchLetter(characters[3], 'p')) 3871 return false; 3872 if (!(characters[4] == ':' 3873 || (matchLetter(characters[4], 's') && characters[5] == ':'))) 3874 return false; 3875 3876 unsigned pos = characters[4] == ':' ? 5 : 6; 3877 3878 // Skip initial two slashes if present. 3879 if (pos + 1 < length && characters[pos] == '/' && characters[pos + 1] == '/') 3880 pos += 2; 3881 3882 // Find next slash. 3883 while (pos < length && characters[pos] != '/') 3884 ++pos; 3885 3886 return pos == length; 3887 } 3888 3889 unsigned Document::visitedLinkHash(const AtomicString& attributeURL) const 3890 { 3891 const UChar* characters = attributeURL.characters(); 3892 unsigned length = attributeURL.length(); 3893 if (!length) 3894 return 0; 3895 3896 // This is a poor man's completeURL. Faster with less memory allocation. 3897 // FIXME: It's missing a lot of what completeURL does and a lot of what KURL does. 3898 // For example, it does not handle international domain names properly. 3899 3900 // FIXME: It is wrong that we do not do further processing on strings that have "://" in them: 3901 // 1) The "://" could be in the query or anchor. 3902 // 2) The URL's path could have a "/./" or a "/../" or a "//" sequence in it. 3903 3904 // FIXME: needsTrailingSlash does not properly return true for a URL that has no path, but does 3905 // have a query or anchor. 3906 3907 bool hasColonSlashSlash = containsColonSlashSlash(characters, length); 3908 3909 if (hasColonSlashSlash && !needsTrailingSlash(characters, length)) 3910 return AlreadyHashed::avoidDeletedValue(attributeURL.string().impl()->hash()); 3911 3912 Vector<UChar, 512> buffer; 3913 3914 if (hasColonSlashSlash) { 3915 // FIXME: This is incorrect for URLs that have a query or anchor; the "/" needs to go at the 3916 // end of the path, *before* the query or anchor. 3917 buffer.append(characters, length); 3918 buffer.append('/'); 3919 return AlreadyHashed::avoidDeletedValue(StringImpl::computeHash(buffer.data(), buffer.size())); 3920 } 3921 3922 switch (characters[0]) { 3923 case '/': 3924 buffer.append(m_baseURL.string().characters(), m_baseURL.pathStart()); 3925 break; 3926 case '#': 3927 buffer.append(m_baseURL.string().characters(), m_baseURL.pathEnd()); 3928 break; 3929 default: 3930 buffer.append(m_baseURL.string().characters(), m_baseURL.pathAfterLastSlash()); 3931 break; 3932 } 3933 buffer.append(characters, length); 3934 cleanPath(buffer); 3935 if (needsTrailingSlash(buffer.data(), buffer.size())) { 3936 // FIXME: This is incorrect for URLs that have a query or anchor; the "/" needs to go at the 3937 // end of the path, *before* the query or anchor. 3938 buffer.append('/'); 3939 } 3940 3941 return AlreadyHashed::avoidDeletedValue(StringImpl::computeHash(buffer.data(), buffer.size())); 3942 } 3943 3774 3944 #if ENABLE(DATABASE) 3775 3945 -
trunk/WebCore/dom/Document.h
r30633 r30949 383 383 void setBaseTarget(const String& baseTarget) { m_baseTarget = baseTarget; } 384 384 385 KURL completeURL(const String&); 385 KURL completeURL(const String&) const; 386 387 unsigned visitedLinkHash(const AtomicString& attributeURL) const; 386 388 387 389 // from cachedObjectClient -
trunk/WebCore/loader/FrameLoader.cpp
r30923 r30949 1808 1808 } 1809 1809 1810 // This does the same kind of work that FrameLoader::openURL does, except it relies on the fact1810 // This does the same kind of work that didOpenURL does, except it relies on the fact 1811 1811 // that a higher level already checked that the URLs match and the scrolling is the right thing to do. 1812 1812 void FrameLoader::scrollToAnchor(const KURL& url) 1813 1813 { 1814 1814 m_URL = url; 1815 updateHistoryForAnchorScroll(); 1815 1816 started(); 1816 1817 1817 gotoAnchor(); 1818 1818 … … 4382 4382 } 4383 4383 4384 void FrameLoader::updateHistoryForAnchorScroll() 4385 { 4386 if (m_URL.isEmpty()) 4387 return; 4388 4389 Settings* settings = m_frame->settings(); 4390 if (!settings || settings->privateBrowsingEnabled()) 4391 return; 4392 4393 Page* page = m_frame->page(); 4394 if (!page) 4395 return; 4396 4397 page->group().addVisitedLink(m_URL); 4398 } 4399 4384 4400 // Walk the frame tree, telling all frames to save their form state into their current 4385 4401 // history item. -
trunk/WebCore/loader/FrameLoader.h
r30840 r30949 456 456 void updateHistoryForClientRedirect(); 457 457 void updateHistoryForCommit(); 458 void updateHistoryForAnchorScroll(); 458 459 459 460 void redirectionTimerFired(Timer<FrameLoader>*); -
trunk/WebCore/page/DOMWindow.cpp
r30923 r30949 617 617 618 618 if (!pseudoElt.isEmpty()) 619 return doc->styleSelector()->pseudoStyleRulesForElement(elt, pseudoElt .impl(), authorOnly);619 return doc->styleSelector()->pseudoStyleRulesForElement(elt, pseudoElt, authorOnly); 620 620 return doc->styleSelector()->styleRulesForElement(elt, authorOnly); 621 621 } -
trunk/WebCore/page/Page.cpp
r30923 r30949 25 25 #include "ContextMenuClient.h" 26 26 #include "ContextMenuController.h" 27 #include "CSSStyleSelector.h" 27 28 #include "EditorClient.h" 28 29 #include "DOMWindow.h" … … 422 423 } 423 424 425 void Page::allVisitedStateChanged(PageGroup* group) 426 { 427 ASSERT(group); 428 ASSERT(allPages); 429 HashSet<Page*>::iterator pagesEnd = allPages->end(); 430 for (HashSet<Page*>::iterator it = allPages->begin(); it != pagesEnd; ++it) { 431 Page* page = *it; 432 if (page->m_group != group) 433 continue; 434 for (Frame* frame = page->m_mainFrame.get(); frame; frame = frame->tree()->traverseNext()) { 435 if (CSSStyleSelector* styleSelector = frame->document()->styleSelector()) 436 styleSelector->allVisitedStateChanged(); 437 } 438 } 439 } 440 441 void Page::visitedStateChanged(PageGroup* group, unsigned visitedLinkHash) 442 { 443 ASSERT(group); 444 ASSERT(allPages); 445 HashSet<Page*>::iterator pagesEnd = allPages->end(); 446 for (HashSet<Page*>::iterator it = allPages->begin(); it != pagesEnd; ++it) { 447 Page* page = *it; 448 if (page->m_group != group) 449 continue; 450 for (Frame* frame = page->m_mainFrame.get(); frame; frame = frame->tree()->traverseNext()) { 451 if (CSSStyleSelector* styleSelector = frame->document()->styleSelector()) 452 styleSelector->visitedStateChanged(visitedLinkHash); 453 } 454 } 455 } 456 424 457 void Page::setDebuggerForAllPages(KJS::Debugger* debugger) 425 458 { -
trunk/WebCore/page/Page.h
r30923 r30949 154 154 static void removeAllVisitedLinks(); 155 155 156 static void allVisitedStateChanged(PageGroup*); 157 static void visitedStateChanged(PageGroup*, unsigned visitedHash); 158 156 159 private: 157 160 void initGroup(); -
trunk/WebCore/page/PageGroup.cpp
r30873 r30949 37 37 static bool shouldTrackVisitedLinks; 38 38 39 // To use a hash value as a key for a hash table, we need to eliminate the40 // "deleted" value, which is negative one. That could be done by changing41 // the hash function to never generate negative one, but this works and is42 // still relatively efficient.43 static inline unsigned avoidDeletedValue(unsigned hash)44 {45 ASSERT(hash);46 unsigned newHash = hash | (!(hash + 1) << 31);47 ASSERT(newHash);48 ASSERT(newHash != 0xFFFFFFFF);49 return newHash;50 }51 52 39 PageGroup::PageGroup(Page* page) 53 40 : m_visitedLinksPopulated(false) … … 71 58 } 72 59 73 static inline int findSlashDotDotSlash(const UChar* characters, size_t length) 74 { 75 if (length < 4) 76 return -1; 77 unsigned loopLimit = length - 3; 78 for (unsigned i = 0; i < loopLimit; ++i) { 79 if (characters[i] == '/' && characters[i + 1] == '.' && characters[i + 2] == '.' && characters[i + 3] == '/') 80 return i; 81 } 82 return -1; 83 } 84 85 static inline int findSlashSlash(const UChar* characters, size_t length, int position) 86 { 87 if (length < 2) 88 return -1; 89 unsigned loopLimit = length - 1; 90 for (unsigned i = position; i < loopLimit; ++i) { 91 if (characters[i] == '/' && characters[i + 1] == '/') 92 return i; 93 } 94 return -1; 95 } 96 97 static inline int findSlashDotSlash(const UChar* characters, size_t length) 98 { 99 if (length < 3) 100 return -1; 101 unsigned loopLimit = length - 2; 102 for (unsigned i = 0; i < loopLimit; ++i) { 103 if (characters[i] == '/' && characters[i + 1] == '.' && characters[i + 2] == '/') 104 return i; 105 } 106 return -1; 107 } 108 109 static inline bool containsColonSlashSlash(const UChar* characters, unsigned length) 110 { 111 if (length < 3) 112 return false; 113 unsigned loopLimit = length - 2; 114 for (unsigned i = 0; i < loopLimit; ++i) { 115 if (characters[i] == ':' && characters[i + 1] == '/' && characters[i + 2] == '/') 116 return true; 117 } 118 return false; 119 } 120 121 static inline void cleanPath(Vector<UChar, 512>& path) 122 { 123 // FIXME: Shold not do this in the query or anchor part. 124 int pos; 125 while ((pos = findSlashDotDotSlash(path.data(), path.size())) != -1) { 126 int prev = reverseFind(path.data(), path.size(), '/', pos - 1); 127 // don't remove the host, i.e. http://foo.org/../foo.html 128 if (prev < 0 || (prev > 3 && path[prev - 2] == ':' && path[prev - 1] == '/')) 129 path.remove(pos, 3); 130 else 131 path.remove(prev, pos - prev + 3); 132 } 133 134 // FIXME: Shold not do this in the query part. 135 // Set refPos to -2 to mean "I haven't looked for the anchor yet". 136 // We don't want to waste a function call on the search for the the anchor 137 // in the vast majority of cases where there is no "//" in the path. 138 pos = 0; 139 int refPos = -2; 140 while ((pos = findSlashSlash(path.data(), path.size(), pos)) != -1) { 141 if (refPos == -2) 142 refPos = find(path.data(), path.size(), '#'); 143 if (refPos > 0 && pos >= refPos) 144 break; 145 146 if (pos == 0 || path[pos - 1] != ':') 147 path.remove(pos); 148 else 149 pos += 2; 150 } 151 152 // FIXME: Shold not do this in the query or anchor part. 153 while ((pos = findSlashDotSlash(path.data(), path.size())) != -1) 154 path.remove(pos, 2); 155 } 156 157 static inline bool matchLetter(UChar c, UChar lowercaseLetter) 158 { 159 return (c | 0x20) == lowercaseLetter; 160 } 161 162 static inline bool needsTrailingSlash(const UChar* characters, unsigned length) 163 { 164 if (length < 6) 165 return false; 166 if (!matchLetter(characters[0], 'h') 167 || !matchLetter(characters[1], 't') 168 || !matchLetter(characters[2], 't') 169 || !matchLetter(characters[3], 'p')) 170 return false; 171 if (!(characters[4] == ':' 172 || (matchLetter(characters[4], 's') && characters[5] == ':'))) 173 return false; 174 175 unsigned pos = characters[4] == ':' ? 5 : 6; 176 177 // Skip initial two slashes if present. 178 if (pos + 1 < length && characters[pos] == '/' && characters[pos + 1] == '/') 179 pos += 2; 180 181 // Find next slash. 182 while (pos < length && characters[pos] != '/') 183 ++pos; 184 185 return pos == length; 186 } 187 188 bool PageGroup::isLinkVisited(Document* document, const AtomicString& attributeURL) 60 bool PageGroup::isLinkVisited(unsigned visitedLinkHash) 189 61 { 190 62 if (!m_visitedLinksPopulated) { … … 193 65 (*m_pages.begin())->chrome()->client()->populateVisitedLinks(); 194 66 } 67 return m_visitedLinkHashes.contains(visitedLinkHash); 68 } 195 69 196 const UChar* characters = attributeURL.characters(); 197 unsigned length = attributeURL.length(); 198 if (!length) 199 return false; 200 201 // FIXME: It is wrong that we do not do further processing on strings that have "://" in them: 202 // 1) The "://" could be in the query or anchor. 203 // 2) The URL's path could have a "/./" or a "/../" or a "//" sequence in it. 204 205 // FIXME: needsTrailingSlash does not properly return true for a URL that has no path, but does 206 // have a query or anchor. 207 208 bool hasColonSlashSlash = containsColonSlashSlash(characters, length); 209 210 if (hasColonSlashSlash && !needsTrailingSlash(characters, length)) 211 return m_visitedLinkHashes.contains(avoidDeletedValue(attributeURL.string().impl()->hash())); 212 213 Vector<UChar, 512> buffer; 214 215 // This is a poor man's completeURL. Faster with less memory allocation. 216 // FIXME: It's missing a lot of what completeURL does and what KURL does. 217 // FIXME: Move this into KURL? Or Document? Even the fast version should be in the right place, 218 // rather than here. 219 220 if (hasColonSlashSlash) { 221 // FIXME: This is incorrect for URLs that have a query or anchor; the "/" needs to go at the 222 // end of the path, *before* the query or anchor. 223 buffer.append(characters, length); 224 buffer.append('/'); 225 return m_visitedLinkHashes.contains(avoidDeletedValue(StringImpl::computeHash(buffer.data(), buffer.size()))); 226 } 227 228 const KURL& baseURL = document->baseURL(); 229 switch (characters[0]) { 230 case '/': 231 buffer.append(baseURL.string().characters(), baseURL.pathStart()); 232 break; 233 case '#': 234 buffer.append(baseURL.string().characters(), baseURL.pathEnd()); 235 break; 236 default: 237 buffer.append(baseURL.string().characters(), baseURL.pathAfterLastSlash()); 238 break; 239 } 240 buffer.append(characters, length); 241 cleanPath(buffer); 242 if (needsTrailingSlash(buffer.data(), buffer.size())) { 243 // FIXME: This is incorrect for URLs that have a query or anchor; the "/" needs to go at the 244 // end of the path, *before* the query or anchor. 245 buffer.append('/'); 246 } 247 248 return m_visitedLinkHashes.contains(avoidDeletedValue(StringImpl::computeHash(buffer.data(), buffer.size()))); 70 inline void PageGroup::addVisitedLink(unsigned stringHash) 71 { 72 ASSERT(shouldTrackVisitedLinks); 73 unsigned visitedLinkHash = AlreadyHashed::avoidDeletedValue(stringHash); 74 if (!m_visitedLinkHashes.add(visitedLinkHash).second) 75 return; 76 Page::visitedStateChanged(this, visitedLinkHash); 249 77 } 250 78 … … 254 82 return; 255 83 ASSERT(!url.isEmpty()); 256 m_visitedLinkHashes.add(avoidDeletedValue(url.string().impl()->hash()));84 addVisitedLink(url.string().impl()->hash()); 257 85 } 258 86 … … 261 89 if (!shouldTrackVisitedLinks) 262 90 return; 263 m_visitedLinkHashes.add(avoidDeletedValue(StringImpl::computeHash(characters, length)));91 addVisitedLink(StringImpl::computeHash(characters, length)); 264 92 } 265 93 266 94 void PageGroup::removeVisitedLinks() 267 95 { 96 m_visitedLinksPopulated = false; 97 if (m_visitedLinkHashes.isEmpty()) 98 return; 268 99 m_visitedLinkHashes.clear(); 269 m_visitedLinksPopulated = false;100 Page::allVisitedStateChanged(this); 270 101 } 271 102 -
trunk/WebCore/page/PageGroup.h
r30873 r30949 29 29 #include <wtf/HashSet.h> 30 30 #include <wtf/Noncopyable.h> 31 #include <wtf/unicode/Unicode.h>31 #include "StringHash.h" 32 32 33 33 namespace WebCore { 34 34 35 class AtomicString;36 class Document;37 35 class KURL; 38 36 class Page; 39 40 struct AlreadyHashed : IntHash<unsigned> {41 static unsigned hash(unsigned key) { return key; }42 };43 37 44 38 class PageGroup : Noncopyable { … … 51 45 void removePage(Page*); 52 46 53 bool isLinkVisited( Document*, const AtomicString& attributeValue);47 bool isLinkVisited(unsigned visitedLinkHash); 54 48 55 49 void addVisitedLink(const KURL&); … … 61 55 62 56 private: 57 void addVisitedLink(unsigned stringHash); 58 63 59 HashSet<Page*> m_pages; 64 60 HashSet<unsigned, AlreadyHashed> m_visitedLinkHashes; -
trunk/WebCore/platform/text/StringHash.h
r29098 r30949 1 1 /* 2 * Copyright (C) 2006, 2007 Apple Inc. All rights reserved2 * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved 3 3 * 4 4 * This library is free software; you can redistribute it and/or … … 28 28 29 29 namespace WebCore { 30 31 // FIXME: We should really figure out a way to put the computeHash function that's 32 // currently a member function of StringImpl into this file so we can be a little 33 // cloer to having all the nearly-identical hash functions in one place. 30 34 31 35 struct StringHash { … … 79 83 // Paul Hsieh's SuperFastHash 80 84 // http://www.azillionmonkeys.com/qed/hash.html 85 static unsigned hash(const UChar* data, unsigned length) 86 { 87 unsigned l = length; 88 const UChar* s = data; 89 uint32_t hash = PHI; 90 uint32_t tmp; 91 92 int rem = l & 1; 93 l >>= 1; 94 95 // Main loop. 96 for (; l > 0; l--) { 97 hash += WTF::Unicode::foldCase(s[0]); 98 tmp = (WTF::Unicode::foldCase(s[1]) << 11) ^ hash; 99 hash = (hash << 16) ^ tmp; 100 s += 2; 101 hash += hash >> 11; 102 } 103 104 // Handle end case. 105 if (rem) { 106 hash += WTF::Unicode::foldCase(s[0]); 107 hash ^= hash << 11; 108 hash += hash >> 17; 109 } 110 111 // Force "avalanching" of final 127 bits. 112 hash ^= hash << 3; 113 hash += hash >> 5; 114 hash ^= hash << 2; 115 hash += hash >> 15; 116 hash ^= hash << 10; 117 118 // This avoids ever returning a hash code of 0, since that is used to 119 // signal "hash not computed yet", using a value that is likely to be 120 // effectively the same as 0 when the low bits are masked. 121 hash |= !hash << 31; 122 123 return hash; 124 } 125 81 126 static unsigned hash(StringImpl* str) 82 127 { 83 unsigned l = str->length(); 84 const UChar* s = str->characters(); 128 return hash(str->characters(), str->length()); 129 } 130 131 static unsigned hash(const char* str, unsigned length) 132 { 133 // This hash is designed to work on 16-bit chunks at a time. But since the normal case 134 // (above) is to hash UTF-16 characters, we just treat the 8-bit chars as if they 135 // were 16-bit chunks, which will give matching results. 136 137 unsigned l = length; 138 const char* s = str; 85 139 uint32_t hash = PHI; 86 140 uint32_t tmp; … … 115 169 // signal "hash not computed yet", using a value that is likely to be 116 170 // effectively the same as 0 when the low bits are masked 117 if (hash == 0) 118 hash = 0x80000000; 119 120 return hash; 121 } 122 123 static unsigned hash(const char* str, unsigned length) 124 { 125 // This hash is designed to work on 16-bit chunks at a time. But since the normal case 126 // (above) is to hash UTF-16 characters, we just treat the 8-bit chars as if they 127 // were 16-bit chunks, which will give matching results. 128 129 unsigned l = length; 130 const char* s = str; 131 uint32_t hash = PHI; 132 uint32_t tmp; 133 134 int rem = l & 1; 135 l >>= 1; 136 137 // Main loop 138 for (; l > 0; l--) { 139 hash += WTF::Unicode::foldCase(s[0]); 140 tmp = (WTF::Unicode::foldCase(s[1]) << 11) ^ hash; 141 hash = (hash << 16) ^ tmp; 142 s += 2; 143 hash += hash >> 11; 144 } 145 146 // Handle end case 147 if (rem) { 148 hash += WTF::Unicode::foldCase(s[0]); 149 hash ^= hash << 11; 150 hash += hash >> 17; 151 } 152 153 // Force "avalanching" of final 127 bits 154 hash ^= hash << 3; 155 hash += hash >> 5; 156 hash ^= hash << 2; 157 hash += hash >> 15; 158 hash ^= hash << 10; 159 160 // this avoids ever returning a hash code of 0, since that is used to 161 // signal "hash not computed yet", using a value that is likely to be 162 // effectively the same as 0 when the low bits are masked 163 if (hash == 0) 164 hash = 0x80000000; 171 hash |= !hash << 31; 165 172 166 173 return hash; … … 199 206 200 207 static const bool safeToCompareToEmptyOrDeleted = false; 208 }; 209 210 // This hash can be used in cases where the key is a hash of a string, but we don't 211 // want to store the string. It's not really specific to string hashing, but all our 212 // current uses of it are for strings. 213 struct AlreadyHashed : IntHash<unsigned> { 214 static unsigned hash(unsigned key) { return key; } 215 216 // To use a hash value as a key for a hash table, we need to eliminate the 217 // "deleted" value, which is negative one. That could be done by changing 218 // the string hash function to never generate negative one, but this works 219 // and is still relatively efficient. 220 static unsigned avoidDeletedValue(unsigned hash) 221 { 222 ASSERT(hash); 223 unsigned newHash = hash | (!(hash + 1) << 31); 224 ASSERT(newHash); 225 ASSERT(newHash != 0xFFFFFFFF); 226 return newHash; 227 } 201 228 }; 202 229 -
trunk/WebCore/rendering/RenderStyle.cpp
r30667 r30949 1067 1067 bool RenderStyle::isStyleAvailable() const 1068 1068 { 1069 return this != CSSStyleSelector:: m_styleNotYetAvailable;1069 return this != CSSStyleSelector::styleNotYetAvailable(); 1070 1070 } 1071 1071
Note:
See TracChangeset
for help on using the changeset viewer.