double Face :: fieldIndex( double k ) const { if( isBoundary() ) return 0.; double Omega = 0.; double index = 0.; HalfEdgeCIter hi = he; do { double phiI = hi->vertex->directionField.arg(); double phiJ = hi->flip->vertex->directionField.arg(); double thetaI = hi->angularCoordinate; double thetaJ = hi->flip->angularCoordinate + M_PI; double dTheta = thetaI - thetaJ; Omega += dTheta; index += fmodPI( phiJ - phiI + k*dTheta ); hi = hi->next; } while( hi != he ); index -= k * fmodPI(Omega); return lround( index / (2.*M_PI) ); }
BoundingBox Face::boundingBox() const { if (isBoundary()) { return BoundingBox(he->vertex->position, he->next->vertex->position); } Eigen::Vector3d p1 = he->vertex->position; Eigen::Vector3d p2 = he->next->vertex->position; Eigen::Vector3d p3 = he->next->next->vertex->position; Eigen::Vector3d min = p1; Eigen::Vector3d max = p1; if (p2.x() < min.x()) min.x() = p2.x(); if (p3.x() < min.x()) min.x() = p3.x(); if (p2.y() < min.y()) min.y() = p2.y(); if (p3.y() < min.y()) min.y() = p3.y(); if (p2.z() < min.z()) min.z() = p2.z(); if (p3.z() < min.z()) min.z() = p3.z(); if (p2.x() > max.x()) max.x() = p2.x(); if (p3.x() > max.x()) max.x() = p3.x(); if (p2.y() > max.y()) max.y() = p2.y(); if (p3.y() > max.y()) max.y() = p3.y(); if (p2.z() > max.z()) max.z() = p2.z(); if (p3.z() > max.z()) max.z() = p3.z(); return BoundingBox(min, max); }
double Face::area() const { if (isBoundary()) { return 0.0; } return 0.5 * normal().norm(); }
//get Boundary Adjacent Vertexes of a vertex void HalfEdgeMesh::getBoundaryAdjacentVertexes(int vertexIndex, vector<int>& adjVtx_ids){ for(int i=0;i<HEHalfEdges.size();i++){ HEHalfEdge he=HEHalfEdges.at(i); int vtx_id=he.origin; int next_edge_id=HEHalfEdges.at(i).next; HEHalfEdge next_he=HEHalfEdges.at(next_edge_id); int next_vtx_id=HEHalfEdges.at(next_edge_id).origin; if(vtx_id==vertexIndex&&isBoundary(he)){ adjVtx_ids.push_back(next_vtx_id); } else if(next_vtx_id==vertexIndex&&isBoundary(he)){ adjVtx_ids.push_back(vtx_id); } } }
bool isBoundary(const _Internal::_triangle* t) { for(int i=0; i<3; ++i) { if(isBoundary(t->edges[i])) return true; } return false; }
//! returns the previous boundary from given index, including the index in the search. //! If index is a boundary, it is returned and current is decreased by one, //! otherwise works as previous() int MIcuBreakIterator::previousInclusive(int index) { Q_D(MIcuBreakIterator); if (isBoundary(index)) { d->current = index - 1; return index; } else { return previous(index); } }
bool Lexer::isDoubleCharOperator (int c0, int c1, int c2) { return (c0 == '=' && c1 == '=') || (c0 == '!' && c1 == '=') || (c0 == '<' && c1 == '=') || (c0 == '>' && c1 == '=') || (c0 == 'o' && c1 == 'r' && isBoundary (c1, c2)) || (c0 == '|' && c1 == '|') || (c0 == '&' && c1 == '&') || (c0 == '!' && c1 == '~'); }
/* An edge is deemed safe if removal of it will not make the shape irregular. A shape is irregular if a vertex has more than two edges that are on the boundary. */ bool isSafe(const _Internal::_edge* e) { if(isBoundary(e)) { _Internal::_triangle* tr = e->faces[0] ? e->faces[0] : e->faces[1]; //one has to be non NULL if(tr == NULL) return false; //this is a dangling edge. not safe. _Internal::_vertex* v = findOpposite(tr, e); for(int j=0; j<v->edges.size(); ++j) { const _Internal::_edge* e2 = v->edges[j]; if(isBoundary(e2)) { return false; } } return true; } return false; }
//if a Vertex is on boundary bool HalfEdgeMesh::isOnBoundary(int vtx_index){ for(int i=0;i<HEHalfEdges.size();i++){ HEHalfEdge he=HEHalfEdges.at(i); if(he.origin==vtx_index&&isBoundary(he)){ return true; } } return false; }
//! returns the previous boundary including the current index in the search. //! If current index is a boundary, it is returned and current is decreased by one, //! otherwise works as previous() int MIcuBreakIterator::previousInclusive() { Q_D(MIcuBreakIterator); if (isBoundary()) { int result = d->current; --d->current; return result; } else { return previous(); } }
void Lanes::changeActiveLane(const CGitHash& sha) { int& t = typeVec[activeLane]; if (t == INITIAL || isBoundary(t)) t = EMPTY; else t = NOT_ACTIVE; int idx = findNextSha(sha, 0); // find first sha if (idx != -1) typeVec[idx] = ACTIVE; // called before setBoundary() else idx = add(BRANCH, sha, activeLane); // new branch activeLane = idx; }
void Lexer::word() { _word[_wi++] = _stream->current(); while (!isBoundary(_stream->peek())) _word[_wi++] = _stream->read(); // does it look like a number? _word[_wi++] = '\0'; if (isint(_word)) add(new (collect) Term(TInt, atol(_word))); else if (isfloat(_word)) add(new (collect) Term(TDouble, atof(_word))); else add(new (collect) Term(TSymbol, Sym::lookup(_word))); _wi = 0; }
Eigen::Vector3d Face::centroid() const { Eigen::Vector3d centroid; if (isBoundary()) { centroid = (he->vertex->position + he->next->vertex->position) / 2.0; } else { centroid = (he->vertex->position + he->next->vertex->position + he->next->next->vertex->position) / 3.0; } return centroid; }
void Vertex::computeCentroid( void ) { // TODO Compute the average position of all neighbors of this vertex, and // TODO store it in Vertex::centroid. This value will be used for resampling. HalfedgeIter h = halfedge(); centroid.x = 0; centroid.y = 0; centroid.z = 0; do { h = h->twin(); Vector3D neighbor = h->vertex()->position; centroid += neighbor; h = h->next(); } while(h != halfedge()); //By convention, Vertex::degree() returns the face degree, //not the edge degree. The edge degree can be computed by finding the face //degree, and adding 1 if the vertex is a boundary vertex. int degree = this->degree(); if(isBoundary()) degree++; centroid /= (double)degree; }
//---------------------------------------------------------------------------- void PrNestedTriangulation::getParents(int i, int jlev, int& p1, int& p2) //----------------------------------------------------------------------------- // Assuming that node i belongs to V^j\V^{j-1} and that // jlev >= 1, find i's two parent nodes in V^{j-1} p1 and p2. { vector<int> neighbours; getNeighbours(i,jlev,neighbours); if(isBoundary(i)) { // Then there are exactly four neighbours. We want the // first and last ones. p1 = neighbours[0]; p2 = neighbours[3]; return; } else { // Then there are exactly six neighbours. Find the first // coarse one. if(neighbours[0] < getNumNodes(jlev-1)) { p1 = neighbours[0]; p2 = neighbours[3]; return; } else if(neighbours[1] < getNumNodes(jlev-1)) { p1 = neighbours[1]; p2 = neighbours[4]; return; } else { p1 = neighbours[2]; p2 = neighbours[5]; return; } } }
Triangulator::Triangulator(const vector<CParticleF>& pnts) { for(int i=0; i<pnts.size(); ++i) { points.push_back(new _Internal::_vertex(pnts[i])); } vector<TriangulateBourke::Triplet> delaunayTriangles = TriangulateBourke::DelaunayTriangulation(pnts); /*if(tripletSanityCheck(delaunayTriangles, pnts.size()) > 0) { int i=0; }*/ for(int i=0; i<delaunayTriangles.size(); i++) { int xk = delaunayTriangles[i].index[0]; int yk = delaunayTriangles[i].index[1]; int zk = delaunayTriangles[i].index[2]; assert(xk>=0 && xk<pnts.size() && yk>=0 && yk<pnts.size() && zk>=0 && zk<pnts.size()); CParticleF x = pnts[xk]; CParticleF y = pnts[yk]; CParticleF z = pnts[zk]; float ccw = CounterClockWise(x, y, z); if(ccw > 0) { //arrange them in clockwise orientation swap(xk, zk); swap(x, z); } _Internal::_edge* tedges[3]; tedges[0] = (new _Internal::_edge(points[xk], points[yk])); tedges[1] = (new _Internal::_edge(points[yk], points[zk])); tedges[2] = (new _Internal::_edge(points[zk], points[xk])); _Internal::_triangle* tr = new _Internal::_triangle(0, 0, 0, points[xk], points[yk], points[zk]); faces.push_back(tr); //add new edges to the edge vector. Make association with a new face and edges. for(int j=0; j<3; ++j) { vector<_Internal::_edge*>::iterator it = find_if(edges.begin(), edges.end(), _Internal::_edge_equal(tedges[j])); if(it == edges.end()) { edges.push_back(tedges[j]); } else { delete tedges[j]; tedges[j] = *it; } tr->edges[j] = tedges[j]; tedges[j]->AddFace(tr); } points[xk]->AddEdge(tedges[0]); points[xk]->AddEdge(tedges[2]); points[yk]->AddEdge(tedges[0]); points[yk]->AddEdge(tedges[1]); points[zk]->AddEdge(tedges[1]); points[zk]->AddEdge(tedges[2]); } sort(edges.begin(), edges.end(), _Internal::_edge_less); //classify each edge. Initially, they are either Inside or Boundary. //After edge-removal, we can have Hole edges when an Inside edge is removed. for(int i=0; i<edges.size(); ++i) { if(isBoundary(edges[i])) { edges[i]->type = _Internal::Boundary; } else { edges[i]->type = _Internal::Inside; } Node<_Internal::_edge*>* node = makeset(edges[i]); vnodes.push_back(node); edges[i]->node = node; } //make a cluster of boundary edges. Initially, there is only one cluster Node<_Internal::_edge*>* root = NULL; for(int i=0; i<edges.size(); ++i) { if(edges[i]->type == _Internal::Boundary) { if(root == NULL) { root = edges[i]->node; } else { merge(edges[i]->node, root); } } } }
//get two sets of sequential Adjacent Vertexes of two vertexes that is in a half edge which is not a boundary edge void HalfEdgeMesh::getSequentialAdjacentVertexes(int he_id, vector<int>& adjVtx_ids0, vector<int>& adjVtx_ids1){ if(!isBoundary(HEHalfEdges.at(he_id))){ int twin_id=HEHalfEdges.at(he_id).twin; int tem_id=-1; int vtx0_id=HEHalfEdges.at(he_id).origin; int vtx1_id=HEHalfEdges.at(twin_id).origin; if(isOnBoundary(vtx0_id)){ vector<int> vtx_ids; getBoundaryAdjacentVertexes(vtx0_id, vtx_ids); int tem_next=-1; int tem_pre=-1; for(int i=0;i<HEHalfEdges.size();i++){ if(HEHalfEdges.at(i).origin==vtx0_id&&(HEHalfEdges.at(HEHalfEdges.at(i).next).origin==vtx_ids.at(0)||HEHalfEdges.at(HEHalfEdges.at(i).next).origin==vtx_ids.at(1))){ tem_next=HEHalfEdges.at(i).next; tem_pre=HEHalfEdges.at(i).prev; adjVtx_ids0.push_back(HEHalfEdges.at(tem_next).origin); break; } } tem_id=HEHalfEdges.at(tem_pre).twin; while(tem_id!=-1){ tem_next=HEHalfEdges.at(tem_id).next; tem_pre=HEHalfEdges.at(tem_id).prev; adjVtx_ids0.push_back(HEHalfEdges.at(tem_next).origin); tem_id=HEHalfEdges.at(tem_pre).twin; } adjVtx_ids0.push_back(HEHalfEdges.at(tem_pre).origin); vector<int> adjVtx_ids_tem; int index_tem=-1; for(int k=0;k<adjVtx_ids0.size();k++){ if(adjVtx_ids0.at(k)==vtx1_id){ index_tem=k; } } for(int k=index_tem;k<adjVtx_ids0.size();k++){ adjVtx_ids_tem.push_back(adjVtx_ids0.at(k)); } for(int k=0;k<index_tem;k++){ adjVtx_ids_tem.push_back(adjVtx_ids0.at(k)); } adjVtx_ids0=adjVtx_ids_tem; } else{ adjVtx_ids0.push_back(HEHalfEdges.at(twin_id).origin); while(twin_id!=tem_id){ if(tem_id==-1){ tem_id=twin_id; } int next_id=HEHalfEdges.at(tem_id).next; tem_id=HEHalfEdges.at(next_id).twin; adjVtx_ids0.push_back(HEHalfEdges.at(tem_id).origin); } invert(adjVtx_ids0); adjVtx_ids0.pop_back(); } tem_id=-1; if(isOnBoundary(vtx1_id)){ vector<int> vtx_ids; getBoundaryAdjacentVertexes(vtx1_id, vtx_ids); int tem_next=-1; int tem_pre=-1; for(int i=0;i<HEHalfEdges.size();i++){ if(HEHalfEdges.at(i).origin==vtx1_id&&(HEHalfEdges.at(HEHalfEdges.at(i).next).origin==vtx_ids.at(0)||HEHalfEdges.at(HEHalfEdges.at(i).next).origin==vtx_ids.at(1))){ tem_next=HEHalfEdges.at(i).next; tem_pre=HEHalfEdges.at(i).prev; adjVtx_ids1.push_back(HEHalfEdges.at(tem_next).origin); break; } } tem_id=HEHalfEdges.at(tem_pre).twin; while(tem_id!=-1){ tem_next=HEHalfEdges.at(tem_id).next; tem_pre=HEHalfEdges.at(tem_id).prev; adjVtx_ids1.push_back(HEHalfEdges.at(tem_next).origin); tem_id=HEHalfEdges.at(tem_pre).twin; } adjVtx_ids1.push_back(HEHalfEdges.at(tem_pre).origin); vector<int> adjVtx_ids_tem; int index_tem=-1; for(int k=0;k<adjVtx_ids1.size();k++){ if(adjVtx_ids1.at(k)==vtx0_id){ index_tem=k; } } for(int k=index_tem;k<adjVtx_ids1.size();k++){ adjVtx_ids_tem.push_back(adjVtx_ids1.at(k)); } for(int k=0;k<index_tem;k++){ adjVtx_ids_tem.push_back(adjVtx_ids1.at(k)); } adjVtx_ids1=adjVtx_ids_tem; } else{ adjVtx_ids1.push_back(HEHalfEdges.at(he_id).origin); while(he_id!=tem_id){ if(tem_id==-1){ tem_id=he_id; } int next_id=HEHalfEdges.at(tem_id).next; tem_id=HEHalfEdges.at(next_id).twin; adjVtx_ids1.push_back(HEHalfEdges.at(tem_id).origin); } invert(adjVtx_ids1); adjVtx_ids1.pop_back(); } } }
IOBufQueue RFC1867Codec::readToBoundary(bool& foundBoundary) { IOBufQueue result{IOBufQueue::cacheChainLength()}; BoundaryResult boundaryResult = BoundaryResult::NO; while (!input_.empty() && boundaryResult != BoundaryResult::PARTIAL) { const IOBuf* head = input_.front(); uint64_t len = head->length(); const uint8_t *ptr = head->data(); /* iterate through first character matches */ while (len > 0 && (ptr = (const uint8_t*)memchr(ptr, boundary_[0], len))) { /* calculate length after match */ uint64_t readlen = (ptr - head->data()); len = head->length() - readlen; boundaryResult = isBoundary(*head, readlen, boundary_.data(), boundary_.length()); if (boundaryResult == BoundaryResult::YES) { CHECK(readlen < head->length()); bool hasCr = false; if (readlen == 0 && pendingCR_) { pendingCR_.reset(); } if (readlen > 0) { // If the last read char is a CR omit from result Cursor c(head); c.skip(readlen - 1); uint8_t ch = c.read<uint8_t>(); if (ch == '\r') { --readlen; hasCr = true; } } result.append(std::move(pendingCR_)); result.append(input_.split(readlen)); uint32_t trimLen = boundary_.length() + (hasCr ? 1 : 0); input_.trimStart(trimLen); bytesProcessed_ += readlen + trimLen; foundBoundary = true; return result; } else if (boundaryResult == BoundaryResult::PARTIAL) { break; } else if (pendingCR_) { // not a match, append pending CR to result result.append(std::move(pendingCR_)); } /* next character */ ptr++; len--; } uint64_t resultLen = ptr ? ptr - head->data() : head->length(); // Put pendingCR_ in result if there was no partial match in head, or a // partial match starting after the first character if ((boundaryResult == BoundaryResult::NO || resultLen > 0) && pendingCR_) { result.append(std::move(pendingCR_)); } // the boundary does not start through resultLen, append it // to result, except maybe the last char if it's a CR. if (resultLen > 0 && head->data()[resultLen - 1] == '\r') { result.append(input_.split(resultLen - 1)); CHECK(!pendingCR_); pendingCR_ = input_.split(1); } else { result.append(input_.split(resultLen)); } bytesProcessed_ += resultLen; } // reached the end but no boundary found foundBoundary = false; return result; }
bool Lexer::isTripleCharOperator (int c0, int c1, int c2, int c3) { return (c0 == 'a' && c1 == 'n' && c2 == 'd' && isBoundary (c2, c3)) || (c0 == 'x' && c1 == 'o' && c2 == 'r' && isBoundary (c2, c3)) || (c0 == '!' && c1 == '=' && c2 == '='); }
std::unique_ptr<IOBuf> RFC1867Codec::onIngress(std::unique_ptr<IOBuf> data) { static auto dummyBuf = IOBuf::wrapBuffer(kDummyGet.data(), kDummyGet.length()); IOBufQueue result{IOBufQueue::cacheChainLength()}; bool foundBoundary = false; BoundaryResult br = BoundaryResult::NO; input_.append(std::move(data)); while (!input_.empty()) { switch (state_) { case ParserState::START: // first time, must start with boundary without leading \n br = isBoundary(*input_.front(), 0, boundary_.data() + 1, boundary_.length() - 1); if (br == BoundaryResult::NO) { if (callback_) { LOG(ERROR) << "Invalid starting sequence"; callback_->onError(); } state_ = ParserState::ERROR; return nullptr; } else if (br == BoundaryResult::PARTIAL) { return input_.move(); } input_.trimStart(boundary_.length() - 1); bytesProcessed_ += boundary_.length() - 1; state_ = ParserState::HEADERS_START; // fall through case ParserState::HEADERS_START: { if (input_.chainLength() < 3) { return input_.move(); } Cursor c(input_.front()); char firstTwo[2]; c.pull(firstTwo, 2); // We have at least 3 chars available to read uint8_t toTrim = 3; if (memcmp(firstTwo, "--", 2) == 0) { do { auto ch = c.read<char>(); if (ch == '\n') { input_.trimStart(toTrim); state_ = ParserState::DONE; } else if (ch == '\r') { // Every \r we encounter is a char we must trim but we must // make sure we have sufficient data available in input_ to // keep reading (toTrim is always one pos ahead to handle the // expected \n) ++toTrim; if (input_.chainLength() < toTrim) { return input_.move(); } } else { state_ = ParserState::ERROR; } } while (state_ == ParserState::HEADERS_START); break; } } headerParser_.setParserPaused(false); headerParser_.onIngress(*dummyBuf); CHECK(!parseError_); state_ = ParserState::HEADERS; // fall through case ParserState::HEADERS: while (!parseError_ && input_.front() && state_ == ParserState::HEADERS) { size_t bytesParsed = headerParser_.onIngress(*input_.front()); input_.trimStart(bytesParsed); bytesProcessed_ += bytesParsed; } if (parseError_) { if (callback_) { LOG(ERROR) << "Error parsing header data: " << IOBufPrinter::printHexFolly(input_.front()); callback_->onError(); } state_ = ParserState::ERROR; return nullptr; } break; case ParserState::PARAM_DATA: result = readToBoundary(foundBoundary); value_.append(result.move()); if (foundBoundary) { if (callback_) { auto value = value_.move()->moveToFbString(); callback_->onParam(param_, value.toStdString(), bytesProcessed_); } state_ = ParserState::HEADERS_START; } else { return input_.move(); } break; case ParserState::FILE_DATA: result = readToBoundary(foundBoundary); value_.append(result.move()); if (!value_.empty() && callback_) { if (callback_->onFileData(value_.move(), bytesProcessed_) < 0) { LOG(ERROR) << "Callback returned error"; state_ = ParserState::ERROR; return nullptr; } } if (foundBoundary) { if (callback_) { callback_->onFileEnd(true, bytesProcessed_); } state_ = ParserState::HEADERS_START; } else { if (input_.chainLength() > 0) { VLOG(5) << "Trailing input=" << IOBufPrinter::printHexFolly(input_.front()); } return input_.move(); } break; case ParserState::DONE: case ParserState::ERROR: // abort, consume all input return nullptr; } } return nullptr; }
void MeshResampler::resample( HalfedgeMesh& mesh ) { // TODO Compute the mean edge length. double mean2 = 0; for(auto edge = mesh.edgesBegin(); edge != mesh.edgesEnd(); ++edge) { Vector3D v0 = edge->halfedge()->vertex()->position; Vector3D v1 = edge->halfedge()->twin()->vertex()->position; mean2 += (v0 - v1).norm(); } mean2 /= (double)mesh.nEdges(); mean2 *= mean2; // TODO Repeat the four main steps for 5 or 6 iterations const int ITER_TIMES = 5; const int SMOOTH_TIMES = 20; const double WEIGHT_FACTOR = 0.2; const double LONG_EDGE_2 = 1.7777777778; const double SHORT_EDGE_2 = 0.64; std::unordered_set<EdgeIter> edgeSet; edgeSet.reserve(mesh.nEdges()); for(int i = 0; i < ITER_TIMES; ++i) { // TODO Split edges much longer than the target length (being careful about how the loop is written!) EdgeIter old_end = mesh.edgesEnd(); --old_end; for(auto edge = mesh.edgesBegin(); edge != mesh.edgesEnd(); ++edge) { Vector3D v0 = edge->halfedge()->vertex()->position; Vector3D v1 = edge->halfedge()->twin()->vertex()->position; if((v0 - v1).norm2() > LONG_EDGE_2 * mean2) { mesh.splitEdge(edge); } if(edge == old_end) break; } // TODO Collapse edges much shorter than the target length. Here we need to be EXTRA careful about // TODO advancing the loop, because many edges may have been destroyed by a collapse (which ones?) edgeSet.clear(); for(auto edge = mesh.edgesBegin(); edge != mesh.edgesEnd(); ++edge) { edgeSet.insert(edge); } while(edgeSet.size() > 0) { EdgeIter curr = *(edgeSet.begin()); edgeSet.erase(edgeSet.begin()); VertexIter v0 = curr->halfedge()->vertex(); VertexIter v1 = curr->halfedge()->twin()->vertex(); if((v0->position - v1->position).norm2() >= SHORT_EDGE_2 * mean2) continue; HalfedgeIter h = v0->halfedge(); do { if(edgeSet.find(h->edge()) != edgeSet.end()) edgeSet.erase(h->edge()); h = h->twin()->next(); } while(h != v0->halfedge()); h = v1->halfedge(); do { if(edgeSet.find(h->edge()) != edgeSet.end()) edgeSet.erase(h->edge()); h = h->twin()->next(); } while(h != v1->halfedge()); VertexIter v_new = mesh.collapseEdge(curr); if(v_new != mesh.verticesEnd()) { h = v_new->halfedge(); do { edgeSet.insert(h->edge()); h = h->twin()->next(); } while(h != v_new->halfedge()); } } // TODO Now flip each edge if it improves vertex degree for(auto edge = mesh.edgesBegin(); edge != mesh.edgesEnd(); ++edge) { if(willFlipEdgeImprove(edge)) mesh.flipEdge(edge); } // TODO Finally, apply some tangential smoothing to the vertex positions for(int j = 0; j < SMOOTH_TIMES; ++j) { for(auto vertex = mesh.verticesBegin(); vertex != mesh.verticesEnd(); ++vertex) { if(vertex->isBoundary()) continue; vertex->computeCentroid(); } for(auto vertex = mesh.verticesBegin(); vertex != mesh.verticesEnd(); ++vertex) { if(vertex->isBoundary()) continue; Vector3D dir = vertex->centroid - vertex->position; Vector3D nrm = vertex->normal(); dir -= (dot(nrm, dir) * nrm); vertex->position = vertex->position + WEIGHT_FACTOR * dir; } } } }
bool SelectionEditor::modify(EAlteration alter, SelectionDirection direction, TextGranularity granularity, EUserTriggered userTriggered) { if (userTriggered == UserTriggered) { OwnPtrWillBeRawPtr<FrameSelection> trialFrameSelection = FrameSelection::create(); trialFrameSelection->setSelection(m_selection); trialFrameSelection->modify(alter, direction, granularity, NotUserTriggered); if (trialFrameSelection->selection().isRange() && m_selection.isCaret() && !dispatchSelectStart()) return false; } willBeModified(alter, direction); bool wasRange = m_selection.isRange(); VisiblePosition originalStartPosition = m_selection.visibleStart(); VisiblePosition position; switch (direction) { case DirectionRight: if (alter == FrameSelection::AlterationMove) position = modifyMovingRight(granularity); else position = modifyExtendingRight(granularity); break; case DirectionForward: if (alter == FrameSelection::AlterationExtend) position = modifyExtendingForward(granularity); else position = modifyMovingForward(granularity); break; case DirectionLeft: if (alter == FrameSelection::AlterationMove) position = modifyMovingLeft(granularity); else position = modifyExtendingLeft(granularity); break; case DirectionBackward: if (alter == FrameSelection::AlterationExtend) position = modifyExtendingBackward(granularity); else position = modifyMovingBackward(granularity); break; } if (position.isNull()) return false; if (isSpatialNavigationEnabled(frame())) { if (!wasRange && alter == FrameSelection::AlterationMove && position.deepEquivalent() == originalStartPosition.deepEquivalent()) return false; } // Some of the above operations set an xPosForVerticalArrowNavigation. // Setting a selection will clear it, so save it to possibly restore later. // Note: the START position type is arbitrary because it is unused, it would be // the requested position type if there were no xPosForVerticalArrowNavigation set. LayoutUnit x = lineDirectionPointForBlockDirectionNavigation(START); m_selection.setIsDirectional(shouldAlwaysUseDirectionalSelection(frame()) || alter == FrameSelection::AlterationExtend); switch (alter) { case FrameSelection::AlterationMove: m_frameSelection->moveTo(position, userTriggered); break; case FrameSelection::AlterationExtend: if (!m_selection.isCaret() && (granularity == WordGranularity || granularity == ParagraphGranularity || granularity == LineGranularity) && frame() && !frame()->editor().behavior().shouldExtendSelectionByWordOrLineAcrossCaret()) { // Don't let the selection go across the base position directly. Needed to match mac // behavior when, for instance, word-selecting backwards starting with the caret in // the middle of a word and then word-selecting forward, leaving the caret in the // same place where it was, instead of directly selecting to the end of the word. VisibleSelection newSelection = m_selection; newSelection.setExtent(position); if (m_selection.isBaseFirst() != newSelection.isBaseFirst()) position = m_selection.visibleBase(); } // Standard Mac behavior when extending to a boundary is grow the // selection rather than leaving the base in place and moving the // extent. Matches NSTextView. if (!frame() || !frame()->editor().behavior().shouldAlwaysGrowSelectionWhenExtendingToBoundary() || m_selection.isCaret() || !isBoundary(granularity)) { m_frameSelection->setExtent(position, userTriggered); } else { TextDirection textDirection = directionOfEnclosingBlock(); if (direction == DirectionForward || (textDirection == LTR && direction == DirectionRight) || (textDirection == RTL && direction == DirectionLeft)) m_frameSelection->setEnd(position, userTriggered); else m_frameSelection->setStart(position, userTriggered); } break; } if (granularity == LineGranularity || granularity == ParagraphGranularity) m_xPosForVerticalArrowNavigation = x; return true; }
bool SelectionModifier::modify(EAlteration alter, SelectionDirection direction, TextGranularity granularity) { DCHECK(!frame()->document()->needsLayoutTreeUpdate()); DocumentLifecycle::DisallowTransitionScope disallowTransition( frame()->document()->lifecycle()); willBeModified(alter, direction); bool wasRange = m_selection.isRange(); VisiblePosition originalStartPosition = m_selection.visibleStart(); VisiblePosition position; switch (direction) { case DirectionRight: if (alter == FrameSelection::AlterationMove) position = modifyMovingRight(granularity); else position = modifyExtendingRight(granularity); break; case DirectionForward: if (alter == FrameSelection::AlterationExtend) position = modifyExtendingForward(granularity); else position = modifyMovingForward(granularity); break; case DirectionLeft: if (alter == FrameSelection::AlterationMove) position = modifyMovingLeft(granularity); else position = modifyExtendingLeft(granularity); break; case DirectionBackward: if (alter == FrameSelection::AlterationExtend) position = modifyExtendingBackward(granularity); else position = modifyMovingBackward(granularity); break; } if (position.isNull()) return false; if (isSpatialNavigationEnabled(frame())) { if (!wasRange && alter == FrameSelection::AlterationMove && position.deepEquivalent() == originalStartPosition.deepEquivalent()) return false; } // Some of the above operations set an xPosForVerticalArrowNavigation. // Setting a selection will clear it, so save it to possibly restore later. // Note: the START position type is arbitrary because it is unused, it would // be the requested position type if there were no // xPosForVerticalArrowNavigation set. LayoutUnit x = lineDirectionPointForBlockDirectionNavigation(START); m_selection.setIsDirectional(shouldAlwaysUseDirectionalSelection(frame()) || alter == FrameSelection::AlterationExtend); switch (alter) { case FrameSelection::AlterationMove: m_selection = createVisibleSelection( SelectionInDOMTree::Builder() .collapse(position.toPositionWithAffinity()) .setIsDirectional(m_selection.isDirectional()) .build()); break; case FrameSelection::AlterationExtend: if (!m_selection.isCaret() && (granularity == WordGranularity || granularity == ParagraphGranularity || granularity == LineGranularity) && frame() && !frame() ->editor() .behavior() .shouldExtendSelectionByWordOrLineAcrossCaret()) { // Don't let the selection go across the base position directly. Needed // to match mac behavior when, for instance, word-selecting backwards // starting with the caret in the middle of a word and then // word-selecting forward, leaving the caret in the same place where it // was, instead of directly selecting to the end of the word. VisibleSelection newSelection = m_selection; newSelection.setExtent(position); if (m_selection.isBaseFirst() != newSelection.isBaseFirst()) position = m_selection.visibleBase(); } // Standard Mac behavior when extending to a boundary is grow the // selection rather than leaving the base in place and moving the // extent. Matches NSTextView. if (!frame() || !frame() ->editor() .behavior() .shouldAlwaysGrowSelectionWhenExtendingToBoundary() || m_selection.isCaret() || !isBoundary(granularity)) { m_selection.setExtent(position); } else { TextDirection textDirection = directionOfEnclosingBlock(); if (direction == DirectionForward || (textDirection == LTR && direction == DirectionRight) || (textDirection == RTL && direction == DirectionLeft)) setSelectionEnd(&m_selection, position); else setSelectionStart(&m_selection, position); } break; } if (granularity == LineGranularity || granularity == ParagraphGranularity) m_xPosForVerticalArrowNavigation = x; return true; }
//! Checks if current index is a boundary. bool MIcuBreakIterator::isBoundary() { Q_D(MIcuBreakIterator); return isBoundary(d->current); }