void CameraController::updateBaseToWorldMatrix() { Vec3d zAt = _testAt - _testBase; /* At point与Base point重合 */ if (zAt.length2() < 1e-10) { _testBaseEyeToWorldMatrix = _testAtToWorldMatrix; _testBaseAtToWorldMatrix = _testAtToWorldMatrix; return; } Vec3d zEye = _testEye - _testBase; /* Eye point与Base point重合 */ if (zEye.length2() < 1e-10) { _testBaseEyeToWorldMatrix = _testBaseEyeToWorldMatrix; Vec3d p1 = Vec3d(0, 0, 0); Vec3d p2 = Vec3d(1, 0, 0); p1 = switchCoordinateSystem_point(p1, _eyeToWorldMatrix, WORLD_MATRIX); p2 = switchCoordinateSystem_point(p2, _eyeToWorldMatrix, WORLD_MATRIX); Matrixd mat1, mat2, mat3, matFinal; mat1.makeTranslate(-p1); mat2.makeRotate(PI, p2-p1); mat3.makeTranslate(p1); matFinal = mat1 * mat2 * mat3; _testBaseAtToWorldMatrix = _testBaseEyeToWorldMatrix * matFinal; return; } Vec3d yEye; Vec3d yAt; if (inSameLine(_testEye, _testAt, _testBase)) // eye, at, base 三点共线 { /* y轴以up向量为参照 */ yEye = _testUp; yAt = _testUp; } else { /* y轴以视线为参照 */ Vec3d sight = _testAt - _testEye; yEye = zEye ^ sight ^ zEye; yAt = zAt ^ sight ^ zAt; } _testBaseEyeToWorldMatrix = calcMatrixBasedOnAxis(_testBase, yEye, zEye); _testBaseAtToWorldMatrix = calcMatrixBasedOnAxis(_testBase, yAt, zAt); }
TEST_F(VisibleUnitsTest, inSameLine) { const char* bodyContent = "<p id='host'>00<b id='one'>11</b><b id='two'>22</b>33</p>"; const char* shadowContent = "<div><span id='s4'>44</span><content select=#two></content><br><span id='s5'>55</span><br><content select=#one></content><span id='s6'>66</span></div>"; setBodyContent(bodyContent); RefPtrWillBeRawPtr<ShadowRoot> shadowRoot = setShadowContent(shadowContent); updateLayoutAndStyleForPainting(); RefPtrWillBeRawPtr<Element> body = document().body(); RefPtrWillBeRawPtr<Element> one = body->querySelector("#one", ASSERT_NO_EXCEPTION); RefPtrWillBeRawPtr<Element> two = body->querySelector("#two", ASSERT_NO_EXCEPTION); RefPtrWillBeRawPtr<Element> four = shadowRoot->querySelector("#s4", ASSERT_NO_EXCEPTION); RefPtrWillBeRawPtr<Element> five = shadowRoot->querySelector("#s5", ASSERT_NO_EXCEPTION); EXPECT_TRUE(inSameLine(positionWithAffinityInDOMTree(*one, 0), positionWithAffinityInDOMTree(*two, 0))); EXPECT_TRUE(inSameLine(positionWithAffinityInDOMTree(*one->firstChild(), 0), positionWithAffinityInDOMTree(*two->firstChild(), 0))); EXPECT_FALSE(inSameLine(positionWithAffinityInDOMTree(*one->firstChild(), 0), positionWithAffinityInDOMTree(*five->firstChild(), 0))); EXPECT_FALSE(inSameLine(positionWithAffinityInDOMTree(*two->firstChild(), 0), positionWithAffinityInDOMTree(*four->firstChild(), 0))); EXPECT_FALSE(inSameLine(positionWithAffinityInComposedTree(*one, 0), positionWithAffinityInComposedTree(*two, 0))); EXPECT_FALSE(inSameLine(positionWithAffinityInComposedTree(*one->firstChild(), 0), positionWithAffinityInComposedTree(*two->firstChild(), 0))); EXPECT_FALSE(inSameLine(positionWithAffinityInComposedTree(*one->firstChild(), 0), positionWithAffinityInComposedTree(*five->firstChild(), 0))); EXPECT_TRUE(inSameLine(positionWithAffinityInComposedTree(*two->firstChild(), 0), positionWithAffinityInComposedTree(*four->firstChild(), 0))); }
VisibleSelection DirectionGranularityStrategy::updateExtent( const IntPoint& extentPoint, LocalFrame* frame) { const VisibleSelection& selection = frame->selection().selection(); if (m_state == StrategyState::Cleared) m_state = StrategyState::Expanding; VisiblePosition oldOffsetExtentPosition = selection.visibleExtent(); IntPoint oldExtentLocation = positionLocation(oldOffsetExtentPosition); IntPoint oldOffsetExtentPoint = oldExtentLocation + m_diffExtentPointFromExtentPosition; IntPoint oldExtentPoint = IntPoint(oldOffsetExtentPoint.x() - m_offset, oldOffsetExtentPoint.y()); // Apply the offset. IntPoint newOffsetExtentPoint = extentPoint; int dx = extentPoint.x() - oldExtentPoint.x(); if (m_offset != 0) { if (m_offset > 0 && dx > 0) m_offset = std::max(0, m_offset - dx); else if (m_offset < 0 && dx < 0) m_offset = std::min(0, m_offset - dx); newOffsetExtentPoint.move(m_offset, 0); } VisiblePosition newOffsetExtentPosition = visiblePositionForContentsPoint(newOffsetExtentPoint, frame); IntPoint newOffsetLocation = positionLocation(newOffsetExtentPosition); // Reset the offset in case of a vertical change in the location (could be // due to a line change or due to an unusual layout, e.g. rotated text). bool verticalChange = newOffsetLocation.y() != oldExtentLocation.y(); if (verticalChange) { m_offset = 0; m_granularity = CharacterGranularity; newOffsetExtentPoint = extentPoint; newOffsetExtentPosition = visiblePositionForContentsPoint(extentPoint, frame); } const VisiblePosition base = selection.visibleBase(); // Do not allow empty selection. if (newOffsetExtentPosition.deepEquivalent() == base.deepEquivalent()) return selection; // The direction granularity strategy, particularly the "offset" feature // doesn't work with non-horizontal text (e.g. when the text is rotated). // So revert to the behavior equivalent to the character granularity // strategy if we detect that the text's baseline coordinate changed // without a line change. if (verticalChange && inSameLine(newOffsetExtentPosition, oldOffsetExtentPosition)) { return createVisibleSelection(selection.visibleBase(), newOffsetExtentPosition); } int oldExtentBaseOrder = selection.isBaseFirst() ? 1 : -1; int newExtentBaseOrder; bool thisMoveShrunkSelection; if (newOffsetExtentPosition.deepEquivalent() == oldOffsetExtentPosition.deepEquivalent()) { if (m_granularity == CharacterGranularity) return selection; // If we are in Word granularity, we cannot exit here, since we may pass // the middle of the word without changing the position (in which case // the selection needs to expand). thisMoveShrunkSelection = false; newExtentBaseOrder = oldExtentBaseOrder; } else { bool selectionExpanded = arePositionsInSpecifiedOrder( newOffsetExtentPosition, oldOffsetExtentPosition, oldExtentBaseOrder); bool extentBaseOrderSwitched = selectionExpanded ? false : !arePositionsInSpecifiedOrder(newOffsetExtentPosition, base, oldExtentBaseOrder); newExtentBaseOrder = extentBaseOrderSwitched ? -oldExtentBaseOrder : oldExtentBaseOrder; // Determine the word boundary, i.e. the boundary extending beyond which // should change the granularity to WordGranularity. VisiblePosition wordBoundary; if (extentBaseOrderSwitched) { // Special case. // If the extent-base order was switched, then the selection is now // expanding in a different direction than before. Therefore we // calculate the word boundary in this new direction and based on // the |base| position. wordBoundary = nextWordBound(base, newExtentBaseOrder > 0 ? SearchDirection::SearchForward : SearchDirection::SearchBackwards, BoundAdjust::NextBoundIfOnBound); m_granularity = CharacterGranularity; } else { // Calculate the word boundary based on |oldExtentWithGranularity|. // If selection was shrunk in the last update and the extent is now // exactly on the word boundary - we need to take the next bound as // the bound of the current word. wordBoundary = nextWordBound(oldOffsetExtentPosition, oldExtentBaseOrder > 0 ? SearchDirection::SearchForward : SearchDirection::SearchBackwards, m_state == StrategyState::Shrinking ? BoundAdjust::NextBoundIfOnBound : BoundAdjust::CurrentPosIfOnBound); } bool expandedBeyondWordBoundary; if (selectionExpanded) expandedBeyondWordBoundary = arePositionsInSpecifiedOrder( newOffsetExtentPosition, wordBoundary, newExtentBaseOrder); else if (extentBaseOrderSwitched) expandedBeyondWordBoundary = arePositionsInSpecifiedOrder( newOffsetExtentPosition, wordBoundary, newExtentBaseOrder); else expandedBeyondWordBoundary = false; // The selection is shrunk if the extent changes position to be closer to // the base, and the extent/base order wasn't switched. thisMoveShrunkSelection = !extentBaseOrderSwitched && !selectionExpanded; if (expandedBeyondWordBoundary) m_granularity = WordGranularity; else if (thisMoveShrunkSelection) m_granularity = CharacterGranularity; } VisiblePosition newSelectionExtent = newOffsetExtentPosition; if (m_granularity == WordGranularity) { // Determine the bounds of the word where the extent is located. // Set the selection extent to one of the two bounds depending on // whether the extent is passed the middle of the word. VisiblePosition boundBeforeExtent = nextWordBound(newOffsetExtentPosition, SearchDirection::SearchBackwards, BoundAdjust::CurrentPosIfOnBound); VisiblePosition boundAfterExtent = nextWordBound(newOffsetExtentPosition, SearchDirection::SearchForward, BoundAdjust::CurrentPosIfOnBound); int xMiddleBetweenBounds = (positionLocation(boundAfterExtent).x() + positionLocation(boundBeforeExtent).x()) / 2; bool offsetExtentBeforeMiddle = newOffsetExtentPoint.x() < xMiddleBetweenBounds; newSelectionExtent = offsetExtentBeforeMiddle ? boundBeforeExtent : boundAfterExtent; // Update the offset if selection expanded in word granularity. if (newSelectionExtent.deepEquivalent() != selection.visibleExtent().deepEquivalent() && ((newExtentBaseOrder > 0 && !offsetExtentBeforeMiddle) || (newExtentBaseOrder < 0 && offsetExtentBeforeMiddle))) { m_offset = positionLocation(newSelectionExtent).x() - extentPoint.x(); } } // Only update the state if the selection actually changed as a result of // this move. if (newSelectionExtent.deepEquivalent() != selection.visibleExtent().deepEquivalent()) m_state = thisMoveShrunkSelection ? StrategyState::Shrinking : StrategyState::Expanding; m_diffExtentPointFromExtentPosition = extentPoint + IntSize(m_offset, 0) - positionLocation(newSelectionExtent); VisibleSelection newSelection = selection; newSelection.setExtent(newSelectionExtent); return newSelection; }