精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

從Chrome源碼看瀏覽器如何layout布局

開發 前端
由于寫html/css很多東西都是不透明,完全不知道背后是怎么工作的,只能是看文檔說這個標簽是怎么用的,那個屬性會有什么效果,然后在瀏覽器上面看效果,有點任瀏覽器宰割的感覺。所以這個源碼解讀就是為了能夠窺探瀏覽器背后工作原理,這樣對寫代碼會有幫助,能夠做到心中有數。當遇到一些比較困難的問題時,能夠很快的找到解決方案或者解決的方向。

假設有以下html/css:

<div style="border:1px solid #000; width:50%; height: 100px; margin: 0 auto"></div>

這在瀏覽器上面將顯示一個框:

為了畫出這個框,首先要知道從哪里開始畫、畫多大,其次是邊緣stroke的顏色,就可以把它畫出來了:

void draw(SkCanvas* canvas) {
    SkPaint paint;
    paint.setStrokeWidth(1);
    //從位置為(200, 200)的地方開始畫,寬度為400,高度為100
    SkRect rect = SkRect::MakeXYWH(200, 200, 400, 100);
    canvas->drawRect(rect, paint);
}

上面是用Skia畫的代碼,Skia是一個跨平臺的開源2D圖形庫,是Chrome/firefox/android采用的底層Paint引擎。

為了能夠獲取到具體的值,就得進行layout。什么叫layout?把css轉化成維度位置等可直接用來描繪的信息的過程就叫layout,如下Chrome源碼對layout的解釋:

// The purpose of the layout tree is to do layout (aka reflow) and store its
// results for painting and hit-testing. Layout is the process of sizing and
// positioning Nodes on the page.

從Chrome源碼看瀏覽器如何計算CSS》這篇文章介紹了怎么把css轉化成ComputedStyle,上面的div,它被轉化后的style如下所示:

width的大小是50,類型是百分比,而margin值是0,類型是auto,這兩種都不能直接用來畫的。所以需要通過layout計算出具體的數字。

 1. 建立layout樹

從Chrome源碼看瀏覽器如何構建DOM樹》這篇文章介紹了如何html文本的過程。當解析完收到的html片段后,會觸發Layout Tree的構建:

void Document::finishedParsing() {
      updateStyleAndLayoutTree();
}

每個非display:none/content的Node結點都會相應地創建一個LayoutObject,如下blink源碼的注釋:

// Also some Node don't have an associated LayoutObjects e.g. if display: none
// or display: contents is set.

并建立起它們的父子兄弟關系:

LayoutObject* newLayoutObject = m_node->createLayoutObject(style);
parentLayoutObject->addChild(newLayoutObject, nextLayoutObject);

形成一棵獨立的layout樹。

當layout樹建立好之后,緊接著用style計算layout的值。

2. 計算layout值

以上面的div為例,它需要計算它的寬度和margin。

(1)計算寬度

寬度的計算是根據數值的類型:

switch (length.type()) {
  case Fixed:
    return LayoutUnit(length.value());
  case Percent:
    // Don't remove the extra cast to float. It is needed for rounding on
    // 32-bit Intel machines that use the FPU stack.
    return LayoutUnit(
        static_cast<float>(maximumValue * length.percent() / 100.0f));
}

如上所示,如果是Fixed,則直接返回一個LayoutUnit封裝的數據,1px = 1 << 6 = 64 unit,這也是Blink存儲的精度。從這里可以看到,設置小數的px其實是有用的。

如果是Percent百分比,則用百分比乘以***值,而這個***值是用容器傳進來的寬度。

(2)計算margin值

上面的div的margin給它設置了margin: 0 auto,需要計算實際的數字。blink會檢測兩邊是不是都為auto,如果是的話就認為是居中:

// CSS 2.1: "If both 'margin-left' and 'margin-right' are 'auto', their used
// values are equal. This horizontally centers the element with respect to
// the edges of the containing block."
const ComputedStyle& containingBlockStyle = containingBlock->styleRef();
if (marginStartLength.isAuto() && marginEndLength.isAuto()) {
  LayoutUnit centeredMarginBoxStart = std::max(
      LayoutUnit(),
      (availableWidth - childWidth) / 2); 
  marginStart = centeredMarginBoxStart;
  marginEnd = availableWidth - childWidth - marginStart;
  return;
}

上面第8行用容器的寬度減掉本身的寬度,然后除以2就得到margin-left,接著用容器的寬度減掉本身的寬度和margin-left就得到margin-right。為什么margin-right還要再算一下,因為上面的代碼是刪減版的,它還有另外一種情況要處理,這里不是很重要,被我省掉了。

margin和width算好了,便把它放到layoutObject結點的盒模型數據結構里面:

m_frameRect.setWidth(width);
m_marginBoxOutsets.setStart(marginLeft);

(3)盒模型數據結構

在blink的源碼注釋里面,很形象地畫出了盒模型圖:

// ***** THE BOX MODEL *****
// The CSS box model is based on a series of nested boxes:
// http://www.w3.org/TR/CSS21/box.html
//
//       |----------------------------------------------------|
//       |                                                    |
//       |                   margin-top                       |
//       |                                                    |
//       |     |-----------------------------------------|    |
//       |     |                                         |    |
//       |     |             border-top                  |    |
//       |     |                                         |    |
//       |     |    |--------------------------|----|    |    |
//       |     |    |                          |    |    |    |
//       |     |    |       padding-top        |####|    |    |
//       |     |    |                          |####|    |    |
//       |     |    |    |----------------|    |####|    |    |
//       |     |    |    |                |    |    |    |    |
//       | ML  | BL | PL |  content box   | PR | SW | BR | MR |
//       |     |    |    |                |    |    |    |    |
//       |     |    |    |----------------|    |    |    |    |
//       |     |    |                          |    |    |    |
//       |     |    |      padding-bottom      |    |    |    |
//       |     |    |--------------------------|----|    |    |
//       |     |    |                      ####|    |    |    |
//       |     |    |     scrollbar height ####| SC |    |    |
//       |     |    |                      ####|    |    |    |
//       |     |    |-------------------------------|    |    |
//       |     |                                         |    |
//       |     |           border-bottom                 |    |
//       |     |                                         |    |
//       |     |-----------------------------------------|    |
//       |                                                    |
//       |                 margin-bottom                      |
//       |                                                    |
//       |----------------------------------------------------|
//
// BL = border-left
// BR = border-right
// ML = margin-left
// MR = margin-right
// PL = padding-left
// PR = padding-right
// SC = scroll corner (contains UI for resizing (see the 'resize' property)
// SW = scrollbar width

上面的盒模型耳熟能詳,不太一樣的是,它還把滾動條給畫出來了。

這個盒模型border及其以內區域是用一個LayoutRect m_frameRect對象表示的:

// The CSS border box rect for this box.
//
// The rectangle is in this box's physical coordinates.
// The location is the distance from this
// object's border edge to the container's border edge (which is not
// always the parent). Thus it includes any logical top/left along
// with this box's margins.
LayoutRect m_frameRect;

上面源碼注釋說得很明白,意思是說這個LayoutRect的位置是從它本身的邊到容器的邊的距離,因此它的距離/位置包含了margin值和left/top的位移偏差。LayoutRect記錄了一個盒子的位置和大小:

LayoutPoint m_location;
  LayoutSize m_size;

上面(1)和(2)計算好寬度后就去設置這個大小,保存起來。

可以在源碼里面看到用這個對象對處理的一些獲取寬度的方式,如clientWidth:

// More IE extensions.  clientWidth and clientHeight represent the interior of
// an object excluding border and scrollbar.
LayoutUnit LayoutBox::clientWidth() const {
  return m_frameRect.width() - borderLeft() - borderRight() -
         verticalScrollbarWidth();
}

clientWidth是除去border和scrollbar的寬度。

而offsetWidth是frameRect的寬度——算上border和scrollbar:

// IE extensions. Used to calculate offsetWidth/Height.
LayoutUnit offsetWidth() const override { return m_frameRect.width(); }
LayoutUnit offsetHeight() const override { return m_frameRect.height(); }

Margin區域是用一個LayoutRectOutsets表示的,這個對象記錄了margin的上下左右值:

LayoutUnit m_top;
LayoutUnit m_right;
LayoutUnit m_bottom;
LayoutUnit m_left;

上面已經分析寬高的計算,還差位置的計算。

(4)位置計算

位置計算就是要算出x和y或者說left和top的值,這兩個值分別在下面兩個函數計算得到:

// Now determine the correct ypos based off examination of collapsing margin
// values.
LayoutUnit logicalTopBeforeClear =
    collapseMargins(child, layoutInfo, childIsSelfCollapsing,
                    childDiscardMarginBefore, childDiscardMarginAfter);
// Now place the child in the correct left position
determineLogicalLeftPositionForChild(child);

用以下html做為例子:

<!DOCType html>
<html>
<head></head>
<body>
    <div id="div-1" style="border:5px solid #000; width:50%; height: 100px; margin: 0 auto;"></div>
    <div id="div-2" style="margin: 50px; padding:80px; border: 20px solid">
        <div id="div-3" style="margin:15px">hello, world</div>
    </div>
</body>
</html>

我先把計算出來的結果打印出來,如下所示:

[LayoutBlockFlow.cpp(925)] location is: “190.25”, “0” size is “400.5”, “110”  (div-1)

[LayoutBlockFlow.cpp(925)] location is: “115”, “115” size is “451”, “18”           (div-3)

[LayoutBlockFlow.cpp(925)] location is: “50”, “160” size is “681”, “248”        (div-2)

[LayoutBlockFlow.cpp(925)] location is: “8”, “8” size is “781”, “408”               (body)

[LayoutBlockFlow.cpp(925)] location is: “0”, “0” size is “797”, “466”               (html)

 

由于它是一個遞歸的過程,所以上面打印的順序是由子元素到父元素的。以div-2為例算一下,它的x = 50, y = 160:因為div-1占據的空間為h = border * 2 + height = 5 * 2 + 100 = 110,并且div-2有一個margin-top = 50,所以div-2的y = 110 + 50 = 160.

對于div-3,由于div-2有一個80px的padding和20px的border,同時它自己本身有一個15px的margin,所以div-3的y = 50 + 20 + 15 = 115.

如果把行內元素也打印出來,那么結果是這樣的:

[LayoutBlockFlowLine.cpp(1997)] inline location is: “0”, “0” size is “400.5”, “10”  (div-1 content)

[LayoutBlockFlow.cpp(925)] location is: “190.25”, “0” size is “400.5”, “110”

[LayoutBlockFlowLine.cpp(1997)] inline location is: “0”, “115” size is “451”, “18”    (div-3 text)

[LayoutBlockFlow.cpp(925)] location is: “115”, “115” size is “451”, “18”

…(后面一樣)

第三行是div-3的文本節點創建的layoutObject,它的行高是18px,所以它的size高度是18px。

這里可以看到塊級元素間的空白節點不會產生layoutObject,這在代碼里面可以找到佐證:

bool Text::textLayoutObjectIsNeeded(const ComputedStyle& style,
                                    const LayoutObject& parent) const {
  if (!length())
    return false;
  if (style.display() == EDisplay::None)
    return false;
  if (!containsOnlyWhitespace())
    return true;

  //其它判斷
}

上面代碼第7行,如果Text結點含有非空白字符,則馬上返回true,否則的話繼續判斷:

    if (parent.isLayoutBlock() && !parent.childrenInline() &&
        (!prev || !prev->isInline()))
      return false;

第二行——如果存在上一個相鄰結點,并且這個結點不是行內元素則返回false,不創建layout對象。

所以在塊級元素后面的空白文本結點將不會參與渲染,這個就解釋了為什么塊級元素后的換行不會被轉換成一個空格。在源碼里面還可以看到,塊級元素內的開頭空白字符將會被忽略:

// Whitespace at the start of a block just goes away.  Don't even
// make a layout object for this text.

這里有個問題,為什么它要遞歸地算,即先算子元素的再回過頭來算父元素呢?因為有些屬性必須得先知道子元素的才能知道父元素,例如父元素的高度是子元素撐起的,但是有些屬性要先知道父元素的才能算子元素的,例如子元素的寬度是父元素的50%。所以在計算子元素之前會先把當前元素的layout計算一下,然后再傳給子元素,子元素計算好之后會返回父元素是否需要重新layout,如下:

  // Use the estimated block position and lay out the child if needed. After
  // child layout, when we have enough information to perform proper margin
  // collapsing, float clearing and pagination, we may have to reposition and
  // lay out again if the estimate was wrong.
  bool childNeededLayout =
      positionAndLayoutOnceIfNeeded(child, logicalTopEstimate, layoutInfo);

具體的計算過程,這里舉一兩個例子,例如計算left值時,會先取父元素的border-left和padding-left作為起始位置,然后再加上它自己的margin-left就得到它的x/left值。

void LayoutBlockFlow::determineLogicalLeftPositionForChild(LayoutBox& child) {
  LayoutUnit startPosition = borderStart() + paddingStart();
  LayoutUnit initialStartPosition = startPosition;

  LayoutUnit childMarginStart = marginStartForChild(child);
  LayoutUnit newPosition = startPosition + childMarginStart;
  //other code
}

我們知道浮動的規則比較復雜,所以相應的計算也比較復雜,我們簡單研究一下。

(5)浮動

用以下三欄布局作為說明:

<div>
    <div style="float:left">hello, world</div>
    <div style="float:right"><p style="width:100px"></p></div>
    <div style="margin:0 100px;"></div>
</div>

先來看寬度的計算,對于***個float: left的div,首先它會先判斷一下寬度是否需要fit content:

bool LayoutBox::sizesLogicalWidthToFitContent(
    const Length& logicalWidth) const {
  if (isFloating() || isInlineBlockOrInlineTable())
    return true;
  //other code
}

如果它是浮動的或者是inlne-block,則需要寬度適應內容。由于子元素是一個行內文本,它需要計算這個行內元素的寬度,計算的規則非常復雜,這里我把部分注釋說明貼出來:

// (3) A text object. Text runs can have breakable characters at the
//     start, the middle or the end. They may also lose whitespace off the
//     front if we're already ignoring whitespace. In order to compute
//     accurate min-width information, we need three pieces of
//     information.
//     (a) the min-width of the first non-breakable run. Should be 0 if
//         the text string starts with whitespace.
//     (b) the min-width of the last non-breakable run. Should be 0 if the
//         text string ends with whitespace.
//     (c) the min/max width of the string (trimmed for whitespace).

第二個浮動的div,它的子元素是一個p標簽,并且它已經指定了寬度。它會去算子元素的寬度加上margin值的寬度,還要判斷是否為浮動,循環所有子元素處理,取一個***值。

再來看位置的計算,計算位置的代碼還是能夠稍微看出點苗頭,例如對float: left的計算:

//如果當前行的剩余空間小于float的寬度,則循環條件成立
while (logicalRightOffsetForPositioningFloat(
           logicalTopOffset, logicalRightOffset, &heightRemainingRight) -
           floatLogicalLeft <
       floatLogicalWidth) {
  //往下挪
  logicalTopOffset +=
      std::min<LayoutUnit>(heightRemainingLeft, heightRemainingRight);
  //計算新的float left位置
  floatLogicalLeft = logicalLeftOffsetForPositioningFloat(
      logicalTopOffset, logicalLeftOffset, &heightRemainingLeft);
  }
}
//循環結束,找到位置
floatLogicalLeft = std::max(
    logicalLeftOffset - borderAndPaddingLogicalLeft(), floatLogicalLeft);

上面它會先判斷當前行剩余空間是否小于浮動元素的寬度,如果是的話就一直往下挪。

通過上面的層層計算,就可以拿到位置坐標和具體大小,上面兩個浮動的div***計算的結果是:

[LayoutBlockFlow.cpp(1475)] location is: “0”, “0” size is “77.3281”, “18”

[LayoutBlockFlow.cpp(1475)] location is: “681”, “0” size is “100”, “16”

有了這些信息,結合顏色等style,就可進行Paint了。

3. Paint

Paint又是一塊很塊很復雜的東西,試圖在一篇文章里面講明layout都已經是一件不太可能的事情。

Paint的初始化會使用layout的數據,如下面的BoxPainter的構造函數:

BoxPainter(const LayoutBox& layoutBox) : m_layoutBox(layoutBox) {}

Paint會調用最上面說的Skia的SkCanvas畫:

SkCanvas* canvas() { return m_canvas; }

這個SkCanvas和JS里面的canvas有什么聯系和區別?

Blink JS里的canvas就是這個canvas,當在js里面獲取canvas對象進行描繪時:

var canvas = document.getElementById("canvas"); 
var ctx = canvas.getContext("2d");
ctx.fillStyle = "green";
ctx.fillRect(10, 10, 100, 100)

就會去獲取SkCanvas實例。

SkCanvas* HTMLCanvasElement::drawingCanvas() const {
  return buffer() ? m_imageBuffer->canvas() : nullptr;
}

所以不管是用html/css畫,還是用canvas畫,它們都是同宗同源的,區別就在于借助html/css比較直觀簡單,瀏覽器幫你進行layout。而直接用canvas就得從點線面一點一點地去畫,但同時它的靈活度就比較大。

4. 觸發layout

什么時候會觸發layout,上文的分析已經提及當html片段解析完會觸發layout。在上一篇也有提及加載完css后也會觸發layout,同時resize頁面的時候也會觸發layout。因為layout的計算是比較復雜的,所以應減少layout的次數。例如CSS要寫在head標簽里面,不然寫在body里面,一旦遇到新的CSS又會重新layout。

第二個是獲取clientWidth/scrollTop等維度信息時,普遍的說法是會觸發layout用于獲取值,但是在筆者的觀察下并沒有觸發layout:
如下使用getComputedStyle或者獲取clientWidth應該會觸發layout:

var style = window.getComputedStyle(document.getElementById("body"));
var width = style.width;
console.log(document.getElementById("canvas").clientWidth)

但是無論是我打斷點還是打log,都無法觀察到layout的觸發,而是直接去獲取clientWidth的值:

LayoutUnit LayoutBox::clientWidth() const {
  return m_frameRect.width() - borderLeft() - borderRight() -
         verticalScrollbarWidth();
}

不過,改變它的clientWidth的時候是一定會觸發layout的:

document.getElementById("canvas").style.width = "500px";

在layout的函數里面打印的Log:

上面幾行是重新計算CSS,下面幾行是進行layout。

另外需要注意的是盡可能地減少layout的范圍,如下的demo——當點擊菜單按鈕的時候把菜單給放出來:

<style>     #menu,      #show-btn{         display: none;     }     .show-menu #menu,     .show-menu #show-btn{         display: block;     } </style>
<body>
<span id="show-btn">Menu</span>
<nav id="menu">
    <ul><li></li></ul>
</nav>
</body>
<script>     document.getElementById("menu").onclick = function(){         document.body.addClass("show-menu");     }; </script>

上面為了圖方便,給body添加了一個類,用這個類控制菜單的狀態。但是這樣會有很大的問題,因為給body添加了一個類導致它要重新計算style和layout,它一旦layout了,它的子元素也要跟著layout,也就是說整個頁面都要重新layout。所以這個代價就很高了,我們應該縮小影響范圍。因此,把show-menu的class加到直接相關的元素上面就好了。

至此,整一個頁面渲染過程就介紹完畢了。我們從html -> CSS -> layout -> paint一步步分析了其中的過程,雖然介紹得不是很全面,但已經把核心的過程剖析了一遍。由于寫html/css很多東西都是不透明,完全不知道背后是怎么工作的,只能是看文檔說這個標簽是怎么用的,那個屬性會有什么效果,然后在瀏覽器上面看效果,有點任瀏覽器宰割的感覺。所以這個源碼解讀就是為了能夠窺探瀏覽器背后工作原理,這樣對寫代碼會有幫助,能夠做到心中有數。當遇到一些比較困難的問題時,能夠很快的找到解決方案或者解決的方向。

例如筆者就遇到一個奇芭的問題,就是使用height: calc(100% - 80px)的時候,在手機Safari上面展開某個子菜單時,偶現菜單滑不動的情況。當時就想很可能是在Safari在展開菜單時高度算錯了,導致overflow: auto不管用。所以在展開菜單后再手手動計算和設置height,然后就解決問題了。

責任編輯:張燕妮 來源: 人人網FED
相關推薦

2017-11-21 14:56:59

2017-02-07 09:44:12

Chrome源碼DOM樹

2017-02-09 15:15:54

Chrome瀏覽器

2011-06-21 16:52:48

2012-07-04 17:00:06

獵豹瀏覽瀏覽器

2010-01-28 10:13:43

2009-11-26 10:55:41

2015-01-21 15:45:50

斯巴達瀏覽器

2018-02-02 15:48:47

ChromeDNS解析

2009-07-17 09:16:20

Google Chro瀏覽器操作系統

2010-01-10 17:50:17

2009-09-22 09:17:46

谷歌Chrome瀏覽器

2012-08-08 09:18:47

Chrome瀏覽器

2019-02-15 15:15:59

ChromeJavascriptHtml

2013-11-13 15:54:20

Chrome 31瀏覽器

2009-12-06 09:38:02

Chrome瀏覽器Avast

2009-03-07 09:57:41

Realplayer捆綁Chrome

2009-12-03 10:56:34

谷歌Chrome瀏覽器

2020-11-25 09:47:11

FedoraGoogle Chro瀏覽器

2022-02-07 21:49:06

瀏覽器渲染chromium
點贊
收藏

51CTO技術棧公眾號

欧美久久久久久一卡四| 午夜精品久久久久久久久久久久久 | 亚洲国产精品v| 国产精品亚洲精品| 日日骚一区二区三区| 国偷自产av一区二区三区| 日本久久电影网| 日本aa在线观看| 国产主播福利在线| 国产一区二区0| 日本精品一区二区三区在线| 色婷婷在线视频观看| 亚瑟一区二区三区四区| 欧美夫妻性生活| 免费在线观看日韩视频| av免费网站在线| 久久一留热品黄| 99久久综合狠狠综合久久止| 最近日韩免费视频| 99成人在线| 超碰精品一区二区三区乱码| 偷拍夫妻性生活| 草草视频在线一区二区| 欧美日韩高清一区二区| 成人免费观看视频在线观看| 日本动漫同人动漫在线观看| 欧美高清在线精品一区| 蜜桃狠狠色伊人亚洲综合网站| 性网爆门事件集合av| 免费观看在线综合色| 91a在线视频| 欧美片一区二区| 国产精品久久久久久影院8一贰佰| 亚洲男人天堂九九视频| 丰满岳乱妇一区二区| 精品久久国产一区| 欧美日韩aaa| 丰满少妇在线观看| 怡红院成人在线| 狠狠色狠狠色综合日日五| 日韩精品久久一区二区| 成年视频在线观看| 1区2区3区国产精品| 亚洲成人午夜在线| 国产黄色在线| 中文字幕欧美激情| 日韩欧美在线电影| 国产女人在线视频| 久久久99精品免费观看不卡| 免费一区二区三区在在线视频| 蜜臀久久99精品久久久| 高清不卡一区二区| 国产aⅴ精品一区二区三区黄| 国产丝袜视频在线观看| 精品无码三级在线观看视频| 国产精品直播网红| 在线观看中文字幕码| 日本不卡高清视频| 国产精品一区二区3区| 亚洲成人av影片| 日韩高清欧美激情| 欧洲成人在线观看| 一级做a爰片久久毛片| 久久看片网站| 2024亚洲男人天堂| 亚洲 日本 欧美 中文幕| 玖玖玖国产精品| 国产精品女人久久久久久| 中文精品久久久久人妻不卡| 麻豆91小视频| 91精品国产一区二区三区动漫 | 日韩精品在线电影| 性欧美丰满熟妇xxxx性仙踪林| 蜜桃一区二区| 中文字幕亚洲综合| 男女性高潮免费网站| 亚洲国产一区二区三区a毛片| 国内揄拍国内精品| 国产无遮挡又黄又爽又色视频| 免费av网站大全久久| 69174成人网| 午夜小视频在线播放| 久久精品一区二区三区不卡牛牛| 亚洲精品无人区| 欧美xxxx黑人又粗又长| 欧美日韩精品国产| 国产3p在线播放| 成人福利一区| 伊人久久大香线蕉av一区二区| 天天爽天天爽天天爽| 国精品一区二区三区| 国产成人小视频在线观看| 国产一区二区三区在线观看| 成人av电影在线播放| 日韩av一级大片| 亚洲wwwww| 在线观看视频一区二区欧美日韩| 欧美日韩理论片| 一区二区三区日本久久久| x99av成人免费| 黄色大片网站在线观看| 久久97超碰国产精品超碰| 国产伦精品一区二区三毛| 国产女人在线视频| 午夜精品爽啪视频| 欧美成人黄色网址| 精品国产乱子伦一区二区| 中文字幕亚洲欧美一区二区三区| 国产一级大片在线观看| 美女脱光内衣内裤视频久久网站| 国产在线精品一区二区三区| 成人影视在线播放| 婷婷久久综合九色国产成人| 国产美女18xxxx免费视频| 日本一道高清一区二区三区| 蜜臀久久99精品久久久久久宅男| av图片在线观看| 国产成人自拍网| 午夜一区二区三视频在线观看| missav|免费高清av在线看| 一本高清dvd不卡在线观看| 久久久久无码国产精品一区李宗瑞| 成人嫩草影院| 国产精品wwwwww| 天天舔天天干天天操| 一二三四社区欧美黄| 艹b视频在线观看| 国产一区二区三区电影在线观看 | 成人免费视频视频在线观看免费| 一本久道久久综合| av在线免费网址| 日韩欧美国产骚| 国产精品麻豆入口| 欧美性色综合| 99国产在线视频| 国产激情小视频在线| 欧美日韩国产小视频在线观看| 久久亚洲AV成人无码国产野外| 精品电影一区| 国产精品国产三级国产专区53 | 黄色精品一区| 91超碰在线电影| fc2ppv国产精品久久| 69p69国产精品| 老司机成人免费视频| 麻豆成人av在线| 一区高清视频| 91国产一区| 久久天天躁狠狠躁夜夜躁| 国产一区二区在线播放视频| 国产精品天天看| 波多结衣在线观看| 天天综合一区| 亚洲va久久久噜噜噜| 成人在线视频亚洲| 日韩一级免费观看| 欧美精品一区二区蜜桃| 高清成人免费视频| 国产一区二区网| 外国成人在线视频| 国产精品xxxxx| 性开放的欧美大片| 欧美一二三区精品| 日本a在线观看| 久久久久一区二区三区四区| 一区二区三区韩国| 外国成人免费视频| 成人国产一区二区| 欧美sm一区| 亚洲天堂开心观看| 亚洲熟妇av乱码在线观看| 亚洲视频一区在线观看| 国产乱淫av麻豆国产免费| 亚洲精品色图| 亚洲国产婷婷香蕉久久久久久99| 天天综合91| 久久久久久久国产| 国产一二在线观看| 666欧美在线视频| 精品深夜av无码一区二区老年| 26uuu国产日韩综合| 污污网站免费观看| 韩国av一区| 日本不卡久久| 精品入口麻豆88视频| 7m精品福利视频导航| 国产一二三区在线| 日韩亚洲欧美一区| www.国产com| 中文字幕在线观看不卡视频| 中国特级黄色片| 久久婷婷亚洲| 99久热在线精品视频| 欧美日韩爱爱| 动漫3d精品一区二区三区| 欧美极度另类| 欧美精品videosex极品1| 国产日韩精品在线看| 日韩精品一区二区三区在线| 一本一道无码中文字幕精品热| 中文字幕一区不卡| 国产国语性生话播放| 青青草97国产精品免费观看无弹窗版| 久久免费视频2| 美女精品一区最新中文字幕一区二区三区 | 中文日韩电影网站| 日韩在线观看视频网站| 欧美日韩高清一区二区| 一本一道无码中文字幕精品热| 亚洲精品成人悠悠色影视| 中文字幕免费高清| 盗摄精品av一区二区三区| 精品亚洲一区二区三区四区| 国产欧美日韩综合一区在线播放 | 日韩精品一区二区三区swag| 99精品国产高清一区二区| 亚洲一区二区福利视频| 好看的av在线不卡观看| 性刺激综合网| 台湾色综合娱乐中文网| 99在线影院| 99久久这里有精品| 国产精品福利久久久| 国产99在线观看| 欧美xxxx做受欧美.88| 国产一二在线观看| 亚洲精品国产成人| 性色av蜜臀av| 欧美精品高清视频| 国产九色91回来了| 欧美性精品220| 日韩人妻无码一区二区三区99 | 国产日韩一区二区| 亚洲综合网站| 亚洲自拍小视频| 99国内精品久久久久| 国产精品天天狠天天看| 综合在线影院| 国产成人高清激情视频在线观看 | 黄色国产精品| 美女av免费观看| 在线成人激情| www.69av| 黄色成人在线网址| 国产免费黄色一级片| 亚洲香蕉网站| 少妇人妻大乳在线视频| 伊人久久久大香线蕉综合直播 | 蜜桃一区二区三区四区| 日日噜噜夜夜狠狠| 免费一级欧美片在线观看| 激情 小说 亚洲 图片: 伦| 日韩高清一级片| 中文字幕免费高清在线| 狠狠色丁香婷婷综合久久片| 亚洲图片 自拍偷拍| 国产精品一区二区黑丝| 在线免费黄色小视频| 国产盗摄一区二区三区| 国产麻豆剧传媒精品国产| 成人性生交大片免费看中文网站| 蜜臀aⅴ国产精品久久久国产老师 性活交片大全免费看 | 国产精品二三区| 国产黄色录像片| 一区二区三区国产豹纹内裤在线 | 欧美性猛交xxxx黑人交| 一级片免费观看视频| 欧美一区二区三区免费视频 | 亚洲精品在线观看www| 欧美视频综合| 日韩中文字幕视频| 欧美hdxxx| 日本三级韩国三级久久| 日韩毛片免费看| 风间由美久久久| 女优一区二区三区| 中文字幕av导航| 极品中文字幕一区| 免费观看成人网| 韩日av一区二区| 成熟妇人a片免费看网站| 久久婷婷国产综合国色天香| fc2ppv在线播放| 亚洲成人动漫在线观看| 少妇一级淫片日本| 欧美一区二区精品在线| 四虎影视在线观看2413| 最近中文字幕mv在线一区二区三区四区| 含羞草www国产在线视频| 91精品国产91久久久| 亚洲日日夜夜| 久久国产精品一区二区三区四区| 日韩欧美中字| 无码专区aaaaaa免费视频| 日韩精品三区四区| wwwxx日本| 亚洲欧洲av色图| www.毛片.com| 日韩视频一区在线观看| 国产对白叫床清晰在线播放| 欧美激情综合色综合啪啪五月| 激情开心成人网| 国产精品视频免费观看| 色狮一区二区三区四区视频| 日本精品免费在线观看| 国产精品综合视频| 夜夜春很很躁夜夜躁| 亚洲成a人片在线不卡一二三区| 伊人网视频在线| 亚洲精品视频免费| 久久香蕉一区| 51精品国产人成在线观看| 欧美日韩国产免费观看视频| 久久久久免费看黄a片app| 国产精品一级黄| 久久精品日韩无码| 色狠狠av一区二区三区| 黄色av中文字幕| 久久综合色88| 亚洲网站免费| 亚洲欧洲中文| 视频在线观看91| 野花社区视频在线观看| 亚洲午夜在线视频| 亚洲a视频在线| 欧美成人第一页| 不卡一区视频| 亚洲砖区区免费| 男人操女人的视频在线观看欧美| 日本黄色特级片| 欧美三级xxx| av女名字大全列表| 97精品一区二区视频在线观看| 日韩一区二区三区高清在线观看| 国产成年人在线观看| 久久99九九99精品| 久久爱一区二区| 欧美人妖巨大在线| 黄色网址视频在线观看| 成人激情视频在线观看| 亚欧美无遮挡hd高清在线视频| 欧美午夜aaaaaa免费视频| 亚洲国产精品激情在线观看| 中文字幕一区二区久久人妻| 伊人亚洲福利一区二区三区| 欧美××××黑人××性爽| 色狠狠久久av五月综合| 日韩精品亚洲一区| 正在播放国产对白害羞| 欧美日韩日本视频| 国产福利在线播放麻豆| 亚洲va码欧洲m码| 在线看片欧美| 亚洲精品国产一区黑色丝袜| 91久久精品国产91性色tv| 91在线免费看| 91香蕉嫩草影院入口| 国内精品久久久久久久影视蜜臀| 伦理片一区二区| 日韩欧美在线观看视频| 国产黄在线看| 成人在线播放av| 最新成人av网站| 国产精品密蕾丝袜| 欧美日韩精品福利| 调教一区二区| 麻豆91蜜桃| 蜜乳av一区二区| 久久r这里只有精品| 亚洲精品白浆高清久久久久久| 日日夜夜天天综合| 欧美 另类 交| youjizz久久| 五月天中文字幕| 欧美成人中文字幕在线| 开心激情综合| 中文字幕一区二区三区四区在线视频| 国产精品国产三级国产aⅴ原创 | 欧洲一区在线| 日本中文字幕网址| 国产精品视频线看| 亚洲精品中文字幕成人片| 日本久久中文字幕| 中文字幕人成人乱码| 国产吞精囗交久久久| 欧美肥妇毛茸茸| 交100部在线观看| 夜夜爽www精品| 91欧美激情一区二区三区成人| 影音先锋国产在线| 久久久最新网址| 日韩成人a**站| a天堂视频在线观看| 欧美日韩和欧美的一区二区| 国产污视频在线播放| 一区二区三区四区免费视频| 91尤物视频在线观看| 国产精品久久久久久无人区| 国产91ⅴ在线精品免费观看| 911精品美国片911久久久|