Chrome の marquee 要素が 優秀だった話

Chrome の marquee 要素が 優秀だった話

marquee の深みに迫ります。

Dc696687bae442425a220771df158346?s=128

tsuyoshi wada

March 29, 2018
Tweet

Transcript

  1. 2.

    ࣗݾ঺հ @wadackel / Θͩ ͭΑ͠ tsuyoshiwada https://blog.wadackel.me • Go Ͱ

    CHANGELOG δΣωϨʔλ࡞ͬͨΓ • Storybook ͱ Puppeteer ͰεΫϦʔϯγϣοτࡱͬͨΓ • CyberAgent, Inc. Ͱಇ͍͍ͯͨΓ͠·͢
  2. 14.

    Ξχϝʔγϣϯ͕։࢝͞Εͯ ͍ΔͩΖ͏෦෼ <method name="start" exposeToUntrustedContent="true"> <body> <![CDATA[ if (this.runId ==

    0) { var myThis = this; var lambda = function myTimeOutFunction(){myThis._doMove(false);} this.runId = window.setTimeout(lambda, this._scrollDelay - this._deltaStartStop); this._deltaStartStop = 0; } ]]> </body> </method> ࢀߟNP[JMMBHFDLPMBZPVUTUZMFYCMNBSRVFFYCMNBSRVFFYNM
  3. 15.

    Ξχϝʔγϣϯ͕։࢝͞Εͯ ͍ΔͩΖ͏෦෼ <method name="start" exposeToUntrustedContent="true"> <body> <![CDATA[ if (this.runId ==

    0) { var myThis = this; var lambda = function myTimeOutFunction(){myThis._doMove(false);} this.runId = window.setTimeout(lambda, this._scrollDelay - this._deltaStartStop); this._deltaStartStop = 0; } ]]> </body> </method> ࢀߟNP[JMMBHFDLPMBZPVUTUZMFYCMNBSRVFFYCMNBSRVFFYNM setTimeout() Λ࢖ͬͯ _doMove() Λݺͼग़ͯ͠Δ
  4. 16.

    _doMove() Λ௥ͬͯΈΔ <method name="_doMove"> <parameter name="aResetPosition"/> <body> <![CDATA[ // ...

    εΫϩʔϧҐஔͷࢉग़ϩδοΫ (௕͍ͷͰলུ) if ((this._direction == "up") || (this._direction == "down")) { this.outerDiv.scrollTop = this.newPosition; } else { this.outerDiv.scrollLeft = this.newPosition; } // ... ͦͷଞॲཧ ]]> </body> </method> ࢀߟNP[JMMBHFDLPMBZPVUTUZMFYCMNBSRVFFYCMNBSRVFFYNM
  5. 17.

    _doMove() Λ௥ͬͯΈΔ <method name="_doMove"> <parameter name="aResetPosition"/> <body> <![CDATA[ // ...

    εΫϩʔϧҐஔͷࢉग़ϩδοΫ (௕͍ͷͰলུ) if ((this._direction == "up") || (this._direction == "down")) { this.outerDiv.scrollTop = this.newPosition; } else { this.outerDiv.scrollLeft = this.newPosition; } // ... ͦͷଞॲཧ ]]> </body> </method> ࢀߟNP[JMMBHFDLPMBZPVUTUZMFYCMNBSRVFFYCMNBSRVFFYNM ཁૉͷ scrollTop, scrollLeft ʹ ࢉग़ͨ͠࠲ඪ஋Λࢦఆ͍ͯ͠Δ
  6. 18.
  7. 21.

    Ξχϝʔγϣϯ͕։࢝͞Εͯ ͍ΔͩΖ͏ίʔυ෦෼ void HTMLMarqueeElement::start() { if (continue_callback_request_id_) return; RequestAnimationFrameCallback* callback

    = new RequestAnimationFrameCallback(this); continue_callback_request_id_ = GetDocument().RequestAnimationFrame(callback); } ࢀߟDISPNJVNUIJSE@QBSUZ8FC,JU4PVSDFDPSFIUNM)5.-.BSRVFF&MFNFOUDQQ
  8. 22.

    Ξχϝʔγϣϯ͕։࢝͞Εͯ ͍ΔͩΖ͏ίʔυ෦෼ void HTMLMarqueeElement::start() { if (continue_callback_request_id_) return; RequestAnimationFrameCallback* callback

    = new RequestAnimationFrameCallback(this); continue_callback_request_id_ = GetDocument().RequestAnimationFrame(callback); } ࢀߟDISPNJVNUIJSE@QBSUZ8FC,JU4PVSDFDPSFIUNM)5.-.BSRVFF&MFNFOUDQQ requestAnimationFrame Λ ࢖ͬͯΔͬΆ͍!!
  9. 23.

    ֤ඳըϑϨʔϜͷॲཧΛ ௥ͬͯΈΔ void HTMLMarqueeElement::ContinueAnimation() { // ... લॲཧ (௕͍ͷͰলུ) AnimationParameters

    parameters = GetAnimationParameters(); int scroll_delay = scrollDelay(); int scroll_amount = scrollAmount(); // ... ࣮ࡍʹ࠲ඪΛద༻ͨ͠Γͯ͠Δ (௕͍ͷͰলུ) } ࢀߟDISPNJVNUIJSE@QBSUZ8FC,JU4PVSDFDPSFIUNM)5.-.BSRVFF&MFNFOUDQQ
  10. 24.

    ֤ඳըϑϨʔϜͷॲཧΛ ௥ͬͯΈΔ void HTMLMarqueeElement::ContinueAnimation() { // ... લॲཧ (௕͍ͷͰলུ) AnimationParameters

    parameters = GetAnimationParameters(); int scroll_delay = scrollDelay(); int scroll_amount = scrollAmount(); // ... ࣮ࡍʹ࠲ඪΛద༻ͨ͠Γͯ͠Δ (௕͍ͷͰলུ) } ࢀߟDISPNJVNUIJSE@QBSUZ8FC,JU4PVSDFDPSFIUNM)5.-.BSRVFF&MFNFOUDQQ Կ΍ΒΞχϝʔγϣϯ༻ͷ ύϥϝʔλΛ࡞͍ͬͯΔ
  11. 25.

    AnimationParameters ͷ ੜ੒ʹഭΔ HTMLMarqueeElement::GetAnimationParameters() { AnimationParameters parameters; Metrics metrics =

    GetMetrics(); // ... ௕͍ͨΊলུ!! parameters.transform_begin = CreateTransform(-metrics.content_width); parameters.transform_end = CreateTransform(metrics.marquee_width); // ... ௕͍ͨΊলུ!! } ࢀߟDISPNJVNUIJSE@QBSUZ8FC,JU4PVSDFDPSFIUNM)5.-.BSRVFF&MFNFOUDQQ
  12. 26.

    AnimationParameters ͷ ੜ੒ʹഭΔ HTMLMarqueeElement::GetAnimationParameters() { AnimationParameters parameters; Metrics metrics =

    GetMetrics(); // ... ௕͍ͨΊলུ!! parameters.transform_begin = CreateTransform(-metrics.content_width); parameters.transform_end = CreateTransform(metrics.marquee_width); // ... ௕͍ͨΊলུ!! } ࢀߟDISPNJVNUIJSE@QBSUZ8FC,JU4PVSDFDPSFIUNM)5.-.BSRVFF&MFNFOUDQQ Transform?? Λ࡞͍ͬͯΔΆ͍
  13. 27.

    ͞Βʹ͞Βʹ CreateTransform ʹഭΔ AtomicString HTMLMarqueeElement::CreateTransform(double value) const { char axis

    = IsHorizontal() ? 'X' : 'Y'; return String::Format("translate%c(", axis) + String::NumberToStringECMAScript(value) + "px)"; } ࢀߟDISPNJVNUIJSE@QBSUZ8FC,JU4PVSDFDPSFIUNM)5.-.BSRVFF&MFNFOUDQQ
  14. 28.

    ͞Βʹ͞Βʹ CreateTransform ʹഭΔ AtomicString HTMLMarqueeElement::CreateTransform(double value) const { char axis

    = IsHorizontal() ? 'X' : 'Y'; return String::Format("translate%c(", axis) + String::NumberToStringECMAScript(value) + "px)"; } ࢀߟDISPNJVNUIJSE@QBSUZ8FC,JU4PVSDFDPSFIUNM)5.-.BSRVFF&MFNFOUDQQ CSS ϓϩύςΟͰ͋Δ Transform ͷ஋Λੜ੒ͯͨ͠
  15. 30.

    ཁૉͷੜ੒ॲཧ void HTMLMarqueeElement::DidAddUserAgentShadowRoot(ShadowRoot& shadow_root) { auto* style = HTMLStyleElement::Create(GetDocument(), CreateElementFlags());

    style->setTextContent( ":host { display: inline-block; overflow: hidden;" "text-align: initial; white-space: nowrap; }" ":host([direction=\"up\"]), :host([direction=\"down\"]) { overflow: " "initial; overflow-y: hidden; white-space: initial; }" ":host > div { will-change: transform; }"); shadow_root.AppendChild(style); Element* mover = HTMLDivElement::Create(GetDocument()); shadow_root.AppendChild(mover); mover->AppendChild( HTMLSlotElement::CreateUserAgentDefaultSlot(GetDocument())); mover_ = mover; } ࢀߟDISPNJVNUIJSE@QBSUZ8FC,JU4PVSDFDPSFIUNM)5.-.BSRVFF&MFNFOUDQQ
  16. 32.

    ੜ੒͞ΕΔཁૉͷΠϝʔδ <marquee> #shadow-root <style> :host { display: inline-block; overflow: hidden;

    text-align: initial; white-space: nowrap; } :host([direction="up"]), :host([direction="down"]) { overflow: initial; overflow-y: hidden; white-space: initial; } :host > div { will-change: transform; } </style> <!-- ҎԼͷ div ͕ transform ϓϩύςΟͰΞχϝʔγϣϯ͢Δ --> <div> <slot></slot> </div> </marquee>
  17. 34.

    Chromium ͷ marquee ࣮૷ ͸૝૾ΑΓ΋Ϟμϯͩͬͨ… • ಺෦࣮૷͸ Web Components ͩͬͨ…!!

    • requestAnimationFrame ʹΑΔ࠶ඳըλΠϛϯάͷ࠷దԽ - ϧʔϓͱϒϥ΢βͷ࠶ඳըλΠϛϯά͕Ұக • ֤ϧʔϓͰͷ࠲ඪ͸ CSS ͷ transform ϓϩύςΟͰ؅ཧ͞Ε͍ͯͨ - ϨΠΞ΢τͷ࠶ܭࢉ͕ى͖ͳ͍ ✨
  18. 35.
  19. 36.

    ͍ʹ͑͠ͷཁૉ͸ࢥ͍ͷ΄͔ Ϟμϯͳٕज़Ͱಈ࡞͍ͯͨ͠ • ShadowDOM ʹΑΔελΠϧͷӅṭ • requestAnimationFrame ʹΑΔΞχϝʔγϣϯͷ੍ޚ • will-change

    Λ࢖ͬͨΞχϝʔγϣϯͷ࠷దԽ • transform/translate Λ࢖ͬͨ࠲ඪҠಈ (ඳըෛՙ࠷దԽ) • ීஈͷ Web ϑϩϯτΤϯυ։ൃʹ௨͡Δٕज़Ͱ
 ߏ੒͞Ε͍ͯͨ • ͋͘·Ͱ Chromium ͷதͰ͸Ͷ
  20. 37.

    ϒϥ΢βͷ࣮૷Λ೷͘ͷ͸ ҙ֎ͱָ͍͠!! • C++ ॻ͚ͳͯ͘΋ɺงғؾͰԿͱͳ͘ॻ͍ͯ͋Δ͜ͱ͕෼͔Δ • ίϝϯτ΋ͦͦ͜͜ॻ͔Ε͍ͯΔͷͰ • ΤσΟλΛ׆༻͢Δ -

    $ ctags --languages=C++ ͰλάΛ࡞ͬͯ… - vim Ͱఆٛδϟϯϓͯ͠ιʔείʔυ㓢኶͢Δͱָ • ripgrep Έ͍ͨͳߴ଎ͳ grep ୅ସπʔϧ΋༗༻ • https://cs.chromium.org ΋ศར