Esempio n. 1
0
bool FrameCaret::caretPositionIsValidForDocument(
    const Document& document) const {
  if (!isActive())
    return true;

  return caretPosition().document() == document && !caretPosition().isOrphan();
}
Esempio n. 2
0
void FrameCaret::paintCaret(GraphicsContext& context,
                            const LayoutPoint& paintOffset) {
  if (m_caretVisibility == CaretVisibility::Hidden)
    return;

  if (!(isActive() && m_shouldPaintCaret))
    return;

  updateCaretRect(caretPosition());
  CaretBase::paintCaret(caretPosition().anchorNode(), context, paintOffset,
                        DisplayItem::kCaret);
}
Esempio n. 3
0
bool FrameCaret::shouldBlinkCaret() const {
  if (m_caretVisibility != CaretVisibility::Visible || !isActive())
    return false;

  Element* root = rootEditableElementOf(caretPosition().position());
  if (!root)
    return false;

  Element* focusedElement = root->document().focusedElement();
  if (!focusedElement)
    return false;

  return focusedElement->isShadowIncludingInclusiveAncestorOf(
      caretPosition().anchorNode());
}
Esempio n. 4
0
void FrameCaret::updateAppearance() {
  // Paint a block cursor instead of a caret in overtype mode unless the caret
  // is at the end of a line (in this case the FrameSelection will paint a
  // blinking caret as usual).
  bool paintBlockCursor = m_shouldShowBlockCursor && isActive();
  if (paintBlockCursor) {
    // TODO(editing-dev): Use of updateStyleAndLayoutIgnorePendingStylesheets
    // needs to be audited.  see http://crbug.com/590369 for more details.
    // In the long term, we should defer the update of the caret's appearance
    // to prevent synchronous layout.
    m_frame->document()->updateStyleAndLayoutIgnorePendingStylesheets();

    if (isLogicalEndOfLine(createVisiblePosition(caretPosition())))
      paintBlockCursor = false;
  }

  bool shouldBlink = !paintBlockCursor && shouldBlinkCaret();

  // If the caret moved, stop the blink timer so we can restart with a
  // black caret in the new location.
  if (!shouldBlink || shouldStopBlinkingDueToTypingCommand(m_frame))
    stopCaretBlinkTimer();

  // Start blinking with a black caret. Be sure not to restart if we're
  // already blinking in the right location.
  if (shouldBlink)
    startBlinkCaret();
}
Esempio n. 5
0
static void restartTerm(Accessible *newTerm, AccessibleText *newTextTerm) {
  char *c,*d;
  const char *e;
  long i,len;
  char *text;

  if (curFocus)
    finiTerm();
  Accessible_ref(curFocus = newTerm);
  curTerm = newTextTerm;
  logMessage(LOG_DEBUG,"new term %p",curTerm);
  text = AccessibleText_getText(curTerm,0,LONG_MAX);
  curNumRows = 0;
  if (curRows) {
    for (i=0;i<curNumRows;i++)
      free(curRows[i]);
    free(curRows);
  }
  free(curRowLengths);
  c = text;
  while (*c) {
    curNumRows++;
    if (!(c = strchr(c,'\n')))
      break;
    c++;
  }
  logMessage(LOG_DEBUG,"%ld rows",curNumRows);
  curRows = malloc(curNumRows * sizeof(*curRows));
  curRowLengths = malloc(curNumRows * sizeof(*curRowLengths));
  i = 0;
  curNumCols = 0;
  for (c = text; *c; c = d+1) {
    d = strchr(c,'\n');
    if (d)
      *d = 0;
    e = c;
    curRowLengths[i] = (len = my_mbsrtowcs(NULL,&e,0,NULL)) + (d != NULL);
    if (len > curNumCols)
      curNumCols = len;
    else if (len < 0) {
      if (len==-2)
	logMessage(LOG_ERR,"unterminated sequence %s",c);
      else if (len==-1)
	logSystemError("mbrlen");
      curRowLengths[i] = (len = -1) + (d != NULL);
    }
    curRows[i] = malloc((len + (d!=NULL)) * sizeof(*curRows[i]));
    e = c;
    my_mbsrtowcs(curRows[i],&e,len,NULL);
    if (d)
      curRows[i][len]='\n';
    else
      break;
    i++;
  }
  logMessage(LOG_DEBUG,"%ld cols",curNumCols);
  SPI_freeString(text);
  caretPosition(AccessibleText_getCaretOffset(curTerm));
}
int TextRendererStringOffsetProvider::offset(Qt::Key /*key*/)
{
	if (!vis_ || !vis_->itemOrChildHasFocus()) return -1;

	auto tc = dynamic_cast<Visualization::TextCursor*> (vis_->scene()->mainCursor());

	return tc ? tc->caretPosition() : -1;
}
Esempio n. 7
0
void FrameCaret::invalidateCaretRect(bool forceInvalidation) {
  if (!m_caretRectDirty)
    return;
  m_caretRectDirty = false;

  DCHECK(caretPositionIsValidForDocument(*m_frame->document()));
  LayoutObject* layoutObject = nullptr;
  LayoutRect newRect;
  PositionWithAffinity currentCaretPosition = caretPosition();
  if (isActive())
    newRect = localCaretRectOfPosition(currentCaretPosition, layoutObject);
  Node* newNode = layoutObject ? layoutObject->node() : nullptr;
  // The current selected node |newNode| could be a child multiple levels below
  // its associated "anchor node" ancestor, so we reference and keep around the
  // anchor node for checking editability.
  // TODO(wkorman): Consider storing previous Position, rather than Node, and
  // making use of EditingUtilies::isEditablePosition() directly.
  Node* newAnchorNode =
      currentCaretPosition.position().parentAnchoredEquivalent().anchorNode();
  if (newNode && newAnchorNode && newNode != newAnchorNode &&
      newAnchorNode->layoutObject() && newAnchorNode->layoutObject()->isBox()) {
    newNode->layoutObject()->mapToVisualRectInAncestorSpace(
        toLayoutBoxModelObject(newAnchorNode->layoutObject()), newRect);
  }
  // It's possible for the timer to be inactive even though we want to
  // invalidate the caret. For example, when running as a layout test the
  // caret blink interval could be zero and thus |m_caretBlinkTimer| will
  // never be started. We provide |forceInvalidation| for use by paint
  // invalidation internals where we need to invalidate the caret regardless
  // of timer state.
  if (!forceInvalidation && !m_caretBlinkTimer.isActive() &&
      newNode == m_previousCaretNode && newRect == m_previousCaretRect &&
      m_caretVisibility == m_previousCaretVisibility)
    return;

  if (m_previousCaretAnchorNode &&
      shouldRepaintCaret(*m_previousCaretAnchorNode)) {
    invalidateLocalCaretRect(m_previousCaretAnchorNode.get(),
                             m_previousCaretRect);
  }
  if (newAnchorNode && shouldRepaintCaret(*newAnchorNode))
    invalidateLocalCaretRect(newAnchorNode, newRect);
  m_previousCaretNode = newNode;
  m_previousCaretAnchorNode = newAnchorNode;
  m_previousCaretRect = newRect;
  m_previousCaretVisibility = m_caretVisibility;
}
Esempio n. 8
0
IntRect FrameCaret::absoluteCaretBounds() {
  DCHECK_NE(m_frame->document()->lifecycle().state(),
            DocumentLifecycle::InPaintInvalidation);
  DCHECK(!m_frame->document()->needsLayoutTreeUpdate());
  DocumentLifecycle::DisallowTransitionScope disallowTransition(
      m_frame->document()->lifecycle());

  if (!isActive()) {
    clearCaretRect();
  } else {
    if (enclosingTextFormControl(caretPosition().position())) {
      if (isVisuallyEquivalentCandidate(caretPosition().position()))
        updateCaretRect(caretPosition());
      else
        updateCaretRect(createVisiblePosition(caretPosition()));
    } else {
      updateCaretRect(createVisiblePosition(caretPosition()));
    }
  }
  return absoluteBoundsForLocalRect(caretPosition().anchorNode(),
                                    localCaretRectWithoutUpdate());
}
Esempio n. 9
0
static void evListenerCB(const AccessibleEvent *event, void *user_data) {
  static int running = 0;
  struct evList *ev = malloc(sizeof(*ev));
  AccessibleEvent_ref(event);
  AccessibleText *newText;
  ev->next = evs;
  ev->ev = event;
  evs = ev;
  int state_changed_focused;

  /* this is not atomic but we can only be recursively called within calls
   * to the lib */
  if (running)
    return;
  else
    running = 1;

  while (evs) {
    pthread_mutex_lock(&updateMutex);
    /* pickup a list of events to handle */
    ev = evs;
    evs = NULL;
    for (; ev; AccessibleEvent_unref(ev->ev), ev = ev->next) {
      event = ev->ev;
      state_changed_focused = !strcmp(event->type,"object:state-changed:focused");
      if (state_changed_focused && !event->detail1) {
	if (event->source == curFocus)
	  finiTerm();
      } else if (!strcmp(event->type,"focus:") || (state_changed_focused && event->detail1)) {
	if (!(newText = Accessible_getText(event->source))) {
	  if (curFocus) finiTerm();
	} else {
          AccessibleRole role = Accessible_getRole(event->source);
	  if (typeAll ||
	      (typeText && ((role == SPI_ROLE_TEXT) || (role == SPI_ROLE_PASSWORD_TEXT) || (role == SPI_ROLE_PARAGRAPH))) ||
	      (typeTerminal && (role == SPI_ROLE_TERMINAL))) {
	    restartTerm(event->source, newText);
	  } else {
	    logMessage(LOG_DEBUG,"AT SPI widget not for us");
	    if (curFocus) finiTerm();
	  }
	}
      } else if (!strcmp(event->type,"object:text-caret-moved")) {
	if (event->source != curFocus) continue;
	logMessage(LOG_DEBUG,"caret move to %lu",event->detail1);
	caretPosition(event->detail1);
      } else if (!strcmp(event->type,"object:text-changed:delete")) {
	long x,y,toDelete = event->detail2;
	long length = 0, toCopy;
	long downTo; /* line that will provide what will follow x */
	logMessage(LOG_DEBUG,"delete %lu from %lu",event->detail2,event->detail1);
	if (event->source != curFocus) continue;
	findPosition(event->detail1,&x,&y);
	downTo = y;
	if (downTo < curNumRows)
		length = curRowLengths[downTo];
	while (x+toDelete >= length) {
	  downTo++;
	  if (downTo <= curNumRows - 1)
	    length += curRowLengths[downTo];
	  else {
	    /* imaginary extra line doesn't provide more length, and shouldn't need to ! */
	    if (x+toDelete > length) {
	      logMessage(LOG_ERR,"deleting past end of text !");
	      /* discarding */
	      toDelete = length - x;
	    }
	    break; /* deleting up to end */
	  }
	}
	if (length-toDelete>0) {
	  /* still something on line y */
	  if (y!=downTo) {
	    curRowLengths[y] = length-toDelete;
	    curRows[y]=realloc(curRows[y],curRowLengths[y]*sizeof(*curRows[y]));
	  }
	  if ((toCopy = length-toDelete-x))
	    memmove(curRows[y]+x,curRows[downTo]+curRowLengths[downTo]-toCopy,toCopy*sizeof(*curRows[downTo]));
	  if (y==downTo) {
	    curRowLengths[y] = length-toDelete;
	    curRows[y]=realloc(curRows[y],curRowLengths[y]*sizeof(*curRows[y]));
	  }
	} else {
	  /* kills this line as well ! */
	  y--;
	}
	if (downTo>=curNumRows)
	  /* imaginary extra lines don't need to be deleted */
	  downTo=curNumRows-1;
	delRows(y+1,downTo-y);
	caretPosition(AccessibleText_getCaretOffset(curTerm));
      } else if (!strcmp(event->type,"object:text-changed:insert")) {
	long len=event->detail2,semilen,x,y;
	char *added;
	const char *adding,*c;
	logMessage(LOG_DEBUG,"insert %lu from %lu",event->detail2,event->detail1);
	if (event->source != curFocus) continue;
	findPosition(event->detail1,&x,&y);
	adding = c = added = AccessibleTextChangedEvent_getChangeString(event);
	if (x && (c = strchr(adding,'\n'))) {
	  /* splitting line */
	  addRows(y,1);
	  semilen=my_mbslen(adding,c+1-adding);
	  curRowLengths[y]=x+semilen;
	  if (x+semilen-1>curNumCols)
	    curNumCols=x+semilen-1;

	  /* copy beginning */
	  curRows[y]=malloc(curRowLengths[y]*sizeof(*curRows[y]));
	  memcpy(curRows[y],curRows[y+1],x*sizeof(*curRows[y]));
	  /* add */
	  my_mbsrtowcs(curRows[y]+x,&adding,semilen,NULL);
	  len-=semilen;
	  adding=c+1;
	  /* shift end */
	  curRowLengths[y+1]-=x;
	  memmove(curRows[y+1],curRows[y+1]+x,curRowLengths[y+1]*sizeof(*curRows[y+1]));
	  x=0;
	  y++;
	}
	while ((c = strchr(adding,'\n'))) {
	  /* adding lines */
	  addRows(y,1);
	  semilen=my_mbslen(adding,c+1-adding);
	  curRowLengths[y]=semilen;
	  if (semilen-1>curNumCols)
	    curNumCols=semilen-1;
	  curRows[y]=malloc(semilen*sizeof(*curRows[y]));
	  my_mbsrtowcs(curRows[y],&adding,semilen,NULL);
	  len-=semilen;
	  adding=c+1;
	  y++;
	}
	if (len) {
	  /* still length to add on the line following it */
	  if (y==curNumRows) {
	    /* It won't insert ending \n yet */
	    addRows(y,1);
	    curRows[y]=NULL;
	    curRowLengths[y]=0;
	  }
	  curRowLengths[y] += len;
	  curRows[y]=realloc(curRows[y],curRowLengths[y]*sizeof(*curRows[y]));
	  memmove(curRows[y]+x+len,curRows[y]+x,(curRowLengths[y]-(x+len))*sizeof(*curRows[y]));
	  my_mbsrtowcs(curRows[y]+x,&adding,len,NULL);
	  if (curRowLengths[y]-(curRows[y][curRowLengths[y]-1]=='\n')>curNumCols)
	    curNumCols=curRowLengths[y]-(curRows[y][curRowLengths[y]-1]=='\n');
	}
	SPI_freeString(added);
	caretPosition(AccessibleText_getCaretOffset(curTerm));
      } else
	logMessage(LOG_INFO,"event %s, source %p, detail1 %lu detail2 %lu",event->type,event->source,event->detail1,event->detail2);
    }
    pthread_mutex_unlock(&updateMutex);
  }
  running = 0;
}