Changeset 249535 in webkit
- Timestamp:
- Sep 5, 2019, 10:44:38 AM (7 years ago)
- Location:
- trunk
- Files:
-
- 3 added
- 8 edited
-
LayoutTests/ChangeLog (modified) (1 diff)
-
LayoutTests/editing/pasteboard/paste-cocoa-writer-markup-with-webkit-standard-font-family-expected.txt (added)
-
LayoutTests/editing/pasteboard/paste-cocoa-writer-markup-with-webkit-standard-font-family.html (added)
-
Source/WebCore/ChangeLog (modified) (1 diff)
-
Source/WebCore/editing/EditingStyle.cpp (modified) (5 diffs)
-
Source/WebCore/editing/EditingStyle.h (modified) (3 diffs)
-
Source/WebCore/editing/markup.cpp (modified) (10 diffs)
-
Tools/ChangeLog (modified) (1 diff)
-
Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj (modified) (4 diffs)
-
Tools/TestWebKitAPI/Tests/WebKitCocoa/PasteHTML.mm (modified) (1 diff)
-
Tools/TestWebKitAPI/Tests/WebKitCocoa/cocoa-writer-markup-with-lists.html (added)
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r249534 r249535 1 2019-09-05 Ryosuke Niwa <rniwa@webkit.org> 2 3 REGRESSION (iOS 13): Bulleted list copied from Notes to Mail results in Times New Roman 4 https://bugs.webkit.org/show_bug.cgi?id=201490 5 6 Reviewed by Daniel Bates. 7 8 Added a test to make sure -webkit-standard font family name isn't stripped away when sanitization is not in effect. 9 10 * editing/pasteboard/paste-cocoa-writer-markup-with-webkit-standard-font-family-expected.txt: Added. 11 * editing/pasteboard/paste-cocoa-writer-markup-with-webkit-standard-font-family.html: Added. 12 1 13 2019-09-05 Chris Fleizach <cfleizach@apple.com> 2 14 -
trunk/Source/WebCore/ChangeLog
r249534 r249535 1 2019-09-05 Ryosuke Niwa <rniwa@webkit.org> 2 3 REGRESSION (iOS 13): Bulleted list copied from Notes to Mail results in Times New Roman 4 https://bugs.webkit.org/show_bug.cgi?id=201490 5 6 Reviewed by Daniel Bates. 7 8 The bug was caused by an element in the pasted content not having any explicit font name resolving 9 to use the font-family value of `-webkit-standard`. When such an inline style is inserted into 10 Mail's WKWebView which sets a different font family, ReplaceSelectionCommand would fail to strip away, 11 making the pasted content using the default font family of Times New Roman. 12 13 Fixed the bug by stripping away font-family set to -webkit-standard in the sanitization document 14 since that's indicative of the pasted content not having any font family being specified. 15 16 In the future, we should consider making regular copy (as opposed to the copy for sanitization) 17 resolve generic font family names to concrete font names since different WKWebView might be using 18 different concrete font names. Unfortuantely, such a change is quite involved and risky since various 19 paste side code in EditingStyle that removes redundant inline styles (i.e. redundant `font-family`) 20 need to be aware of this special font family resolution. 21 22 Tests: editing/pasteboard/paste-cocoa-writer-markup-with-webkit-standard-font-family.html 23 PasteHTML.DoesNotAddStandardFontFamily 24 25 * editing/EditingStyle.cpp: 26 (WebCore::EditingStyle::mergeInlineAndImplicitStyleOfElement): 27 (WebCore::EditingStyle::wrappingStyleForSerialization): 28 (WebCore::familyNameFromCSSPrimitiveValue): Added. 29 (WebCore::loneFontFamilyName): Extracted from usesForbiddenSystemFontAsOnlyFontFamilyName. Fixed 30 a bug that it was not handling the case when `font-family` property's value is a CSSPrimitiveValue 31 instead of a CSSValueList. 32 (WebCore::usesForbiddenSystemFontAsOnlyFontFamilyName): Deleted. 33 (WebCore::EditingStyle::mergeStyleFromRulesForSerialization): Remove `font-family` property when 34 StandardFontFamilySerializationMode::Strip is specified and its value is `-webkit-standard`. 35 * editing/EditingStyle.h: 36 * editing/markup.cpp: 37 (WebCore::StyledMarkupAccumulator::StyledMarkupAccumulator): Added 38 StandardFontFamilySerializationMode as an argument. 39 (WebCore::StyledMarkupAccumulator::appendStartTag): 40 (WebCore::StyledMarkupAccumulator::serializeNodes): 41 (WebCore::serializePreservingVisualAppearanceInternal): Ditto. 42 (WebCore::serializePreservingVisualAppearance): Use StandardFontFamilySerializationMode::Keep 43 to preserve the pre-existing behavior. 44 (WebCore::sanitizedMarkupForFragmentInDocument): Use StandardFontFamilySerializationMode::Strip 45 as this is the code used by sanitization code. 46 1 47 2019-09-05 Chris Fleizach <cfleizach@apple.com> 2 48 -
trunk/Source/WebCore/editing/EditingStyle.cpp
r249517 r249535 1158 1158 } 1159 1159 1160 void EditingStyle::mergeInlineAndImplicitStyleOfElement(StyledElement& element, CSSPropertyOverrideMode mode, PropertiesToInclude propertiesToInclude )1160 void EditingStyle::mergeInlineAndImplicitStyleOfElement(StyledElement& element, CSSPropertyOverrideMode mode, PropertiesToInclude propertiesToInclude, StandardFontFamilySerializationMode standardFontFamilySerializationMode) 1161 1161 { 1162 1162 auto styleFromRules = EditingStyle::create(); 1163 styleFromRules->mergeStyleFromRulesForSerialization(element );1163 styleFromRules->mergeStyleFromRulesForSerialization(element, standardFontFamilySerializationMode); 1164 1164 1165 1165 if (element.inlineStyle()) … … 1182 1182 } 1183 1183 1184 Ref<EditingStyle> EditingStyle::wrappingStyleForSerialization(Node& context, bool shouldAnnotate )1184 Ref<EditingStyle> EditingStyle::wrappingStyleForSerialization(Node& context, bool shouldAnnotate, StandardFontFamilySerializationMode standardFontFamilySerializationMode) 1185 1185 { 1186 1186 if (shouldAnnotate) { … … 1203 1203 for (Node* node = &context; node && !node->isDocumentNode(); node = node->parentNode()) { 1204 1204 if (is<StyledElement>(*node) && !isMailBlockquote(node)) 1205 wrappingStyle->mergeInlineAndImplicitStyleOfElement(downcast<StyledElement>(*node), EditingStyle::DoNotOverrideValues, EditingStyle::EditingPropertiesInEffect);1205 wrappingStyle->mergeInlineAndImplicitStyleOfElement(downcast<StyledElement>(*node), DoNotOverrideValues, EditingPropertiesInEffect, standardFontFamilySerializationMode); 1206 1206 } 1207 1207 … … 1283 1283 } 1284 1284 1285 static bool usesForbiddenSystemFontAsOnlyFontFamilyName(CSSValue& value) 1286 { 1285 static String familyNameFromCSSPrimitiveValue(const CSSPrimitiveValue& primitiveValue) 1286 { 1287 if (!primitiveValue.isFontFamily()) 1288 return { }; 1289 return primitiveValue.fontFamily().familyName; 1290 } 1291 1292 static String loneFontFamilyName(const CSSValue& value) 1293 { 1294 if (is<CSSPrimitiveValue>(value)) 1295 return familyNameFromCSSPrimitiveValue(downcast<CSSPrimitiveValue>(value)); 1296 1287 1297 if (!is<CSSValueList>(value) || downcast<CSSValueList>(value).length() != 1) 1288 return false;1298 return { }; 1289 1299 1290 1300 auto& item = *downcast<CSSValueList>(value).item(0); 1291 1301 if (!is<CSSPrimitiveValue>(item)) 1292 return false; 1293 1294 auto& primitiveValue = downcast<CSSPrimitiveValue>(item); 1295 if (!primitiveValue.isFontFamily()) 1296 return false; 1297 return FontCache::isSystemFontForbiddenForEditing(primitiveValue.fontFamily().familyName); 1298 } 1299 1300 void EditingStyle::mergeStyleFromRulesForSerialization(StyledElement& element) 1302 return { }; 1303 1304 return familyNameFromCSSPrimitiveValue(downcast<CSSPrimitiveValue>(item)); 1305 } 1306 1307 void EditingStyle::mergeStyleFromRulesForSerialization(StyledElement& element, StandardFontFamilySerializationMode standardFontFamilySerializationMode) 1301 1308 { 1302 1309 mergeStyleFromRules(element); … … 1314 1321 StyleProperties::PropertyReference property = m_mutableStyle->propertyAt(i); 1315 1322 CSSValue& value = *property.value(); 1316 if (property.id() == CSSPropertyFontFamily && usesForbiddenSystemFontAsOnlyFontFamilyName(value)) { 1317 shouldRemoveFontFamily = true; 1323 if (property.id() == CSSPropertyFontFamily) { 1324 auto familyName = loneFontFamilyName(value); 1325 if (FontCache::isSystemFontForbiddenForEditing(familyName) 1326 || (standardFontFamilySerializationMode == StandardFontFamilySerializationMode::Strip && familyName == standardFamily)) 1327 shouldRemoveFontFamily = true; 1318 1328 continue; 1319 1329 } -
trunk/Source/WebCore/editing/EditingStyle.h
r242776 r249535 61 61 enum class TextDecorationChange { None, Add, Remove }; 62 62 63 // FIXME: "Keep" should be "Resolve" instead and resolve all generic font family names. 64 enum class StandardFontFamilySerializationMode : uint8_t { Keep, Strip }; 65 63 66 class EditingStyle : public RefCounted<EditingStyle> { 64 67 public: … … 142 145 enum CSSPropertyOverrideMode { OverrideValues, DoNotOverrideValues }; 143 146 void mergeInlineStyleOfElement(StyledElement&, CSSPropertyOverrideMode, PropertiesToInclude = AllProperties); 144 static Ref<EditingStyle> wrappingStyleForSerialization(Node& context, bool shouldAnnotate );147 static Ref<EditingStyle> wrappingStyleForSerialization(Node& context, bool shouldAnnotate, StandardFontFamilySerializationMode); 145 148 void mergeStyleFromRules(StyledElement&); 146 void mergeStyleFromRulesForSerialization(StyledElement& );149 void mergeStyleFromRulesForSerialization(StyledElement&, StandardFontFamilySerializationMode); 147 150 void removeStyleFromRulesAndContext(StyledElement&, Node* context); 148 151 void removePropertiesInElementDefaultStyle(Element&); … … 182 185 template<typename T> TriState triStateOfStyle(T& styleToCompare, ShouldIgnoreTextOnlyProperties) const; 183 186 bool conflictsWithInlineStyleOfElement(StyledElement&, RefPtr<MutableStyleProperties>* newInlineStyle, EditingStyle* extractedStyle) const; 184 void mergeInlineAndImplicitStyleOfElement(StyledElement&, CSSPropertyOverrideMode, PropertiesToInclude );187 void mergeInlineAndImplicitStyleOfElement(StyledElement&, CSSPropertyOverrideMode, PropertiesToInclude, StandardFontFamilySerializationMode); 185 188 void mergeStyle(const StyleProperties*, CSSPropertyOverrideMode); 186 189 -
trunk/Source/WebCore/editing/markup.cpp
r248846 r249535 223 223 224 224 StyledMarkupAccumulator(const Position& start, const Position& end, Vector<Node*>* nodes, ResolveURLs, SerializeComposedTree, 225 AnnotateForInterchange, MSOListMode, bool needsPositionStyleConversion, Node* highestNodeToBeSerialized = nullptr);225 AnnotateForInterchange, StandardFontFamilySerializationMode, MSOListMode, bool needsPositionStyleConversion, Node* highestNodeToBeSerialized = nullptr); 226 226 227 227 Node* serializeNodes(const Position& start, const Position& end); … … 319 319 bool m_useComposedTree; 320 320 bool m_needsPositionStyleConversion; 321 StandardFontFamilySerializationMode m_standardFontFamilySerializationMode; 322 bool m_shouldPreserveMSOList; 321 323 bool m_needRelativeStyleWrapper { false }; 322 324 bool m_needClearingDiv { false }; 323 bool m_shouldPreserveMSOList;324 325 bool m_inMSOList { false }; 325 326 }; 326 327 327 328 inline StyledMarkupAccumulator::StyledMarkupAccumulator(const Position& start, const Position& end, Vector<Node*>* nodes, ResolveURLs urlsToResolve, SerializeComposedTree serializeComposedTree, 328 AnnotateForInterchange annotate, MSOListMode msoListMode, bool needsPositionStyleConversion, Node* highestNodeToBeSerialized)329 AnnotateForInterchange annotate, StandardFontFamilySerializationMode standardFontFamilySerializationMode, MSOListMode msoListMode, bool needsPositionStyleConversion, Node* highestNodeToBeSerialized) 329 330 : MarkupAccumulator(nodes, urlsToResolve) 330 331 , m_start(start) … … 334 335 , m_useComposedTree(serializeComposedTree == SerializeComposedTree::Yes) 335 336 , m_needsPositionStyleConversion(needsPositionStyleConversion) 337 , m_standardFontFamilySerializationMode(standardFontFamilySerializationMode) 336 338 , m_shouldPreserveMSOList(msoListMode == MSOListMode::Preserve) 337 339 { … … 532 534 if (shouldAnnotateOrForceInline) { 533 535 if (shouldAnnotate()) 534 newInlineStyle->mergeStyleFromRulesForSerialization(downcast<HTMLElement>(*const_cast<Element*>(&element)) );536 newInlineStyle->mergeStyleFromRulesForSerialization(downcast<HTMLElement>(*const_cast<Element*>(&element)), m_standardFontFamilySerializationMode); 535 537 536 538 if (addDisplayInline) … … 580 582 581 583 if (m_highestNodeToBeSerialized && m_highestNodeToBeSerialized->parentNode()) 582 m_wrappingStyle = EditingStyle::wrappingStyleForSerialization(*m_highestNodeToBeSerialized->parentNode(), shouldAnnotate() );584 m_wrappingStyle = EditingStyle::wrappingStyleForSerialization(*m_highestNodeToBeSerialized->parentNode(), shouldAnnotate(), m_standardFontFamilySerializationMode); 583 585 584 586 return traverseNodesForSerialization(startNode.get(), pastEnd, NodeTraversalMode::EmitString); … … 823 825 824 826 static String serializePreservingVisualAppearanceInternal(const Position& start, const Position& end, Vector<Node*>* nodes, ResolveURLs urlsToResolve, SerializeComposedTree serializeComposedTree, 825 AnnotateForInterchange annotate, ConvertBlocksToInlines convertBlocksToInlines, MSOListMode msoListMode)827 AnnotateForInterchange annotate, ConvertBlocksToInlines convertBlocksToInlines, StandardFontFamilySerializationMode standardFontFamilySerializationMode, MSOListMode msoListMode) 826 828 { 827 829 static NeverDestroyed<const String> interchangeNewlineString(MAKE_STATIC_STRING_IMPL("<br class=\"" AppleInterchangeNewline "\">")); … … 849 851 Node* specialCommonAncestor = highestAncestorToWrapMarkup(start, end, *commonAncestor, annotate); 850 852 851 StyledMarkupAccumulator accumulator(start, end, nodes, urlsToResolve, serializeComposedTree, annotate, msoListMode, needsPositionStyleConversion, specialCommonAncestor);853 StyledMarkupAccumulator accumulator(start, end, nodes, urlsToResolve, serializeComposedTree, annotate, standardFontFamilySerializationMode, msoListMode, needsPositionStyleConversion, specialCommonAncestor); 852 854 853 855 Position startAdjustedForInterchangeNewline = start; … … 918 920 { 919 921 return serializePreservingVisualAppearanceInternal(range.startPosition(), range.endPosition(), nodes, urlsToReslve, SerializeComposedTree::No, 920 annotate, convertBlocksToInlines, MSOListMode::DoNotPreserve);922 annotate, convertBlocksToInlines, StandardFontFamilySerializationMode::Keep, MSOListMode::DoNotPreserve); 921 923 } 922 924 … … 924 926 { 925 927 return serializePreservingVisualAppearanceInternal(selection.start(), selection.end(), nodes, resolveURLs, serializeComposedTree, 926 AnnotateForInterchange::Yes, ConvertBlocksToInlines::No, MSOListMode::DoNotPreserve);928 AnnotateForInterchange::Yes, ConvertBlocksToInlines::No, StandardFontFamilySerializationMode::Keep, MSOListMode::DoNotPreserve); 927 929 } 928 930 … … 951 953 // SerializeComposedTree::No because there can't be a shadow tree in the pasted fragment. 952 954 auto result = serializePreservingVisualAppearanceInternal(firstPositionInNode(bodyElement.get()), lastPositionInNode(bodyElement.get()), nullptr, 953 ResolveURLs::YesExcludingLocalFileURLsForPrivacy, SerializeComposedTree::No, AnnotateForInterchange::Yes, ConvertBlocksToInlines::No, msoListMode);955 ResolveURLs::YesExcludingLocalFileURLsForPrivacy, SerializeComposedTree::No, AnnotateForInterchange::Yes, ConvertBlocksToInlines::No, StandardFontFamilySerializationMode::Strip, msoListMode); 954 956 955 957 if (msoListMode == MSOListMode::Preserve) { -
trunk/Tools/ChangeLog
r249525 r249535 1 2019-09-05 Ryosuke Niwa <rniwa@webkit.org> 2 3 REGRESSION (iOS 13): Bulleted list copied from Notes to Mail results in Times New Roman 4 https://bugs.webkit.org/show_bug.cgi?id=201490 5 6 Reviewed by Daniel Bates. 7 8 Added a test. 9 10 * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: 11 * TestWebKitAPI/Tests/WebKitCocoa/PasteHTML.mm: 12 * TestWebKitAPI/Tests/WebKitCocoa/cocoa-writer-markup-with-lists.html: Added. 13 1 14 2019-09-05 Ryosuke Niwa <rniwa@webkit.org> 2 15 -
trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj
r249525 r249535 734 734 9B7A37C41F8AEBA5004AA228 /* CopyURL.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9B7A37C21F8AEBA5004AA228 /* CopyURL.mm */; }; 735 735 9B7D740F1F8378770006C432 /* paste-rtfd.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 9B7D740E1F8377E60006C432 /* paste-rtfd.html */; }; 736 9B9332CE2320C745002D50E8 /* cocoa-writer-markup-with-lists.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 9B9332CD2320C73E002D50E8 /* cocoa-writer-markup-with-lists.html */; }; 736 737 9BAD7F3E22690F2000F8DA66 /* DeallocWebViewInEventListener.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9BAD7F3D22690F1400F8DA66 /* DeallocWebViewInEventListener.mm */; }; 737 738 9BAE177B22E2BBFB00DF3098 /* cocoa-writer-markup-with-system-fonts.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 9BAE177A22E2BB6B00DF3098 /* cocoa-writer-markup-with-system-fonts.html */; }; … … 1161 1162 1A50AA201A2A51FC00F4C345 /* close-from-within-create-page.html in Copy Resources */, 1162 1163 9B270FEE1DDC2C0B002D53F3 /* closed-shadow-tree-test.html in Copy Resources */, 1164 9B9332CE2320C745002D50E8 /* cocoa-writer-markup-with-lists.html in Copy Resources */, 1163 1165 9BAE177B22E2BBFB00DF3098 /* cocoa-writer-markup-with-system-fonts.html in Copy Resources */, 1164 1166 E5036F78211BC25400BFDBE2 /* color-drop.html in Copy Resources */, … … 2091 2093 9B7A37C21F8AEBA5004AA228 /* CopyURL.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = CopyURL.mm; sourceTree = "<group>"; }; 2092 2094 9B7D740E1F8377E60006C432 /* paste-rtfd.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "paste-rtfd.html"; sourceTree = "<group>"; }; 2095 9B9332CD2320C73E002D50E8 /* cocoa-writer-markup-with-lists.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "cocoa-writer-markup-with-lists.html"; sourceTree = "<group>"; }; 2093 2096 9BAD7F3D22690F1400F8DA66 /* DeallocWebViewInEventListener.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DeallocWebViewInEventListener.mm; sourceTree = "<group>"; }; 2094 2097 9BAE177A22E2BB6B00DF3098 /* cocoa-writer-markup-with-system-fonts.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "cocoa-writer-markup-with-system-fonts.html"; sourceTree = "<group>"; }; … … 3167 3170 2EFF06C61D886A560004BB30 /* change-video-source-on-end.html */, 3168 3171 839AA35E21A26ACD00980DD6 /* client-side-redirect.html */, 3172 9B9332CD2320C73E002D50E8 /* cocoa-writer-markup-with-lists.html */, 3169 3173 9BAE177A22E2BB6B00DF3098 /* cocoa-writer-markup-with-system-fonts.html */, 3170 3174 E5036F77211BC22800BFDBE2 /* color-drop.html */, -
trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/PasteHTML.mm
r249517 r249535 361 361 } 362 362 363 TEST(PasteHTML, DoesNotAddStandardFontFamily) 364 { 365 writeHTMLToPasteboard([NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"cocoa-writer-markup-with-lists" ofType:@"html" inDirectory:@"TestWebKitAPI.resources"] encoding:NSUTF8StringEncoding error:NULL]); 366 367 auto webView = createWebViewWithCustomPasteboardDataSetting(true); 368 [webView synchronouslyLoadTestPageNamed:@"paste-rtfd"]; 369 [webView stringByEvaluatingJavaScript:@"document.body.style.fontFamily = 'Arial'"]; 370 [webView paste:nil]; 371 372 EXPECT_WK_STREQ("[\"text/html\"]", [webView stringByEvaluatingJavaScript:@"JSON.stringify(clipboardData.types)"]); 373 [webView stringByEvaluatingJavaScript:@"window.htmlInDataTransfer = clipboardData.values[0]"]; 374 [webView stringByEvaluatingJavaScript:@"window.pastedHTML = editor.innerHTML"]; 375 376 EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"pastedHTML.includes('Hello')"].boolValue); 377 EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"pastedHTML.includes('font-weight: bold')"].boolValue); 378 EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"!pastedHTML.includes('-webkit-standard')"].boolValue); 379 380 EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"htmlInDataTransfer.includes('Hello')"].boolValue); 381 EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"htmlInDataTransfer.includes('font-weight: bold')"].boolValue); 382 EXPECT_TRUE([webView stringByEvaluatingJavaScript:@"!htmlInDataTransfer.includes('-webkit-standard')"].boolValue); 383 384 EXPECT_WK_STREQ([webView stringByEvaluatingJavaScript:@"getComputedStyle(document.querySelector('.s2')).fontFamily"], 385 [webView stringByEvaluatingJavaScript:@"getComputedStyle(document.body).fontFamily"]); 386 EXPECT_WK_STREQ([webView stringByEvaluatingJavaScript:@"getComputedStyle(document.querySelector('.s4')).fontFamily"], 387 [webView stringByEvaluatingJavaScript:@"getComputedStyle(document.body).fontFamily"]); 388 } 389 363 390 #if ENABLE(DARK_MODE_CSS) && HAVE(OS_DARK_MODE_SUPPORT) 364 391
Note:
See TracChangeset
for help on using the changeset viewer.